Containers & Deployment

Docker & Deployment

Docker empaqueta tu aplicación y su entorno en una imagen que se ejecuta igual en cualquier lugar. Los multi-stage builds, el almacenamiento en caché y CI/CD convierten el despliegue en un paso repetible.

intermediate14 min readUpdated 15 sept 2026
Dockerfile
dockerfile
// Dockerfile
FROM node:22-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM nginx:alpine
COPY --from=build /app/dist /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
Imagen
Una plantilla de solo lectura
Contenedor
Una imagen en ejecución
Archivo de construcción
Dockerfile
Capas
Almacenadas en caché y reutilizadas
Compose
Aplicaciones multi-servicio
Registro
Donde se almacenan las imágenes

Por que importa

Por qué los contenedores ganaron la batalla del despliegue

Consistente en todas partes

La imagen incluye el SO, el runtime y las dependencias, por lo que se ejecuta igual en tu laptop, en CI y en producción.

Aislado por defecto

Los contenedores comparten el kernel del host pero aíslan procesos, sistemas de archivos y redes, lo que limita el radio de impacto.

Portable y escalable

La misma imagen se ejecuta en cualquier host de contenedores, lo que hace que escalar y moverse entre nubes sea sencillo.

La imagen completa

Las tres ideas detrás de Docker

Una imagen es la construcción, un contenedor es la ejecución y un registro es cómo las imágenes viajan entre máquinas.

La imagen

Build

Una plantilla de solo lectura y capas construida a partir de un Dockerfile.

El contenedor

Run

Una instancia en ejecución de una imagen con su propio proceso y sistema de archivos.

El registro

Distribute

Un almacén de imágenes desde el cual CI y producción descargan los artefactos.

Docker de un vistazo

El núcleo de Docker

Dockerfile

Instrucciones que construyen una imagen capa por capa.

Capas y caché

Cada instrucción es una capa en caché, por lo que los pasos que no cambian se reutilizan.

Multi-stage builds

Construye en una etapa y envía solo el resultado en una imagen final más pequeña.

Compose

Define y ejecuta aplicaciones multi-contenedor, como una app más una base de datos.

Registro

Sube y descarga imágenes desde Docker Hub, GHCR o un registro privado.

CI/CD

Construye, prueba y despliega automáticamente en cada cambio.

Una breve historia

De las VMs a los contenedores y CI/CD

  1. 2013

    Lanzamiento de Docker

    Los contenedores se vuelven accesibles para los desarrolladores comunes.

    13
  2. 2015

    Compose y orquestación

    Compose y Kubernetes hacen que los despliegues multi-servicio sean prácticos.

    15
  3. 2017

    Multi-stage builds

    Las imágenes de producción más pequeñas se convierten en la práctica estándar.

    17
  4. 2020

    Contenedores en todas partes

    El CI/CD basado en contenedores y las plataformas de contenedores serverless se vuelven comunes.

    20
  5. Today

    La base del despliegue

    La mayoría de los sistemas de producción se despliegan como imágenes de contenedor.

    Today

La guia completa

Docker & Deployment: Todo lo que necesitas saber

Por qué ganaron los contenedores

Antes de los contenedores, desplegar significaba reproducir un entorno: la versión correcta del runtime, las librerías del sistema adecuadas y la configuración precisa. El famoso “en mi máquina funciona” era un problema real, y los servidores tendían a divergir del entorno de desarrollo con el tiempo.

Docker solucionó esto empaquetando la aplicación y su entorno en una sola imagen. La imagen se ejecuta de forma idéntica en una laptop, en CI y en producción, porque lleva consigo todo lo que necesita. Esa consistencia es la razón por la cual los contenedores se convirtieron en el estándar para el despliegue, y por qué aprender Docker es una de las habilidades más valiosas para lanzar software.

Imágenes y contenedores

Una imagen es una plantilla de solo lectura creada a partir de un Dockerfile, compuesta por capas almacenadas en caché. Un contenedor es una instancia en ejecución de una imagen que posee su propia capa escribible, proceso y red. Construyes una vez y ejecutas muchas.

docker build -t my-app:1.0 .
docker run -p 3000:3000 my-app:1.0
docker ps
docker logs <container>

El flag -p mapea un puerto del host a un puerto del contenedor. Los contenedores son efímeros por diseño: puedes detenerlos, eliminarlos y recrearlos libremente porque la imagen es la fuente de verdad.

El Dockerfile

El Dockerfile es la receta de construcción. Cada instrucción crea una capa.

# Dockerfile
FROM node:22-alpine
WORKDIR /app

# install dependencies first for better caching
COPY package*.json ./
RUN npm ci --omit=dev

# then copy source
COPY . .

ENV NODE_ENV=production
EXPOSE 3000
USER node
CMD ["node", "server.js"]

El orden es fundamental. Copiar los manifiestos de dependencias e instalarlas antes de copiar el código fuente significa que un cambio en el código solo invalida la capa de fuente (que es ligera), y no la de instalación (que es costosa). npm ci garantiza una instalación reproducible, y USER node se ejecuta como un usuario que no es root.

Caché de capas

Docker almacena en caché cada capa y la reutiliza cuando las entradas no han cambiado. Por esto, el orden anterior es deliberado: coloca los elementos que cambian rara vez en la parte superior y los que cambian con frecuencia en la parte inferior.

# cached unless package files change
COPY package*.json ./
RUN npm ci

# invalidated on every source change
COPY . .

