Packaging Spring Boot Applications for Containerized Deployment with Docker

Containerization has reshaped how backend teams ship Java services, and Australian engineering squads are leaning into the practice as workloads shift toward Sydney and Melbourne cloud regions. For teams building with Spring Boot, moving from a fat JAR running on a local workstation to an immutable image rolling out across a Kubernetes cluster is no longer an exotic exercise, it is the default path. The container also offers predictable startup behaviour, consistent dependencies and a clean way to bundle the JVM tuning along with the bytecode.

What makes the transition smooth is a clear understanding of layered images, image registries and runtime configuration. Engineers at Atlassian, REA Group and the smaller fintechs around Pyrmont and Cremorne routinely treat the Dockerfile as part of the application source. Once the workflow feels routine, the leap from "works on my machine" to "running in production" shrinks from days to minutes.

Preparing a Spring Boot Project for Containerization

Before touching any Dockerfile, the project itself should be in a state that plays nicely with container lifecycles. Externalising configuration through environment variables, keeping the entry point small and ensuring that the application boots in a reasonable window all matter when the same image is scheduled across dozens of pods. Australian teams often wire their application.yml to read from SPRING_DATASOURCE_URL and SPRING_PROFILES_ACTIVE, which lets the same image run in dev, UAT and ATO-style production environments without rebuilding.

Dependency hygiene is another quiet win. The boot fat JAR already pulls in transitives through Maven or Gradle, but a quick mvn dependency:tree reveals whether commons-logging, snappy or some native library has crept in that will not survive inside an Alpine-based image. Brisbane-based squads often adopt the Buildpacks route first through the Spring Boot Maven plugin, then graduate to hand-written Dockerfiles once they need finer control over base images and JVM flags.

Writing a Maintainable Dockerfile for the JVM

A Dockerfile for a Spring Boot service does not need to be exotic. The classic pattern starts from a slim JRE base, copies the layered JAR produced by the Spring Boot tooling, and exposes a single ENTRYPOINT. The layered output is what makes the difference between a five-minute rebuild and a five-second rebuild: dependencies rarely change, so the corresponding layer stays cached across dozens of daily commits pushed from laptops in Surry Hills or St Kilda.

FROM eclipse-temurin:21-jre-jammy
WORKDIR /app
COPY target/*.jar app.jar
EXPOSE 8080
ENTRYPOINT ["java","-jar","app.jar"]

Health checks and graceful shutdown handlers deserve a spot in the image as well. A short-lived container behind a load balancer benefits from an HTTP /actuator/health probe, and Spring Boot Actuator already produces one out of the box. Setting server.shutdown=graceful lets in-flight requests finish before the SIGTERM arrives, which avoids the dreaded 502 storm during a rolling deploy on Amazon EKS or Azure Kubernetes Service inside the Sydney region.

Multi-Stage Builds and Slim Images

Single-stage Dockerfiles work, but they leak build tooling into the final image. Multi-stage builds separate the compile step from the runtime step, so the final layer only carries the JRE, the layered JAR and a curated set of native dependencies. This matters once a security review runs trivy image against a registry in ap-southeast-2 and finds three CVEs in Maven or Gradle binaries that do not belong.

For organisations in the ASX-listed finance space, image size also feeds infrastructure cost. Smaller images boot faster on Fargate, pull faster over the sometimes congested link between an on-prem data centre in Macquarie Park and an AWS Sydney region, and reduce the storage bill on ECR. The pattern is straightforward: build with maven:3.9-eclipse-temurin-21, package into target/*.jar, then copy into a jre:alpine runtime stage. A single docker build -t registry.internal/spring-app:1.4.0 . produces a 180 MB image rather than a 600 MB one.

Registries and the Australian Cloud Footprint

Pushing images to a registry is where local reality starts to bite. Latency from an office in Parramatta or Adelaide to docker.io over a typical NBN business link is fine for developers, but a CI runner sitting in ap-southeast-2 benefits from a nearby registry such as Amazon ECR, Google Artifact Registry, or Azure Container Registry hosted in Australia East. Keeping pulls inside the country also helps with data sovereignty reviews that procurement teams sometimes request when integrating with government or healthcare partners.

Tagging should follow a sane scheme. Stamping images with the Git SHA, the build number and latest for the development track gives developers a frictionless path, while immutable tags such as 1.4.0-a1f3c9d protect production rollbacks. Login is handled once through aws ecr get-login-password, and most pipelines cache credentials using OIDC roles rather than long-lived access keys, which keeps things tidy for an APRA-aligned audit.

Running Containers in Production

The image is only half the story. Once it lands on the registry, the deployment description needs to map JVM ergonomics, environment variables and resource requests onto the cluster. Spring Boot exposes Actuator endpoints that pair naturally with Kubernetes liveness and readiness probes, and a sidecar such as Prometheus scrapes Micrometer metrics without any code change. Teams running kube-prometheus-stack in AKS clusters around Sydney Olympic Park often mirror the same dashboards across dev and prod so that incident reviews stay consistent.

When the rollout misbehaves, logs are the fastest compass. Structured JSON logging through Logback, shipped to an Elasticsearch cluster running in Sydney, turns a vague "pod crashlooping" into a precise stack trace with a timestamp aligned to AEST. Paired with distributed tracing from OpenTelemetry, the same image gives the on-call engineer enough context to either fix the bug or roll back to the previous tag before the morning standup in the Melbourne office even starts.

Practical Pointers for Reliable Container Rollouts