Introducción: ¿Por qué Docker es importante para el desarrollador Java?
El desarrollo moderno de Java rara vez prescinde de la contenerización. Docker permite empaquetar la aplicación junto con todas sus dependencias, JVM y configuración en un contenedor aislado. Esto resuelve el problema de «funciona en mi máquina» y simplifica el CI/CD. En este artículo, analizaremos el ciclo completo: desde la instalación de Docker hasta la optimización de imágenes para producción.
1. Fundamentos de Docker para Java
1.1 ¿Qué es Docker y por qué es útil para proyectos Java?
Docker es una plataforma para crear, distribuir y ejecutar aplicaciones en contenedores. Para Java, esto es especialmente relevante:
- Aislamiento de versiones de JVM — se puede usar Java 11 para un servicio y Java 17 para otro en el mismo host.
- Reproducibilidad — la imagen contiene la versión exacta del JDK, bibliotecas y utilidades del sistema.
- Escalabilidad — es fácil ejecutar múltiples instancias mediante Kubernetes o Docker Swarm.
1.2 Instalación de Docker
Para empezar, instale Docker Desktop (Windows/Mac) o Docker Engine (Linux). Verifique la instalación:
docker --versiondocker info2. Creación de un Dockerfile para una aplicación Java
Consideremos una aplicación Spring Boot simple. Crearemos un archivo Dockerfile en la raíz del proyecto.
2.1 Dockerfile básico
# Usamos la imagen oficial de OpenJDKFROM openjdk:17-jdk-alpine
# Establecemos el directorio de trabajoWORKDIR /app
# Copiamos el archivo JARCOPY target/myapp.jar app.jar
# Abrimos el puertoEXPOSE 8080
# Comando de inicioENTRYPOINT ["java", "-jar", "app.jar"]2.2 Construcción y ejecución del contenedor
# Construcción de la imagendocker build -t my-java-app .
# Ejecución del contenedordocker run -p 8080:8080 my-java-appDespués de la ejecución, la aplicación estará disponible en http://localhost:8080.
3. Optimización de imágenes Docker para Java
Las imágenes grandes ralentizan el despliegue. Analicemos las técnicas clave de optimización.
3.1 Construcción multi-etapa (Multi-stage builds)
Permite separar la etapa de compilación de la etapa de ejecución. En la imagen final solo se incluye el JAR, sin Maven/Gradle ni los fuentes.
# Etapa de compilaciónFROM maven:3.8.5-openjdk-17 AS buildWORKDIR /appCOPY pom.xml .RUN mvn dependency:go-offlineCOPY src ./srcRUN mvn package -DskipTests
# Etapa de ejecuciónFROM openjdk:17-jdk-alpineWORKDIR /appCOPY --from=build /app/target/myapp.jar app.jarEXPOSE 8080ENTRYPOINT ["java", "-jar", "app.jar"]3.2 Optimización de capas
Docker almacena en caché las capas. Separe la copia de datos: primero las dependencias (cambian raramente), luego el código (cambia con frecuencia).
FROM maven:3.8.5-openjdk-17 AS buildWORKDIR /app# Copiamos solo el POM y descargamos dependenciasCOPY pom.xml .RUN mvn dependency:go-offline# Copiamos los fuentes y compilamosCOPY src ./srcRUN mvn package -DskipTests
FROM openjdk:17-jdk-alpineWORKDIR /appCOPY --from=build /app/target/*.jar app.jarEXPOSE 8080ENTRYPOINT ["java", "-jar", "app.jar"]3.3 Uso de jlink para crear una JRE mínima
Si usa Java 9+, puede crear una JRE personalizada solo con los módulos necesarios.
FROM openjdk:17-slim AS jre-buildRUN jlink --add-modules java.base,java.logging,java.sql \ --output /jre \ --strip-debug \ --no-man-pages \ --no-header-files
FROM alpine:latestCOPY --from=jre-build /jre /jreCOPY target/app.jar /app.jarENTRYPOINT ["/jre/bin/java", "-jar", "/app.jar"]Esta imagen puede pesar menos de 50 MB en lugar de 300+ MB.
4. Docker Compose para microservicios Java
Si tiene varios servicios (por ejemplo, Spring Boot + PostgreSQL), use docker-compose.yml.