Option 1: Dockerfiles, since 2013
Dockerfiles enable you to DIY a script to add layers (OS, runtime, application...) into your container. This provides fantastic flexibility but also risk—it's on you to guarantee correctness, security, optimization, and OS/runtime updates. No pressure.
Option 2: Jib, since 2018
A Google project just for Java, this maven/gradle plugin adds compiled class files to a minimal base image, includes some optimizations for app startup & container rebuilds, and allows configuration per-app (via pom.xml, e.g.). Convenient for simple, Dockerfile and Docker daemon-free builds, but the extreme simplicity and focus on a single app introduces risk at scale (e.g. can you remember what cfg went into each pom.xml?).
Option 3: Cloud Native Buildpacks, since 2018
A collaboration between Heroku and Pivotal (now Broadcom), Buildpacks take source code and produce an OCI image in one simple step that accounts for security, governance, optimizations, and consistency across all applications. A common, shared builder image churns code into layers, guaranteeing all apps across your org are built & updated the same way.
Option 4: Spring Boot, since 2020
Spring Boot's maven/gradle plugins can produce not just JAR fies, but OCI images too (e.g. mvn spring-boot:build-image
). Under the covers, they're actually using Option #3 above, with the OSS Paketo implementation of the Cloud Native Buildpacks project.
Recommendations
I don't know about you, but I'd pick Options 3 or 4 any day of the week for my Java apps!