Introduction
Paketo Buildpacks provide a modern, cloud-native way to build container images from your Java applications without writing Dockerfiles. Based on the Cloud Native Buildpacks specification, Paketo offers intelligent, secure, and production-ready container images.
Core Concepts
What are Buildpacks?
- Buildpacks inspect your source code and create a plan to build and run your application
- Stacks provide the build and run environments
- Builders combine buildpacks with a stack and lifecycle
- Images are the final OCI-compliant containers
Getting Started
1. Installation and Setup
# Install pack CLI (required for buildpacks) # On macOS brew install buildpacks/tap/pack # On Linux curl -sSL "https://github.com/buildpacks/pack/releases/download/v0.32.1/pack-v0.32.1-linux.tgz" | sudo tar -C /usr/local/bin/ --no-same-owner -xzv pack # Verify installation pack --version
2. Basic Java Application Build
// Simple Spring Boot application @SpringBootApplication @RestController public class DemoApplication { public static void main(String[] args) { SpringApplication.run(DemoApplication.class, args); } @GetMapping("/") public String hello() { return "Hello from Paketo Buildpacks!"; } } <!-- Maven pom.xml --> <project> <modelVersion>4.0.0</modelVersion> <groupId>com.example</groupId> <artifactId>paketo-demo</artifactId> <version>1.0.0</version> <parent> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-parent</artifactId> <version>3.2.0</version> </parent> <properties> <java.version>17</java.version> </properties> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> </dependencies> <build> <plugins> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> </plugin> </plugins> </build> </project>
Building with Paketo
3. Basic Build Commands
# Build from source pack build my-java-app --builder paketobuildpacks/builder:base # Build with specific Java version pack build my-java-app --builder paketobuildpacks/builder:base \ --env BP_JVM_VERSION=17 # Build from pre-built JAR pack build my-java-app --builder paketobuildpacks/builder:base \ --path target/my-app-1.0.0.jar
4. Advanced Build Configuration
# Custom JVM settings pack build my-java-app --builder paketobuildpacks/builder:base \ --env BPL_JVM_HEAD_ROOM=32 \ --env BPL_JVM_LOADED_CLASS_COUNT=35 \ --env BPL_JVM_THREAD_COUNT=50 # Application-specific configuration pack build my-java-app --builder paketobuildpacks/builder:base \ --env SPRING_PROFILES_ACTIVE=production \ --env JAVA_OPTS="-Dserver.port=8080 -Dlogging.level.com.example=DEBUG" # Resource constraints pack build my-java-app --builder paketobuildpacks/builder:base \ --env BP_JVM_CFLAGS="-J-Xmx2g -J-Xms1g" \ --env BPL_DEBUG_ENABLED=true \ --env BPL_DEBUG_PORT=8000
Paketo Buildpack Types
5. Different Builder Types
# Base builder (recommended for most applications) pack build my-app --builder paketobuildpacks/builder:base # Full builder (includes additional packages) pack build my-app --builder paketobuildpacks/builder:full # Tiny builder (minimal footprint) pack build my-app --builder paketobuildpacks/builder:tiny
6. Buildpack Suite Components
Paketo Buildpacks include:
- Java Buildpack: Detects and builds Java applications
- BellSoft Liberica Buildpack: Provides JRE/JDK
- Executable JAR Buildpack: Runs executable JARs
- Spring Boot Buildpack: Optimizes Spring Boot applications
- Apache Tomcat Buildpack: Deploys WAR files
- DistZip Buildpack: Handles dist-zip formatted applications
Advanced Configuration
7. Custom Buildpack Configuration
# project.toml (build-time configuration)
[project]
id = "com.example.myapp" version = "1.0.0" [[build.env]] name = "BP_JVM_VERSION" value = "17" [[build.env]] name = "BP_MAVEN_BUILD_ARGUMENTS" value = "-DskipTests -Pproduction package" [[build.env]] name = "BPE_APPEND_JAVA_OPTS" value = "-Dspring.profiles.active=cloud -Dmanagement.endpoints.web.exposure.include=health,metrics,info" # Buildpack-specific settings [[build.buildpacks]] id = "paketo-buildpacks/bellsoft-liberica" version = "9.9.0" [[build.buildpacks]] id = "paketo-buildpacks/maven" version = "6.5.0"
# Build with project descriptor pack build my-app --builder paketobuildpacks/builder:base --descriptor project.toml
8. Multi-Module Maven Project Setup
<!-- parent pom.xml --> <project> <modelVersion>4.0.0</modelVersion> <groupId>com.example</groupId> <artifactId>multi-module-app</artifactId> <version>1.0.0</version> <packaging>pom</packaging> <modules> <module>api</module> <module>service</module> <module>web</module> </modules> <properties> <java.version>17</java.version> <maven.compiler.source>17</maven.compiler.source> <maven.compiler.target>17</maven.compiler.target> </properties> </project>
# Build multi-module project pack build multi-module-app --builder paketobuildpacks/builder:base \ --env BP_MAVEN_BUILT_MODULE=web \ --env BP_MAVEN_BUILD_ARGUMENTS="clean package -DskipTests"
Integration with Build Systems
9. Maven Integration
<!-- Maven plugin for buildpacks --> <plugin> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-maven-plugin</artifactId> <configuration> <image> <name>my-registry.com/my-org/my-app:${project.version}</name> </image> </configuration> </plugin> # Build using Spring Boot Maven plugin mvn spring-boot:build-image # With custom configuration mvn spring-boot:build-image \ -Dspring-boot.build-image.imageName=my-registry.com/my-app:latest \ -Dspring-boot.build-image.builder=paketobuildpacks/builder:base
10. Gradle Integration
// build.gradle.kts plugins { java id("org.springframework.boot") version "3.2.0" id("io.spring.dependency-management") version "1.1.4" } springBoot { buildImage { imageName = "my-registry.com/my-app:${project.version}" builder = "paketobuildpacks/builder:base" environment = mapOf( "BP_JVM_VERSION" to "17", "BPE_DELIM_JAVA_OPTS" to " ", "BPE_APPEND_JAVA_OPTS" to "-Dspring.profiles.active=prod" ) } } # Build using Gradle ./gradlew bootBuildImage # With custom settings ./gradlew bootBuildImage --imageName=my-registry.com/my-app:latest
Production Optimizations
11. Security and Best Practices
# Build with security scanning pack build my-app --builder paketobuildpacks/builder:base \ --env BP_EMBED_CERTS=true # Use minimal base image pack build my-app --builder paketobuildpacks/builder:tiny # Enable SBOM generation pack build my-app --builder paketobuildpacks/builder:base \ --env BP_DISABLE_SBOM=false # Scan for vulnerabilities pack sbom download my-app --output-dir ./sbom docker scan my-app
12. Runtime Configuration
// Application properties for cloud-native deployment @Configuration public class CloudConfig { @Bean @Profile("cloud") public WebServerFactoryCustomizer<ConfigurableServletWebServerFactory> webServerFactoryCustomizer() { return factory -> factory.setPort(getRuntimePort()); } private int getRuntimePort() { String port = System.getenv("PORT"); return port != null ? Integer.parseInt(port) : 8080; } } # Runtime environment variables docker run -d \ --name my-app \ -p 8080:8080 \ -e SPRING_PROFILES_ACTIVE=production \ -e JAVA_OPTS="-Xmx512m -Xms256m" \ -e BPL_DEBUG_ENABLED=true \ -e BPL_DEBUG_PORT=8000 \ -e BPL_JVM_HEAD_ROOM=32 \ my-java-app:latest
CI/CD Integration
13. GitHub Actions Workflow
# .github/workflows/buildpack.yml name: Build with Paketo Buildpacks on: push: branches: [ main ] pull_request: branches: [ main ] env: REGISTRY: ghcr.io IMAGE_NAME: ${{ github.repository }} jobs: build: runs-on: ubuntu-latest permissions: contents: read packages: write steps: - name: Checkout code uses: actions/checkout@v4 - name: Set up Java uses: actions/setup-java@v4 with: java-version: '17' distribution: 'temurin' cache: 'maven' - name: Build with Maven run: mvn -B package -DskipTests - name: Install Pack CLI run: | curl -sSL "https://github.com/buildpacks/pack/releases/download/v0.32.1/pack-v0.32.1-linux.tgz" | sudo tar -C /usr/local/bin/ --no-same-owner -xzv pack - name: Log in to Container Registry uses: docker/login-action@v3 with: registry: ${{ env.REGISTRY }} username: ${{ github.actor }} password: ${{ secrets.GITHUB_TOKEN }} - name: Build container image run: | pack build ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest \ --builder paketobuildpacks/builder:base \ --env BP_JVM_VERSION=17 \ --env SPRING_PROFILES_ACTIVE=ci \ --publish - name: Run security scan run: | docker scan ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}:latest 14. GitLab CI Configuration
# .gitlab-ci.yml image: docker:latest services: - docker:dind variables: DOCKER_HOST: tcp://docker:2375 DOCKER_TLS_CERTDIR: "" stages: - build - test - package build-image: stage: package before_script: - apk add --no-cache curl openjdk17 maven - curl -sSL "https://github.com/buildpacks/pack/releases/download/v0.32.1/pack-v0.32.1-linux.tgz" | tar -C /usr/local/bin/ -xzv pack - docker login -u $CI_REGISTRY_USER -p $CI_REGISTRY_PASSWORD $CI_REGISTRY script: - mvn -B package -DskipTests - pack build $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA \ --builder paketobuildpacks/builder:base \ --env BP_JVM_VERSION=17 \ --env BP_MAVEN_BUILD_ARGUMENTS="-DskipTests package" \ --publish - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA
Custom Buildpacks
15. Creating Custom Buildpacks
# Create a custom buildpack pack buildpack new examples/my-custom-buildpack \ --api 0.8 \ --path ./custom-buildpack \ --version 0.0.1 \ --stacks io.buildpacks.stacks.bionic
# buildpack.toml api = "0.8"
[buildpack]
id = "examples/java-custom" version = "0.0.1" name = "Custom Java Buildpack" homepage = "https://example.com" [[buildpack.licenses]] type = "MIT" [[stacks]] id = "io.buildpacks.stacks.bionic" [[stacks]] id = "*"
16. Custom Builder Creation
# builder.toml description = "Custom Java Builder"
[stack]
id = "io.buildpacks.stacks.bionic" build-image = "paketobuildpacks/build:base-cnb" run-image = "paketobuildpacks/run:base-cnb" [[buildpacks]] id = "paketo-buildpacks/java" version = "6.0.0" uri = "docker://gcr.io/paketo-buildpacks/java:6.0.0" [[buildpacks]] id = "examples/my-custom-buildpack" version = "0.0.1" uri = "file://./custom-buildpack" [[order]] [[order.group]] id = "paketo-buildpacks/java" version = "6.0.0" [[order.group]] id = "examples/my-custom-buildpack" version = "0.0.1"
# Create custom builder pack builder create my-org/custom-java-builder:latest --config builder.toml # Build with custom builder pack build my-app --builder my-org/custom-java-builder:latest
Monitoring and Debugging
17. Build Inspection and Analysis
# Inspect built image pack inspect-image my-app # Check what buildpacks were used pack inspect-image my-app --bom # Download build logs pack build my-app --builder paketobuildpacks/builder:base --verbose # Analyze image layers docker history my-app # Check image metadata docker inspect my-app
18. Runtime Debugging
# Enable debug mode pack build my-app --builder paketobuildpacks/builder:base \ --env BPL_DEBUG_ENABLED=true \ --env BPL_DEBUG_PORT=8000 # Connect to debug port docker run -p 8080:8080 -p 8000:8000 my-app jdb -attach localhost:8000 # Check runtime environment docker exec -it my-app bash cat /layers/paketo-buildpacks_bellsoft-liberica/jre/contents/Info
Best Practices
19. Performance Optimizations
# Use build cache for faster builds pack build my-app --builder paketobuildpacks/builder:base \ --volume $(pwd)/pack-cache:/tmp/cache \ --env BP_MAVEN_DAEMON_ENABLED=true # Optimize for production pack build my-app --builder paketobuildpacks/builder:base \ --env BP_JVM_TYPE=JRE \ --env BP_JVM_JLINK_ENABLED=true \ --env BP_JVM_JLINK_ARGS="--strip-debug --no-man-pages --no-header-files" # Use tiny builder for minimal footprint pack build my-app --builder paketobuildpacks/builder:tiny \ --env BP_NATIVE_IMAGE=true \ --env BP_MAVEN_BUILD_ARGUMENTS="-Pnative native:compile -DskipTests"
20. Security Hardening
# Build with non-root user pack build my-app --builder paketobuildpacks/builder:base \ --env BP_OCI_USER_ID=1000 \ --env BP_OCI_USER_GROUP_ID=1000 # Disable unnecessary features pack build my-app --builder paketobuildpacks/builder:base \ --env BP_JVM_JLINK_ENABLED=true \ --env BP_JVM_JLINK_ARGS="--strip-debug --no-man-pages --no-header-files --compress=2" # Regular updates pack build my-app --builder paketobuildpacks/builder:base \ --pull-policy always
Conclusion
Paketo Buildpacks provide a robust, secure, and efficient way to containerize Java applications. Key benefits include:
- No Dockerfile required - Intelligent detection and building
- Production-ready images - Security-focused and optimized
- Consistent builds - Reproducible across environments
- Automatic updates - Base images and dependencies stay current
- Extensible - Custom buildpacks for specific needs
By integrating Paketo Buildpacks into your Java development workflow, you can streamline containerization while maintaining high standards for security and performance.