GL
DevOps 15 de abril de 2025 18 min de lectura Por Gustavo Leyva

Docker para desarrolladores

Guía completa de Docker para desarrollo y producción, con mejores prácticas empresariales y arquitecturas de microservicios.

#Docker #DevOps #Contenedores #Infraestructura #Microservicios
D

¿Qué es Docker?

Docker es una plataforma que permite empaquetar aplicaciones y sus dependencias en contenedores ligeros y portables que pueden ejecutarse en cualquier sistema que tenga Docker instalado. Empresas como Netflix, Uber, Spotify y PayPal utilizan Docker para desplegar miles de microservicios diariamente.

Conceptos básicos

Imágenes

Una imagen es una plantilla de solo lectura que contiene todo lo necesario para ejecutar una aplicación.

# Descargar una imagen
docker pull node:18

# Listar imágenes
docker images

# Eliminar una imagen
docker rmi node:18

# Ver historial de capas de una imagen
docker history node:18

Contenedores

Un contenedor es una instancia en ejecución de una imagen.

# Ejecutar un contenedor
docker run -d -p 3000:3000 --name mi-app node:18

# Listar contenedores en ejecución
docker ps

# Listar todos los contenedores
docker ps -a

# Detener un contenedor
docker stop mi-app

# Eliminar un contenedor
docker rm mi-app

# Ver logs en tiempo real
docker logs -f mi-app

Dockerfile

Un Dockerfile define cómo construir una imagen personalizada.

# Imagen base
FROM node:18-alpine

# Directorio de trabajo
WORKDIR /app

# Copiar archivos de dependencias
COPY package*.json ./

# Instalar dependencias
RUN npm ci --only=production

# Copiar código fuente
COPY . .

# Exponer puerto
EXPOSE 3000

# Comando de inicio
CMD ["node", "server.js"]

Construir imagen

docker build -t mi-aplicacion:1.0 .

Docker Compose para Microservicios

Docker Compose permite definir y ejecutar aplicaciones multi-contenedor, ideal para arquitecturas de microservicios.

version: '3.8'

services:
  app:
    build: .
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=production
      - DB_HOST=db
      - REDIS_HOST=redis
    depends_on:
      - db
      - redis
    volumes:
      - ./src:/app/src
    networks:
      - app-network
    restart: unless-stopped
  
  db:
    image: postgres:15-alpine
    environment:
      - POSTGRES_USER=usuario
      - POSTGRES_PASSWORD=contraseña
      - POSTGRES_DB=midb
    volumes:
      - postgres-data:/var/lib/postgresql/data
    ports:
      - "5432:5432"
    networks:
      - app-network
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U usuario"]
      interval: 10s
      timeout: 5s
      retries: 5
  
  redis:
    image: redis:7-alpine
    ports:
      - "6379:6379"
    networks:
      - app-network
    volumes:
      - redis-data:/data

volumes:
  postgres-data:
  redis-data:

networks:
  app-network:
    driver: bridge

Comandos de Docker Compose

# Iniciar servicios
docker-compose up -d

# Ver logs
docker-compose logs -f

# Ver logs de un servicio específico
docker-compose logs -f app

# Detener servicios
docker-compose down

# Detener y eliminar volúmenes
docker-compose down -v

# Reconstruir imágenes
docker-compose build

# Ejecutar comando en servicio
docker-compose exec app npm test

# Escalar servicios
docker-compose up -d --scale app=3

Mejores prácticas empresariales

1. Usar imágenes oficiales y específicas

# ✅ Bueno: versión específica
FROM node:18-alpine

# ❌ Malo: versión latest
FROM node:latest

2. Multi-stage builds para optimización

Los multi-stage builds reducen el tamaño de la imagen final hasta en un 90%, como lo implementa Google en sus contenedores.

# Stage 1: Build
FROM node:18 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build

# Stage 2: Production
FROM node:18-alpine
WORKDIR /app

# Copiar solo lo necesario
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY package*.json ./

# Usuario no-root para seguridad
RUN addgroup -g 1001 -S nodejs && \
    adduser -S nodejs -u 1001 && \
    chown -R nodejs:nodejs /app

USER nodejs

