Configuración por entorno en Docker

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.

Los secretos no van en la imagen. Nunca. Una contraseña puesta con 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.