Dockerización y Despliegues en Producción: Multi-Stage Builds y Seguridad
Lo Que Dominarás en Este Tutorial
- Reducir imágenes de 1.2 GB a menos de 85 MB con patrones de construcción multi-etapa
- Blindar la seguridad del contenedor configurando y ejecutando usuarios no root
- Configurar Docker Compose con comprobaciones de salud para PostgreSQL y caché Redis
- Optimizar el almacenamiento en caché de capas para acelerar los pipelines CI/CD más del 70%
# Etapa 1: Compilación
FROM node:22-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# Etapa 2: Imagen Final Ligera
FROM node:22-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
# Usuario sin privilegios por seguridad
USER node
COPY --chown=node:node package*.json ./
RUN npm ci --only=production && npm cache clean --force
COPY --chown=node:node --from=builder /app/dist ./dist
EXPOSE 3000
CMD ["node", "dist/server.js"]
Preguntas Frecuentes
Profundizando: la contenerización en la práctica
El Dockerfile multi-stage de este tutorial, que reduce una imagen de 1,2 GB a menos de 85 MB, es solo la mitad visible de la contenerización en producción. La otra mitad son los hábitos que la rodean: construir una imagen y promover ese mismo artefacto por todos los entornos, replicar producción en local con pilas de Docker Compose cuyos health checks de PostgreSQL y cachés de Redis se comportan como los reales, y ordenar las capas del Dockerfile para que las compilaciones de CI/CD se mantengan en caché y rápidas. Los equipos que interiorizan esos hábitos dejan de tener sorpresas del tipo «funciona en el contenedor, falla en producción», porque la definición del contenedor se convierte en el contrato de entorno de todo el pipeline.
Errores comunes
- Copiar todo el repositorio antes de instalar las dependencias. Un COPY amplio invalida la caché de capas con cada cambio de código. El Dockerfile del tutorial copia primero los manifiestos de paquetes y ejecuta npm ci antes de añadir el código, de modo que las capas de dependencias sobreviven a las ediciones.
- Ejecutar el contenedor de producción como root. La etapa final crea el usuario sin privilegios node y cambia a él por una razón: si el proceso se ve comprometido alguna vez, quien ataque heredará los menores privilegios posibles dentro del contenedor.
- Enviar la etapa de construcción a producción. Compiladores, dependencias de desarrollo y cachés de compilación multiplican el tamaño de la imagen y la superficie de ataque. Las compilaciones multi-stage existen para que solo lleguen a la imagen final el resultado compilado y las dependencias de producción.
- Tratar los contenedores como lugar donde guardar datos. Todo lo que se escribe en el sistema de archivos de un contenedor desaparece cuando este se reemplaza. Los datos duraderos pertenecen a volúmenes o servicios gestionados, igual que la pila de Compose ejecuta PostgreSQL como un servicio propio con health checks.
Preguntas frecuentes
¿Por qué el tutorial construye sobre Alpine Linux y no sobre una imagen basada en Debian?
Como explica la sección de preguntas del tutorial, las imágenes base de Alpine parten de apenas 5 MB e incluyen muchos menos paquetes instalados, lo que reduce drásticamente la superficie de ataque frente a vulnerabilidades CVE. El contrapunto a verificar es la compatibilidad de módulos nativos, porque Alpine usa una biblioteca C distinta de la de Debian.
¿Debería usar contenedores o máquinas virtuales?
Los contenedores comparten el núcleo del anfitrión, así que arrancan en segundos y se empaquetan con densidad en una sola máquina; las máquinas virtuales aíslan un sistema operativo huésped completo a un costo mayor. La mayoría de las aplicaciones en la nube corre en contenedores, muy a menudo sobre anfitriones virtualizados por debajo.
¿Cómo sé si una pila de Compose está realmente lista para recibir tráfico?
Usa health checks, como hace este tutorial con PostgreSQL: los servicios dependientes deben esperar a que un servicio se reporte sano, no simplemente arrancado, antes de conectarse; de lo contrario, las primeras peticiones golpean una base de datos que aún se está inicializando.