Saltearse al contenido

Configuración de Docker

Tabla de Contenidos

  1. Propósito
  2. ¿Para quién es esto?
  3. Arquitectura de Dockerfile
  4. Configuración de Docker Compose
  5. Construcción de Imágenes Docker
  6. Ejecución de Servicios con Docker
  7. Referencia de Comandos Docker
  8. Verificación y Health Checks
  9. Solución de Problemas

Propósito

Esta guía explica la configuración de Docker para la plataforma Algesta, cubriendo Dockerfiles para microservicios individuales y configuraciones de Docker Compose para desarrollo local y pruebas. Proporciona análisis detallado de builds multi-etapa, gestión de dependencias y orquestación de contenedores.

Siguiendo esta guía, entenderás:

  • Estructura y optimización de Dockerfile multi-etapa
  • Cómo construir imágenes Docker listas para producción
  • Configuración de Docker Compose para desarrollo full-stack
  • Health checks y gestión de dependencias
  • Redes de contenedores y gestión de volúmenes

¿Para quién es esto?

Esta guía es para desarrolladores ejecutando servicios en contenedores localmente, ingenieros DevOps preparando imágenes para despliegue y administradores de sistemas gestionando entornos contenerizados. Asume familiaridad con Docker, Docker Compose y conceptos de contenerización.


Arquitectura de Dockerfile

Todos los microservicios de Algesta usan Dockerfiles multi-etapa para optimizar el tamaño de imagen y eficiencia de build. El patrón sigue dos etapas: Builder (compilación) y Final (runtime).

Dockerfile del Microservicio Orders

Ubicación: algesta-ms-orders-nestjs/Dockerfile

# ============================
# Builder Stage
# ============================
FROM node:20-slim AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
# Si husky falla no detiene el proceso
RUN npm install -g husky && npx husky install || echo "husky skipped"
COPY . .
RUN npm run build
# ============================
# Final Stage
# ============================
FROM node:20-slim
WORKDIR /app
COPY package*.json ./
# Instala Puppeteer con Chromium
RUN apt-get update && \
apt-get install -y wget ca-certificates fonts-liberation libappindicator3-1 libasound2 libatk-bridge2.0-0 libatk1.0-0 libc6 libdrm2 libgbm1 libnspr4 libnss3 libx11-xcb1 libxcomposite1 libxdamage1 libxrandr2 xdg-utils
# Instala todo lo necesario, incluyendo bcrypt compilado
RUN npm install --force --only=production bcrypt
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/src/shared/templates ./dist/src/shared/templates
ENV PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=false
EXPOSE 3000
CMD ["node", "dist/main"]

Desglose del Dockerfile

Etapa Builder

Propósito: Compilar TypeScript a JavaScript, ejecutar pasos de build

Pasos Clave:

  1. Imagen Base: node:20-slim - Imagen mínima de Node.js 20
  2. Directorio de Trabajo: /app
  3. Copiar Archivos de Paquetes: package*.json para instalación de dependencias
  4. Instalar Dependencias: npm ci para instalaciones limpias y reproducibles
  5. Configuración de Husky: Instalar git hooks (se salta si falla, no es crítico para build)
  6. Copiar Código Fuente: Copiar todos los archivos fuente
  7. Build: npm run build compila TypeScript a dist/

¿Por Qué Etapa Builder?

  • Separa dependencias de build del runtime
  • Reduce tamaño final de imagen (sin devDependencies)
  • Cachea capa de npm install para rebuilds más rápidos

Etapa Final

Propósito: Crear imagen de producción ligera con solo dependencias de runtime

Pasos Clave:

  1. Imagen Base: node:20-slim fresco
  2. Dependencias del Sistema: Instalar dependencias de Puppeteer/Chromium:
    • wget, ca-certificates: Capacidades de descarga
    • Librerías de fuentes: Renderizado de texto en PDFs
    • Librerías GTK/X11: Soporte de navegador sin cabeza
  3. Dependencias de Producción: npm install --force --only=production bcrypt
    • --only=production: Excluir devDependencies
    • --force: Reconstruir módulos nativos (bcrypt) para arquitectura correcta
  4. Copiar Artefactos:
    • Código compilado del builder: /app/dist
    • Plantillas de email: /app/src/shared/templates (requerido en runtime)
  5. Entorno: PUPPETEER_SKIP_CHROMIUM_DOWNLOAD=false asegura que Chromium esté disponible
  6. Exponer Puerto: 3000 (sobreescrito por env PORT en producción)
  7. Comando: node dist/main - Iniciar aplicación compilada