EXPOSE 3000
CMD ["node", "dist/server.js"]

3. Seguridad: Usuario no-root

Ejecutar contenedores como root es un riesgo de seguridad. Empresas como Amazon y Microsoft requieren contenedores no-root en producción.

# Crear usuario
RUN addgroup -g 1001 -S nodejs && \
    adduser -S nodejs -u 1001

# Cambiar permisos
RUN chown -R nodejs:nodejs /app

# Cambiar a usuario
USER nodejs

4. Minimizar capas y tamaño de imagen

# ✅ Bueno: combinar comandos
RUN apt-get update && \
    apt-get install -y curl && \
    apt-get clean && \
    rm -rf /var/lib/apt/lists/*

# ❌ Malo: múltiples RUN
RUN apt-get update
RUN apt-get install -y curl
RUN apt-get clean

5. Usar .dockerignore

node_modules
npm-debug.log
.git
.env
.env.local
*.md
.DS_Store
coverage/
.vscode/
.idea/
dist/
build/

6. Gestión de secretos

Nunca incluyas secretos en la imagen. Usa variables de entorno o servicios de gestión de secretos.

# ❌ NUNCA hagas esto
ENV DATABASE_PASSWORD=mi-password-secreto

# ✅ Usa variables de entorno en runtime
# docker run -e DATABASE_PASSWORD=$DB_PASS mi-app

Docker en producción

Health checks

HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
  CMD node healthcheck.js

Límites de recursos

services:
  app:
    deploy:
      resources:
        limits:
          cpus: '0.5'
          memory: 512M
        reservations:
          cpus: '0.25'
          memory: 256M

Logging y monitoreo

# Configurar driver de logging
docker run --log-driver=json-file \
  --log-opt max-size=10m \
  --log-opt max-file=3 \
  mi-app

# Ver estadísticas en tiempo real
docker stats

# Inspeccionar contenedor
docker inspect mi-app

Debugging

# Ejecutar shell en contenedor
docker exec -it mi-app /bin/sh

# Ver logs con timestamps
docker logs -f --timestamps mi-app

# Inspeccionar contenedor
docker inspect mi-app

# Ver uso de recursos
docker stats

# Ver procesos en contenedor
docker top mi-app

# Copiar archivos desde/hacia contenedor
docker cp mi-app:/app/logs ./logs

Arquitectura de microservicios con Docker

Empresas como Netflix ejecutan más de 700 microservicios en contenedores Docker. Aquí un ejemplo de arquitectura:

version: '3.8'

services:
  # API Gateway
  gateway:
    image: nginx:alpine
    ports:
      - "80:80"
    volumes:
      - ./nginx.conf:/etc/nginx/nginx.conf
    depends_on:
      - auth-service
      - user-service
      - order-service
  
  # Servicio de autenticación
  auth-service:
    build: ./services/auth
    environment:
      - JWT_SECRET=${JWT_SECRET}
    depends_on:
      - redis
  
  # Servicio de usuarios
  user-service:
    build: ./services/users
    depends_on:
      - postgres
  
  # Servicio de pedidos
  order-service:
    build: ./services/orders
    depends_on:
      - postgres
      - rabbitmq
  
  # Message broker
  rabbitmq:
    image: rabbitmq:3-management-alpine
    ports:
      - "5672:5672"
      - "15672:15672"
  
  # Cache
  redis:
    image: redis:7-alpine
  
  # Base de datos
  postgres:
    image: postgres:15-alpine
    volumes:
      - pg-data:/var/lib/postgresql/data

volumes:
  pg-data:

Conclusión

Docker ha revolucionado el desarrollo y despliegue de aplicaciones modernas. Con estas mejores prácticas empresariales, puedes:

  • Reducir el tamaño de imágenes hasta 90% con multi-stage builds
  • Mejorar la seguridad ejecutando contenedores como usuarios no-root
  • Escalar aplicaciones fácilmente con Docker Compose
  • Implementar microservicios como lo hacen Netflix, Uber y Spotify

Docker no es solo una herramienta de desarrollo; es la base de la infraestructura moderna en la nube.

GL

Gustavo Leyva

Desarrollador de Software

← Volver al blog