Contenerizar una App Node.js con Docker para Producción Containerize a Node.js App with Docker for Production

Docker asegura que tu aplicación Node.js se ejecute igual en cualquier entorno: desarrollo, CI/CD y producción. En esta guía aprenderás a construir imágenes optimizadas con multi-stage builds, orquestar servicios con docker-compose y seguir las mejores prácticas de seguridad para contenedores en producción. Docker ensures your Node.js application runs identically across every environment: development, CI/CD and production. In this guide you'll learn to build optimized images with multi-stage builds, orchestrate services with docker-compose and follow security best practices for production containers.

1. Por qué Docker para Node.js1. Why Docker for Node.js

El problema clásico "en mi máquina funciona" desaparece con Docker. Los contenedores encapsulan el runtime de Node.js, las dependencias y la configuración del sistema operativo en una imagen reproducible y portable: The classic "it works on my machine" problem disappears with Docker. Containers encapsulate the Node.js runtime, dependencies and OS configuration into a reproducible, portable image:

  • Entornos idénticos en dev, staging y producciónIdentical environments in dev, staging and production
  • Despliegues rápidos y rollbacks trivialesFast deployments and trivial rollbacks
  • Escalado horizontal con Kubernetes o Docker SwarmHorizontal scaling with Kubernetes or Docker Swarm
  • Aislamiento de seguridad entre serviciosSecurity isolation between services

2. Dockerfile multi-stage para producción2. Multi-Stage Dockerfile for Production

Un multi-stage build separa la fase de construcción (con herramientas de desarrollo) de la imagen final de producción (solo el runtime). El resultado es una imagen más pequeña y segura: A multi-stage build separates the build phase (with dev tools) from the final production image (runtime only). The result is a smaller, more secure image:

# ---- Stage 1: Build ----
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build   # Compila TypeScript a dist/

# ---- Stage 2: Production ----
FROM node:20-alpine AS production
WORKDIR /app

# Usuario no-root para seguridad
RUN addgroup -S appgroup && adduser -S appuser -G appgroup

COPY package*.json ./
RUN npm ci --omit=dev  && npm cache clean --force

COPY --from=builder /app/dist ./dist

USER appuser
EXPOSE 3000

HEALTHCHECK --interval=30s --timeout=5s \
  CMD wget -qO- http://localhost:3000/health || exit 1

CMD ["node", "dist/index.js"]

Puntos clave de seguridad: usa node:20-alpine (imagen mínima), corre como usuario no-root y añade un HEALTHCHECK para que orquestadores como ECS o Kubernetes sepan cuándo el contenedor está listo. Key security points: use node:20-alpine (minimal image), run as a non-root user and add a HEALTHCHECK so orchestrators like ECS or Kubernetes know when the container is ready.

3. Archivo .dockerignore3. The .dockerignore File

El .dockerignore evita que archivos innecesarios (o sensibles) entren al contexto de construcción de Docker, reduciendo el tamaño y el tiempo de build: The .dockerignore prevents unnecessary (or sensitive) files from entering the Docker build context, reducing image size and build time:

node_modules
dist
.git
.env
.env.*
*.log
coverage
.nyc_output
README.md
*.test.ts
__tests__

4. docker-compose para desarrollo local4. docker-compose for Local Development

docker-compose.yml orquesta múltiples servicios (app + base de datos + cache) con un solo comando: docker-compose.yml orchestrates multiple services (app + database + cache) with a single command:

version: '3.9'
services:
  api:
    build:
      context: .
      target: builder   # Stage de desarrollo con hot-reload
    volumes:
      - .:/app
      - /app/node_modules
    ports:
      - "3000:3000"
    env_file: .env
    depends_on:
      db:
        condition: service_healthy

  db:
    image: postgres:16-alpine
    environment:
      POSTGRES_DB: mydb
      POSTGRES_USER: postgres
      POSTGRES_PASSWORD: ${DB_PASSWORD}
    volumes:
      - pgdata:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 5s
      timeout: 3s
      retries: 5

volumes:
  pgdata:

5. Variables de entorno y secretos5. Environment Variables and Secrets

Nunca embeds secretos en la imagen Docker. Usa variables de entorno inyectadas en tiempo de ejecución. Para producción en AWS/GCP, usa sus servicios de Secrets Manager: Never embed secrets in the Docker image. Use environment variables injected at runtime. For production on AWS/GCP, use their Secrets Manager services:

# Pasar variables al ejecutar el contenedor
docker run -d \
  --name api \
  --env-file .env.production \
  -p 3000:3000 \
  mi-api:latest

# O con Docker Compose en producción
docker compose -f docker-compose.prod.yml up -d

6. Push al registry y deploy6. Push to Registry and Deploy

# Build con tag de versión
docker build -t mi-usuario/mi-api:1.0.0 .
docker build -t mi-usuario/mi-api:latest .

# Push a Docker Hub (o GitHub Container Registry: ghcr.io)
docker login
docker push mi-usuario/mi-api:1.0.0
docker push mi-usuario/mi-api:latest

# Deploy en servidor remoto con SSH
ssh user@servidor "docker pull mi-usuario/mi-api:latest && \
  docker-compose -f /app/docker-compose.prod.yml up -d --no-deps api"

ConclusiónConclusion

Docker + multi-stage builds es la forma estándar de empaquetar apps Node.js para producción en 2026. Un Dockerfile bien escrito reduce el tamaño de imagen hasta un 70%, mejora la seguridad con usuarios no-root y hace los deploys reproducibles en cualquier nube. Docker + multi-stage builds is the standard way to package Node.js apps for production in 2026. A well-written Dockerfile reduces image size by up to 70%, improves security with non-root users and makes deployments reproducible on any cloud.

¿Necesitas ayuda containerizando tu aplicación o configurando un pipeline CI/CD con Docker? Contáctame y configuramos tu infraestructura juntos. Need help containerizing your application or setting up a CI/CD pipeline with Docker? Contact me and we'll configure your infrastructure together.

← React Native← React Native Siguiente: Desplegar Astro en Netlify →Next: Deploy Astro to Netlify →

Servicios de desarrollo de software: Santiago Alexander Aguilar Torres

Soy Santiago Alexander Aguilar Torres, desarrollador Full-Stack colombiano con sede en Tunja, Boyacá. Desarrollo aplicaciones web, plataformas móviles con Flutter y React Native, servicios backend con Node.js y Spring Boot, e infraestructura Linux VPS con Docker.

Disponible para roles de ingeniería y proyectos técnicos directos. Respuesta en menos de 24 horas.

Tecnologías y especialidades

Investigación y ponencias

Ponente en más de 6 congresos internacionales de ingeniería en Colombia: TEINCO 2025, CIISS 2025, TEINCO 2024, ENIIU 2024, Ci3S 2024. Co-investigador en proyectos de transporte urbano con validación offline y plataformas universitarias.

Disponibilidad y contacto

Disponible para trabajo remoto desde Colombia en roles Full-Stack Developer, Backend Developer y Freelance. Clientes en Colombia, Latinoamérica y España. Email: santiagoaguilart0@gmail.com. LinkedIn: santiagoaguilartorres-fullstack. WhatsApp: +57 314 256 6364.

—