¿Por Qué Compilación Nativa?

  • bcrypt usa bindings nativos compilados para la arquitectura del host
  • Etapa builder se ejecuta en máquina de build (ej., macOS, Linux x86)
  • Etapa final puede ejecutarse en arquitectura diferente (ej., Cloud Run en Linux ARM)
  • Reconstruir en etapa final asegura compatibilidad

Dockerfile para Otros Microservicios

Microservicios Notifications y Provider usan Dockerfiles similares con diferencias menores:

  • Notifications: Puede omitir dependencias de Puppeteer si no genera PDFs
  • Provider: Incluye SDKs de Azure Storage, configuración similar de Puppeteer

API Gateway tiene Dockerfile más simple (sin Puppeteer, sin bcrypt):

FROM node:20-slim AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM node:20-slim
WORKDIR /app
COPY package*.json ./
RUN npm install --only=production
COPY --from=builder /app/dist ./dist
EXPOSE 3000
CMD ["node", "dist/main"]

Configuración de Docker Compose

Docker Compose orquesta múltiples contenedores para desarrollo local, habilitando pruebas full-stack sin gestión manual de servicios.

Docker Compose de Servicio Individual

Ejemplo: algesta-ms-orders-nestjs/docker-compose.yml

version: "3.8"
services:
postgres:
image: postgres:15-alpine
container_name: auth-ms-postgres
environment:
POSTGRES_USER: postgres
POSTGRES_PASSWORD: postgres
POSTGRES_DB: auth_ms
ports:
- "5432:5432"
volumes:
- postgres_data:/var/lib/postgresql/data
networks:
- auth_network
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
auth-ms:
build:
context: .
dockerfile: Dockerfile
container_name: auth-ms
depends_on:
postgres:
condition: service_healthy
environment:
- NODE_ENV=development
- DB_HOST=postgres
- DB_PORT=5432
- DB_USERNAME=postgres
- DB_PASSWORD=postgres
- DB_DATABASE=auth_ms
ports:
- "3000:3000"
networks:
- auth_network
volumes:
postgres_data:
networks:
auth_network:
name: auth_network
driver: bridge

Nota: El ejemplo anterior es del repositorio de Orders MS pero referencia Postgres (probablemente desactualizado de una plantilla). Algesta usa MongoDB, no Postgres.

Docker Compose Full-Stack

Configuración Recomendada: Crear docker-compose.yml en directorio raíz de Algesta para todos los servicios.

