Introduction
Containerizing Spring Boot applications improves deployment consistency, scalability, and security. While traditional Dockerfile-based approaches work, newer methods eliminate manual configuration, reduce errors, and leverage optimized build processes.
This guide explores four Dockerfile-free approaches to containerize Spring Boot apps, comparing their benefits, configurations, and best practices.
1. Why Dockerize Without a Dockerfile?
1.1 Simplification & Automation
- No need to manually write
Dockerfile
instructions. - Automatic dependency resolution and layer optimization.
- Built-in best practices for security and performance.
1.2 Security & Maintenance
- Base images are automatically updated (e.g., JVM patches).
- Reduced risk of misconfigurations in
Dockerfile
. - Smaller attack surface due to optimized layering.
1.3 Portability & CI/CD Integration
- Works seamlessly across different environments (local, cloud, Kubernetes).
- Faster builds with caching and incremental updates.
- Native integration with Maven/Gradle and cloud platforms.
2. Approach 1: Using Spring Boot’s Built-in Build Plugin
2.1 How It Works
Spring Boot 2.3+ integrates with Cloud Native Buildpacks to generate OCI-compliant images without a Dockerfile
.
2.2 Maven Configuration
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<image>
<name>myapp:${project.version}</name>
<builder>paketobuildpacks/builder:base</builder>
<env>
<BP_JVM_VERSION>17</BP_JVM_VERSION>
</env>
</image>
</configuration>
</plugin>
</plugins>
</build>
2.3 Gradle Configuration
plugins {
id 'org.springframework.boot' version '3.1.0'
}
bootBuildImage {
imageName = "myapp:${project.version}"
builder = "paketobuildpacks/builder:base"
environment = [
"BP_JVM_VERSION": "17",
"BPE_APPEND_JAVA_TOOL_OPTIONS": "-Dspring.profiles.active=prod"
]
}
2.4 Build Command
# Maven
./mvnw spring-boot:build-image
# Gradle
./gradlew bootBuildImage
2.5 Advantages
✅ Zero configuration for most apps.
✅ Automatic security updates via Paketo Buildpacks.
✅ Supports ARM64 & AMD64 out of the box.
3. Approach 2: Using Google’s Jib Plugin
3.1 How Jib Works
- Builds optimized Docker images without Docker daemon.
- Creates distroless images (smaller & more secure).
3.2 Maven Setup
<plugin>
<groupId>com.google.cloud.tools</groupId>
<artifactId>jib-maven-plugin</artifactId>
<version>3.3.1</version>
<configuration>
<from>
<image>eclipse-temurin:17-jre-jammy</image>
</from>
<to>
<image>myapp:${project.version}</image>
</to>
<container>
<ports>
<port>8080</port>
</ports>
<jvmFlags>
<jvmFlag>-Dspring.profiles.active=prod</jvmFlag>
</jvmFlags>
</container>
</configuration>
</plugin>
3.3 Gradle Setup
plugins {
id 'com.google.cloud.tools.jib' version '3.3.1'
}
jib {
from {
image = 'eclipse-temurin:17-jre-jammy'
}
to {
image = "myapp:${project.version}"
}
container {
ports = ['8080']
jvmFlags = ['-Dspring.profiles.active=prod']
}
}
3.4 Build Commands
# Build & push to registry
./mvnw jib:build
# Build to local Docker daemon
./mvnw jib:dockerBuild
3.5 Advantages
✅ No Docker daemon needed (faster CI/CD).
✅ Smallest possible image size (~100MB).
✅ Layer caching for faster builds.
4. Approach 3: Cloud Native Buildpacks (Pack CLI)
4.1 What Are Buildpacks?
- Automatically detect frameworks (Java, Node.js, etc.).
- Apply optimizations (memory, security, JVM tuning).
4.2 Using pack
CLI
1. Install:
brew install buildpacks/tap/pack
2. Build:
pack build myapp --builder paketobuildpacks/builder:base \
--env BP_JVM_VERSION=17 \
--env BPE_DELIM_JAVA_TOOL_OPTIONS=" " \
--env BPE_APPEND_JAVA_TOOL_OPTIONS="-Dspring.profiles.active=prod"
4.3 Advantages
✅ Works with any language (not just Java).
✅ Enterprise-ready (used in Heroku, Cloud Foundry).
✅ Automatic security patches.
5. Approach 4: Docker Compose with Auto-Generated Image
5.1 Using Spring Boot + Docker Compose
1. Generate image first:
./gradlew bootBuildImage
2. Define docker-compose.yml
:
version: '3.8'
services:
app:
image: myapp:latest
ports:
- "8080:8080"
environment:
- SPRING_PROFILES_ACTIVE=prod
5.2 Advantages
✅ Easy local development.
✅ Multi-container setups (DB, Redis, etc.).
6. Comparison: Which Method Should You Use?
Method | Best For | Image Size | Build Speed | Customization |
---|---|---|---|---|
Spring Boot Plugin | Simple deployments | Medium (~200MB) | Fast | Low |
Jib | CI/CD, security-sensitive | Small (~100MB) | Very Fast | Medium |
Buildpacks (Pack CLI) | Polyglot apps, cloud-native | Medium (~200MB) | Moderate | Medium |
Docker Compose | Local development | Depends | Fast | Low |
7. Best Practices for Production
7.1 Image Tagging
Always use versioned tags:
./mvnw spring-boot:build-image -Dspring-boot.build-image.imageName=myapp:1.0.0
7.2 Minimize Image Size
- Use Jib’s distroless base images.
- With Buildpacks, use
builder:base
instead ofbuilder:full
.
7.3 Security Scanning
docker scan myapp:latest
7.4 Environment-Specific Configs
bootBuildImage {
environment = [
"BP_JVM_VERSION": "17",
"BPE_APPEND_JAVA_TOOL_OPTIONS": "-Dspring.profiles.active=${System.env.SPRING_PROFILE}"
]
}
8. Troubleshooting Common Issues
8.1 Build Failures
- Solution: Clean Docker cache:
docker system prune
8.2 Port Conflicts
- Solution: Check
application.properties
:
server.port=8080
8.3 Authentication Errors (Private Registry)
- Solution: Configure Jib credentials:
./mvnw jib:build -Djib.to.auth.username=$USER -Djib.to.auth.password=$TOKEN
Conclusion
Dockerizing Spring Boot without a Dockerfile
is faster, more secure, and easier to maintain.
- For simplicity: Use Spring Boot Plugin.
- For smallest images: Use Jib.
- For cloud-native apps: Use Buildpacks (Pack CLI).
- For local dev: Use Docker Compose.
By adopting these methods, you streamline deployments while keeping images lightweight, secure, and production-ready.