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.