version: "3.8"
services:
# ============================
# Infrastructure Services
# ============================
mongodb:
image: mongo:7
container_name: algesta-mongodb
ports:
- "27017:27017"
volumes:
- algesta-mongo-data:/data/db
networks:
- algesta-network
healthcheck:
test: ["CMD", "mongosh", "--eval", "db.adminCommand('ping')"]
interval: 10s
timeout: 5s
retries: 5
restart: unless-stopped
redis:
image: redis:7-alpine
container_name: algesta-redis
ports:
- "6379:6379"
volumes:
- algesta-redis-data:/data
networks:
- algesta-network
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 5s
retries: 5
restart: unless-stopped
kafka:
image: confluentinc/cp-kafka:7.5.0
container_name: algesta-kafka
depends_on:
- zookeeper
ports:
- "9092:9092"
environment:
KAFKA_BROKER_ID: 1
KAFKA_ZOOKEEPER_CONNECT: zookeeper:2181
KAFKA_ADVERTISED_LISTENERS: PLAINTEXT://localhost:9092
KAFKA_OFFSETS_TOPIC_REPLICATION_FACTOR: 1
networks:
- algesta-network
restart: unless-stopped
zookeeper:
image: confluentinc/cp-zookeeper:7.5.0
container_name: algesta-zookeeper
ports:
- "2181:2181"
environment:
ZOOKEEPER_CLIENT_PORT: 2181
ZOOKEEPER_TICK_TIME: 2000
networks:
- algesta-network
restart: unless-stopped
# ============================
# Microservices
# ============================
orders-ms:
build:
context: ./algesta-ms-orders-nestjs
dockerfile: Dockerfile
container_name: algesta-orders-ms
depends_on:
mongodb:
condition: service_healthy
redis:
condition: service_healthy
kafka:
condition: service_started
environment:
- NODE_ENV=development
- PORT=3001
- MONGODB_URI=mongodb://mongodb:27017/orders_ms
- REDIS_HOST=redis
- REDIS_PORT=6379
- KAFKA_BROKERS=kafka:9092
- JWT_SECRET=dev-secret-minimum-32-characters-long-for-local
ports:
- "3001:3001"
networks:
- algesta-network
volumes:
- ./algesta-ms-orders-nestjs:/app
- /app/node_modules
restart: unless-stopped
notifications-ms:
build:
context: ./algesta-ms-notifications-nestjs
dockerfile: Dockerfile
container_name: algesta-notifications-ms
depends_on:
mongodb:
condition: service_healthy
redis:
condition: service_healthy
kafka:
condition: service_started
environment:
- NODE_ENV=development
- PORT=3002
- MONGODB_URI=mongodb://mongodb:27017/notifications_ms
- REDIS_HOST=redis
- REDIS_PORT=6379
- KAFKA_BROKERS=kafka:9092
ports:
- "3002:3002"
networks:
- algesta-network
restart: unless-stopped
provider-ms:
build:
context: ./algesta-ms-provider-nestjs
dockerfile: Dockerfile
container_name: algesta-provider-ms
depends_on:
mongodb:
condition: service_healthy
redis:
condition: service_healthy
kafka:
condition: service_started
environment:
- NODE_ENV=development
- PORT=3003
- MONGODB_URI=mongodb://mongodb:27017/providers_ms
- REDIS_HOST=redis
- REDIS_PORT=6379
- KAFKA_BROKERS=kafka:9092
- JWT_SECRET=dev-secret-minimum-32-characters-long-for-local
ports:
- "3003:3003"
networks:
- algesta-network
restart: unless-stopped
api-gateway:
build:
context: ./algesta-api-gateway-nestjs
dockerfile: Dockerfile
container_name: algesta-api-gateway
depends_on:
- orders-ms
- notifications-ms
- provider-ms
- redis
environment:
- NODE_ENV=development
- PORT=3000
- MS_ORDERS_URL=http://orders-ms:3001
- MS_NOTIFICATIONS_URL=http://notifications-ms:3002
- MS_PROVIDER_URL=http://provider-ms:3003
- REDIS_HOST=redis
- REDIS_PORT=6379
- JWT_SECRET=dev-secret-minimum-32-characters-long-for-local
- RATE_LIMIT_MAX=100
- RATE_LIMIT_WINDOW_MS=60000
ports:
- "3000:3000"
networks:
- algesta-network
restart: unless-stopped
volumes:
algesta-mongo-data:
algesta-redis-data:
networks:
algesta-network:
driver: bridge

Funcionalidades de Docker Compose

Health Checks

Propósito: Asegurar que las dependencias estén listas antes de iniciar servicios dependientes

Health Check de MongoDB:

healthcheck:
test: ["CMD", "mongosh", "--eval", "db.adminCommand('ping')"]
interval: 10s
timeout: 5s
retries: 5

Explicación:

  • Comando de Prueba: Hace ping a MongoDB para verificar que responde
  • Intervalo: Verificar cada 10 segundos
  • Timeout: Esperar máximo 5 segundos para respuesta
  • Reintentos: Reintentar 5 veces antes de marcar como no saludable

Beneficios:

  • Previene condiciones de carrera (ej., servicio intentando conectar a MongoDB antes de que esté listo)
  • depends_on.condition: service_healthy espera a que health check pase

Gestión de Dependencias

Orden de Inicio:

depends_on:
mongodb:
condition: service_healthy # Wait for health check
redis:
condition: service_healthy
kafka:
condition: service_started # Just wait for container start (no health check)

Orden de Operaciones:

  1. Iniciar infraestructura: MongoDB, Redis, Zookeeper, Kafka
  2. Esperar a que health checks pasen
  3. Iniciar microservicios (Orders, Notifications, Provider)
  4. Iniciar API Gateway (depende de todos los microservicios)

Volúmenes

Volúmenes Nombrados:

volumes:
algesta-mongo-data: # Persists MongoDB data
algesta-redis-data: # Persists Redis snapshots

Bind Mounts (Desarrollo):

