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.