Un archivo .dockerignore también es importante. Sin él, node_modules, .git y la salida de la compilación se copian en el contexto de construcción, lo que ralentiza el proceso y puede filtrar archivos dentro de la imagen.

node_modules
.git
dist
.env

Builds multi-etapa

Un build multi-etapa compila en una imagen y distribuye únicamente el resultado en otra.

# Dockerfile
FROM node:22-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM nginx:alpine
COPY --from=build /app/dist /usr/share/nginx/html
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

La imagen final contiene solo los archivos estáticos compilados y un servidor web, no el runtime de Node, el código fuente ni las herramientas de construcción. El resultado es más pequeño, se descarga más rápido y tiene una superficie de ataque mucho menor. Para una aplicación de servidor, la etapa final sería una imagen slim de Node solo con las dependencias de producción.

Compose para aplicaciones multiservicio

Las aplicaciones reales suelen necesitar más de un proceso. Compose permite definirlos en conjunto.

# docker-compose.yml
services:
  app:
    build: .
    ports:
      - "3000:3000"
    environment:
      DATABASE_URL: postgres://db:5432/app
    depends_on:
      - db
  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_PASSWORD: example
    volumes:
      - data:/var/lib/postgresql/data

volumes:
  data:

depends_on controla el orden de inicio, volumes persiste los datos entre reinicios de contenedores, y los servicios se comunican entre sí mediante su nombre en la red compartida. Compose es ideal para el desarrollo local y despliegues sencillos en un único host.

Registries y CI/CD

Las imágenes viajan a través de un registry como Docker Hub, GitHub Container Registry o un registry privado. Un pipeline típico consiste en:

  1. Instalar dependencias y ejecutar tests.
  2. Construir la imagen y etiquetarla con el SHA del commit.
  3. Hacer push al registry.
  4. Desplegar la nueva etiqueta en el entorno de destino.
docker build -t ghcr.io/me/app:$GIT_SHA .
docker push ghcr.io/me/app:$GIT_SHA

Debido a que la imagen es inmutable y está etiquetada por commit, los rollbacks consisten simplemente en desplegar una etiqueta anterior. Este es el núcleo de un proceso de despliegue fiable: construir una sola vez, promover el mismo artefacto a través de los entornos y nunca volver a construir para producción.

Prácticas de producción

  • Health checks. Expón un endpoint que la plataforma pueda consultar para saber que el contenedor está listo.
  • Usuario no root. Ejecuta el proceso con el usuario que tenga los privilegios mínimos necesarios.
  • Sistema de archivos de solo lectura siempre que sea posible, con volúmenes de escritura explícitos.
  • Graceful shutdown. Gestiona SIGTERM para finalizar las solicitudes en curso.
  • Límites de recursos. Configura la CPU y la memoria para que un contenedor no pueda agotar los recursos de los demás.
  • Fija las versiones de la imagen base para garantizar builds reproducibles.
  • Secretos en tiempo de ejecución, nunca integrados en la imagen.
  • Imágenes base pequeñas, como Alpine o distroless, para reducir las vulnerabilidades.

Mejores prácticas

  • Ordena las instrucciones del Dockerfile de la que menos cambia a la que más cambia.
  • Utiliza multi-stage builds y despliega únicamente lo necesario.
  • Añade un .dockerignore para node_modules, .git, dist y .env.
  • Ejecuta el proceso como un usuario que no sea root.
  • Etiqueta las imágenes por el SHA del commit, no solo con latest.
  • Construye la imagen una sola vez y promociónala a través de los entornos.
  • Gestiona SIGTERM para un apagado controlado (graceful shutdown).

Errores comunes

  • Copiar node_modules dentro de la imagen.
  • Ejecutar como root.
  • Incluir secretos en la imagen o hacer commit de .env.
  • Usar latest como único tag y perder la reproducibilidad.
  • Reconstruir la imagen de forma distinta para cada entorno.
  • Ignorar .dockerignore y crear builds enormes y lentos.

Próximos pasos

Los contenedores hacen que el despliegue sea predecible, y las mismas habilidades se aplican ya sea que despliegues en una VM, Kubernetes o una plataforma de contenedores serverless. Refuerza los conceptos del runtime con la guía de Node.js, gestiona las dependencias con npm, sírvelo a través de HTTP y asegúralo con Web Security. Después, convierte una aplicación pequeña en un contenedor y despliégala de principio a fin.

Construcción de la imagen

Un multi-stage build mantiene las herramientas de construcción fuera de la imagen final, lo que la hace más pequeña y reduce la superficie de ataque.

Preferir
FROM node:22-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM nginx:alpine
COPY --from=build /app/dist /usr/share/nginx/html
Evitar
FROM node:22
WORKDIR /app
COPY . .
RUN npm install
RUN npm run build
CMD ["node", "dist/server.js"]
# ships dev deps, source
# and build tools

Ejecución como usuario

Ejecuta el contenedor como un usuario que no sea root para que una vulnerabilidad no pueda escalar fácilmente en el host.

Preferir
FROM node:22-alpine
WORKDIR /app
COPY --chown=node:node . .
USER node
CMD ["node", "server.js"]
Evitar
FROM node:22-alpine
WORKDIR /app
COPY . .
# runs as root by default
CMD ["node", "server.js"]

Preguntas frecuentes

Preguntas frecuentes

Keep learning

Related topics from the roadmap.

$ comienza a aprender

Listo para aprender Docker & Deployment?

Nuestro tutorial interactivo te guia a traves de Docker & Deployment paso a paso — con quizzes y codigo real que puedes ejecutar en el navegador.