volumes:
- ./algesta-ms-orders-nestjs:/app # Sincronizar cambios de código
- /app/node_modules # Preservar node_modules del contenedor

Beneficios:

  • Volúmenes Nombrados: Persistir datos a través de reinicios de contenedor
  • Bind Mounts: Habilitar hot-reload durante desarrollo
  • Volumen Anónimo /app/node_modules: Previene que node_modules del host sobreescriba los del contenedor

Redes

Red Bridge:

networks:
algesta-network:
driver: bridge

Beneficios:

  • Todos los servicios en la misma red pueden comunicarse vía nombres de servicio
  • mongodb://mongodb:27017 resuelve al contenedor de MongoDB
  • Aislado de la red del host (a menos que los puertos estén expuestos)

Construir Imágenes Docker

Construir Servicio Individual

Ventana de terminal
cd algesta-ms-orders-nestjs
docker build -t algesta-orders-ms:latest .

Construir con Tag Personalizado:

Ventana de terminal
docker build -t algesta-orders-ms:v1.0.0 .

Construir para Plataforma Específica:

Ventana de terminal
docker build --platform linux/amd64 -t algesta-orders-ms:latest .

Verificación:

Ventana de terminal
docker images | grep algesta-orders-ms
# Esperado: algesta-orders-ms latest <image-id> X minutes ago XMB

Construir Todos los Servicios (Docker Compose)

Ventana de terminal
cd ~/Documents/3A/Algesta # Root directory with docker-compose.yml
docker-compose build

Build with No Cache (force rebuild):

Ventana de terminal
docker-compose build --no-cache

Build Specific Service:

Ventana de terminal
docker-compose build orders-ms

Verification:

Ventana de terminal
docker-compose images
# Lists all images built by docker-compose

Running Services with Docker

Run Individual Service

Ventana de terminal
docker run -d \
--name algesta-orders-ms \
-p 3001:3001 \
-e NODE_ENV=development \
-e MONGODB_URI=mongodb://host.docker.internal:27017/orders_ms \
-e REDIS_HOST=host.docker.internal \
-e JWT_SECRET=dev-secret \
algesta-orders-ms:latest

Flags:

  • -d: Detached mode (run in background)
  • --name: Container name
  • -p 3001:3001: Port mapping (host:container)
  • -e: Environment variables
  • host.docker.internal: Host machine IP from container perspective (macOS/Windows)

Run All Services (Docker Compose)

Ventana de terminal
cd ~/Documents/3A/Algesta
docker-compose up -d

Commands:

Ventana de terminal
# Start all services in foreground (see logs)
docker-compose up
# Start in background (detached)
docker-compose up -d
# Start specific service
docker-compose up -d orders-ms
# Rebuild and start
docker-compose up -d --build
# Stop all services
docker-compose down
# Stop and remove volumes (data loss!)
docker-compose down -v

Verification:

Ventana de terminal
docker-compose ps
# Shows status of all services
docker-compose logs -f
# Follow logs from all services
docker-compose logs -f orders-ms
# Follow logs from specific service

Docker Commands Reference

Container Management

Ventana de terminal
# List running containers
docker ps
# List all containers (including stopped)
docker ps -a
# Start container
docker start algesta-orders-ms
# Stop container
docker stop algesta-orders-ms
# Restart container
docker restart algesta-orders-ms
# Remove container
docker rm algesta-orders-ms
# Remove all stopped containers
docker container prune

Image Management

Ventana de terminal
# List images
docker images
# Remove image
docker rmi algesta-orders-ms:latest
# Remove unused images
docker image prune
# Remove all unused images (including dangling)
docker image prune -a

Logs and Debugging

Ventana de terminal
# View logs
docker logs algesta-orders-ms
# Follow logs (real-time)
docker logs -f algesta-orders-ms
# Last 100 lines
docker logs --tail 100 algesta-orders-ms
# Logs since timestamp
docker logs --since 2025-11-20T10:00:00 algesta-orders-ms
# Execute command in running container
docker exec -it algesta-orders-ms bash
# Inspect container details
docker inspect algesta-orders-ms
# View container resource usage
docker stats algesta-orders-ms

Networking

Ventana de terminal
# List networks
docker network ls
# Inspect network
docker network inspect algesta-network
# Create network
docker network create algesta-network
# Connect container to network
docker network connect algesta-network algesta-orders-ms

