Introducción a Docker y Java
El desarrollo moderno de aplicaciones Java es impensable sin la contenedorización. Docker es una plataforma para empaquetar, distribuir y ejecutar aplicaciones en entornos aislados (contenedores). Para los desarrolladores de Java, Docker resuelve el problema eterno: «¡En mi máquina funciona!». El contenedor garantiza que su aplicación se ejecute de la misma manera en la máquina local, el servidor de desarrollo y en producción.
En este artículo, analizaremos cómo contenedorizar aplicaciones Java con Docker: desde un Dockerfile simple hasta la optimización de imágenes para arquitectura de microservicios. Todos los ejemplos están escritos en Java y listos para usar.
Fundamentos de Docker para aplicaciones Java
¿Qué es una imagen Docker y un contenedor?
Una imagen Docker es una plantilla (de solo lectura) que contiene todo lo necesario para ejecutar una aplicación: JVM, bibliotecas, código y configuraciones. Un contenedor es una instancia en ejecución de la imagen. Para Java, esto significa que no necesita instalar manualmente el JDK en el servidor — la JVM ya estará dentro del contenedor.
Creación de un Dockerfile simple para Java
Consideremos un ejemplo básico. Tenemos una aplicación Java simple (por ejemplo, HelloWorld.java).
// HelloWorld.javapublic class HelloWorld { public static void main(String[] args) { System.out.println("Hello from Docker and Java!"); }}Creemos un Dockerfile:
# Usamos la imagen oficial de OpenJDKFROM openjdk:11-jre-slim
# Establecemos el directorio de trabajoWORKDIR /app
# Copiamos el jar compilado o los archivos classCOPY HelloWorld.class .
# Comando de ejecuciónCMD ["java", "HelloWorld"]Compilación y ejecución:
# Compilación de la imagendocker build -t hello-java .
# Ejecución del contenedordocker run hello-javaSalida: Hello from Docker and Java!
Contenedorización de aplicaciones Spring Boot
Para proyectos reales (por ejemplo, en Spring Boot), el proceso se vuelve más complejo. Consideremos un microservicio típico.
Compilación multi-etapa (Multi-stage build)
Esta es la mejor práctica para Java: primero compilamos la aplicación con el JDK completo, luego copiamos el resultado en una imagen ligera de JRE.
# Etapa 1: CompilaciónFROM maven:3.8.5-openjdk-11 AS buildWORKDIR /appCOPY pom.xml .RUN mvn dependency:go-offlineCOPY src ./srcRUN mvn clean package -DskipTests
# Etapa 2: EjecuciónFROM openjdk:11-jre-slimWORKDIR /appCOPY --from=build /app/target/*.jar app.jarEXPOSE 8080ENTRYPOINT ["java", "-jar", "app.jar"]Explicación:
- build — usa Maven y el JDK completo para la compilación.
- Imagen final — contiene solo JRE y el archivo jar listo. El tamaño de la imagen se reduce 2-3 veces.
Optimización del almacenamiento en caché de capas
Docker almacena en caché cada capa (instrucción). Para acelerar la compilación, coloque las dependencias que cambian con poca frecuencia al principio:
FROM maven:3.8.5-openjdk-11 AS buildWORKDIR /app# Almacenamos en caché las dependenciasCOPY pom.xml .RUN mvn dependency:go-offline# Ahora copiamos el códigoCOPY src ./srcRUN mvn clean packageAhora, si solo cambia el código, Docker recompilará solo las últimas capas, mientras que las dependencias se tomarán de la caché.
Trabajo con variables de entorno y perfiles
Paso de parámetros a la aplicación Java
Docker permite configurar la aplicación de manera flexible a través de variables de entorno. Para Spring Boot, esto es especialmente conveniente.
docker run -e SPRING_PROFILES_ACTIVE=prod -e DB_URL=jdbc:postgresql://db:5432/mydb my-appEn el Dockerfile se pueden establecer valores predeterminados:
ENV SPRING_PROFILES_ACTIVE=devENV DB_URL=jdbc:h2:mem:testdbEjemplo de docker-compose para Java + BD
Para microservicios, es conveniente usar docker-compose.yml:
version: '3.8'services: app: bu