Desplegar en QA y producción con Docker

Aprende Docker → Lección 10

La última lección es la que da sentido a las nueve anteriores. Todo lo visto —imágenes inmutables, configuración fuera, etiquetas trazables— existe para que esto sea posible: validar algo en QA y publicar exactamente eso en producción, con la certeza de que no cambió por el camino.

La regla: construir una vez, promover siempre

El flujo correcto tiene cuatro pasos y solo uno de ellos construye:

# 1. La integración continua construye UNA vez, al fusionar
docker build -t registro.ejemplo.com/mi-app:$COMMIT .
docker push registro.ejemplo.com/mi-app:$COMMIT

# 2. QA descarga esa imagen y la arranca con su configuración
docker pull registro.ejemplo.com/mi-app:$COMMIT
docker run -d --env-file qa.env registro.ejemplo.com/mi-app:$COMMIT

# 3. Se valida en QA

# 4. Producción arranca LA MISMA, con otra configuración
docker run -d --env-file produccion.env registro.ejemplo.com/mi-app:$COMMIT

Entre el paso 2 y el 4 no hay ningún build. Eso es lo esencial. Si en el paso 4 se reconstruyera, entre una construcción y otra podrían cambiar una dependencia transitiva, una versión de la imagen base o un parche de seguridad del sistema, y lo que se publica dejaría de ser lo validado.

Para estar del todo seguro, despliega por digest. Una etiqueta se puede sobrescribir: si alguien vuelve a publicar con el mismo nombre, mi-app:2bbc62e pasaría a apuntar a otra cosa. El digest no, porque es la huella del contenido. En entornos donde esto importe, el despliegue debería fijar mi-app@sha256:af364ec0... en vez de la etiqueta.

Que el contenedor sepa decir si está sano

Un contenedor «arrancado» no es un contenedor que funcione: el proceso puede estar vivo y la aplicación no responder. HEALTHCHECK resuelve esa diferencia:

HEALTHCHECK --interval=5s --timeout=3s --retries=3 \
  CMD curl -fsS http://localhost/salud || exit 1

El estado aparece en la propia lista de contenedores:

docker ps, recién arrancadoUp 1 second (health: starting)
docker ps, unos segundos despuésUp 9 seconds (healthy)
docker inspect --format '{{.State.Health.Status}}' mi-contenedorhealthy

Eso es lo que permite un despliegue sin corte: se levanta el contenedor nuevo, se espera a que diga healthy, y solo entonces se le manda tráfico y se retira el viejo. Sin comprobación de salud, el único criterio es «el proceso arrancó», que no significa gran cosa.

Revertir, que es la parte que se olvida

Si las imágenes están etiquetadas por commit, volver atrás es arrancar la anterior:

docker run -d --env-file produccion.env registro.ejemplo.com/mi-app:e97a329

No hay que reconstruir, ni revertir el repositorio, ni esperar a la integración continua. La imagen anterior sigue en el registro intacta. Esta es la razón práctica más fuerte para no desplegar por latest: con etiquetas móviles la versión anterior deja de ser localizable justo cuando más falta hace.

Una reversión de código no revierte la base de datos. Si el despliegue incluyó una migración que cambió el esquema, volver a la imagen anterior deja una aplicación vieja hablando con una base nueva, que a veces es peor que el fallo original. La regla que lo evita es hacer las migraciones compatibles hacia atrás: añadir columnas antes de usarlas y eliminarlas un despliegue después, nunca en el mismo.

Una lista para el despliegue

Comprobación Por qué
La imagen se construyó una sola vez Es lo que garantiza que QA y producción son lo mismo
La etiqueta identifica el commit Trazabilidad y reversión
La configuración viene de fuera Si no, harían falta dos imágenes
Hay HEALTHCHECK Para saber cuándo está listo de verdad
El proceso corre sin privilegios USER en el Dockerfile; root por defecto es un riesgo
Hay límites de memoria y CPU --memory, --cpus: que un contenedor no tumbe la máquina
La política de reinicio está puesta --restart unless-stopped
Los registros van a la salida estándar Para que los recoja la plataforma, no un archivo dentro
Sabes cómo revertir Y lo has probado alguna vez

Y aquí se cierra el curso

La idea que resume las diez lecciones es que Docker no es sobre todo una herramienta de empaquetado, sino una forma de eliminar la incertidumbre del despliegue. La imagen inmutable, la configuración fuera y la etiqueta trazable sirven todas al mismo fin: que la pregunta «¿qué hay exactamente en producción?» tenga una respuesta exacta, y que volver atrás sea una orden y no una noche en vela.