Volumes

Ventana de terminal
# List volumes
docker volume ls
# Inspect volume
docker volume inspect algesta-mongo-data
# Remove volume
docker volume rm algesta-mongo-data
# Remove unused volumes
docker volume prune

Verification and Health Checks

1. Check Container Estado

Ventana de terminal
docker-compose ps
# Expected: All services "Up" with healthy status

Sample Output:

NAME STATUS PORTS
algesta-api-gateway Up 2 minutes 0.0.0.0:3000->3000/tcp
algesta-mongodb Up 2 minutes (healthy) 0.0.0.0:27017->27017/tcp
algesta-orders-ms Up 2 minutes 0.0.0.0:3001->3001/tcp
algesta-redis Up 2 minutes (healthy) 0.0.0.0:6379->6379/tcp

2. Health Check Endpoints

Ventana de terminal
# API Gateway
curl http://localhost:3000/health | jq .
# Orders MS
curl http://localhost:3001/health | jq .
# Notifications MS
curl http://localhost:3002/health | jq .
# Provider MS
curl http://localhost:3003/health | jq .

Expected Response:

{
"status": "ok",
"timestamp": "2025-11-20T12:00:00.000Z",
"uptime": 120
}

3. Test Service Communication

Ventana de terminal
# From API Gateway, test routing to Orders MS
curl -X POST http://localhost:3000/orders \
-H "Content-Type: application/json" \
-d '{"service":"Test","address":"Test Address","city":"Bogotá"}'

4. Check Base de datos Connectivity

Ventana de terminal
# Execute MongoDB command in container
docker exec algesta-mongodb mongosh --eval "show dbs"
# Expected: orders_ms, notifications_ms, providers_ms

5. Monitor Container Resources

Ventana de terminal
docker stats
# Shows CPU, memory, network I/O for all containers

Troubleshooting

Issue: Container fails to start with “Cannot connect to Base de datos”

Diagnosis:

Ventana de terminal
docker-compose logs orders-ms
# Look for connection errors

Solutions:

  1. Verify MongoDB is healthy:
    Ventana de terminal
    docker-compose ps mongodb
    # Should show "Up (healthy)"
  2. Check network connectivity:
    Ventana de terminal
    docker exec algesta-orders-ms ping mongodb
  3. Verify environment variables:
    Ventana de terminal
    docker exec algesta-orders-ms printenv | grep MONGODB_URI
  4. Ensure depends_on with health check is configured

Issue: Puppeteer fails with “Failed to launch Chrome”

Diagnosis:

Ventana de terminal
docker exec algesta-orders-ms which chromium
# Should return path to chromium

Solutions:

  1. Verify system dependencies installed in Dockerfile
  2. Check Puppeteer environment variables:
    Ventana de terminal
    docker exec algesta-orders-ms printenv | grep PUPPETEER
  3. Test Chromium manually:
    Ventana de terminal
    docker exec algesta-orders-ms chromium --version
  4. Ensure image rebuilt after Dockerfile changes:
    Ventana de terminal
    docker-compose build --no-cache orders-ms

Issue: bcrypt fails with “Version mismatch”

Cause: bcrypt compiled for wrong Arquitectura (e.g., macOS arm64 vs Linux x86)

Solution: Rebuild bcrypt in Dockerfile final stage:

RUN npm install --force --only=production bcrypt

Verification:

Ventana de terminal
docker exec algesta-orders-ms node -e "require('bcrypt').hash('test', 10, console.log)"
# Should output hash without errors

Issue: Hot reload not working with bind mounts

Solution: Add polling to NestJS in main.ts:

if (module.hot) {
module.hot.accept();
module.hot.dispose(() => app.close());
}

Or use nodemon with polling:

{
"watch": ["src"],
"ext": "ts",
"legacy-watch": true
}

Issue: Port already in use

Diagnosis:

Ventana de terminal
lsof -i :3001
# Shows process using port 3001

Solution:

Ventana de terminal
# Kill process
kill -9 <PID>
# Or change Docker port mapping
docker-compose down
# Edit docker-compose.yml to use different port
# e.g., - "3011:3001"
docker-compose up -d

Related Guías:

For Support:

  • Review Dockerfile comments in each Microservicio
  • Check Docker Compose logs: docker-compose logs -f
  • Validate images with docker inspect <image-name>