Aprende Docker → Lección 6
Esta lección es la que hace posible la promesa del curso: que la misma imagen valga para QA y para producción. Si la configuración estuviera dentro de la imagen harían falta dos imágenes distintas, y ya no habría garantía de que lo probado es lo publicado. La solución es que la imagen no sepa en qué entorno corre.
La imagen trae valores por defecto, el arranque los cambia
ENV define valores en la imagen. Al arrancar, -e los sobrescribe:
FROM alpine:3.22
ENV ENTORNO=desarrollo
ENV PUERTO=8080
CMD ["sh","-c","echo \"entorno=$ENTORNO puerto=$PUERTO nivel=${NIVEL_LOG:-info}\""]
docker run --rm mi-demo:enventorno=desarrollo puerto=8080 nivel=info
docker run --rm -e ENTORNO=qa -e NIVEL_LOG=debug mi-demo:enventorno=qa puerto=8080 nivel=debug
docker run --rm -e ENTORNO=produccion -e PUERTO=80 mi-demo:enventorno=produccion puerto=80 nivel=info
Tres contenedores, tres configuraciones, una sola imagen. Esa es toda la idea. Fíjate además en ${NIVEL_LOG:-info}: esa variable no está declarada en el Dockerfile y aun así tiene un valor por defecto, escrito en el propio punto de uso.
Archivos .env para no escribir diez banderas
Cuando las variables son muchas, se agrupan en un archivo:
ENTORNO=qa PUERTO=8080 NIVEL_LOG=debug BASE_URL=https://qa.ejemplo.com
docker run --rm --env-file qa.env mi-app:2bbc62e
Lo habitual es tener un archivo por entorno —qa.env, produccion.env— fuera del repositorio, y que el sistema de despliegue elija cuál pasar. La imagen sigue siendo la misma en los dos casos.
ENV en el Dockerfile queda grabada en una capa, y cualquiera que tenga la imagen puede leerla con docker history. Borrarla en una instrucción posterior no sirve: la capa anterior sigue ahí. Lo mismo vale para un COPY de un archivo de credenciales. Si una clave ha entrado alguna vez en una imagen publicada, hay que darla por comprometida y rotarla.Entonces, ¿dónde van los secretos?
| Situación | Qué usar |
|---|---|
| En tu máquina | Un .env local, listado en .gitignore y en .dockerignore |
| Al arrancar el contenedor | --env-file o -e, que no quedan en la imagen |
| Durante la construcción | RUN --mount=type=secret, que no deja capa |
| Con Compose | La sección secrets: |
| En producción | El gestor de secretos de la plataforma |
ARG tampoco sirve para secretos. Es tentador porque solo existe durante la construcción y no aparece en el entorno del contenedor, pero su valor queda registrado en los metadatos de la imagen y se ve con docker history. Para pasar una credencial al construir, lo correcto es el montaje de secretos, que entrega el valor a una instrucción concreta sin escribirlo en ninguna capa.Lo que debería cambiar entre entornos, y lo que no
| Cambia por entorno | Nunca cambia |
|---|---|
| Direcciones de bases de datos y servicios | El código de la aplicación |
| Credenciales y claves de API | Las dependencias y sus versiones |
| Nivel de registro | La imagen base |
| Límites de recursos y número de réplicas | El identificador de la imagen |
| Dominios y URL públicas | El comportamiento del programa |
Si algo de la columna izquierda está dentro de la imagen, hará falta reconstruir para cambiar de entorno, y ahí se pierde la garantía. Si algo de la derecha cambia entre QA y producción, lo que se validó no es lo que se publica.