Packaging & Deployment
The executable jar
One file with your classes, the dependencies and a launcher. No application server.
Container image, no Dockerfile
Cloud Native Buildpacks pick a JDK, layer the image and set sane defaults.
Container image with a Dockerfile
Layered jars keep dependencies in their own layer, so a code change rebuilds only the last one:
Native images
| JVM | Native | |
|---|---|---|
| startup | ~1 s | ~50 ms |
| memory | higher | much lower |
| build time | seconds | minutes |
| runtime reflection | free | needs hints |
Worth it for functions and scale-to-zero workloads; usually not for a long-running service.
Configuration in production
- profiles per environment, secrets from the environment or a secret manager
spring.jpa.hibernate.ddl-auto=validateplus Flyway migrations- actuator on a separate port:
management.server.port=9001 - structured logs:
logging.structured.format.console=ecs - graceful shutdown so in-flight requests finish:
Kubernetes essentials
The JVM reads container limits by default — set the memory limit, not -Xmx, unless you
have a reason.
Tip
management.endpoint.health.probes.enabled=true gives you the two probe endpoints; combined
with graceful shutdown you get rolling deploys without dropped requests.
Release checklist
-
./mvnw verifygreen, including integration tests - migrations tested against a copy of production data
- no secrets in the image or the repository
- health probes, metrics and logs reaching your platform
- rollback path: previous image tag still deployable
- dependency and base image versions patched
★ Exercises
- Build the jar and run it with the
prodprofile. - Build an image with
spring-boot:build-imageand run it. - Write a layered Dockerfile and compare the rebuild time after a one-line change.
- Enable graceful shutdown and watch a long request finish during
SIGTERM. - Add readiness and liveness probes, then make readiness fail on purpose.