DevOps

🐳 Imágenes y contenedores Docker

Docker es una plataforma para crear, enviar y ejecutar aplicaciones en contenedores ligeros y aislados. A diferencia de las máquinas virtuales, los contenedores comparten el kernel del sistema operativo host, lo que los hace rápidos en su inicio y eficientes en el uso de recursos.

Conceptos básicos

  • Imagen: una plantilla en capas de solo lectura creada a partir de un Dockerfile. Las imágenes se almacenan en registros.
  • Contenedor: una instancia en ejecución de una imagen. Los contenedores son efímeros a menos que se utilicen volúmenes.
  • Capa: cada instrucción de Dockerfile crea una capa inmutable. Las capas se almacenan en caché y se comparten entre imágenes.
  • Registro: un repositorio de imágenes (Docker Hub, AWS ECR, GitHub Container Registry).
  • Volumen: un almacén de datos persistente que sobrevive a los reinicios y eliminaciones de contenedores.

Escribir archivos Docker

Un Dockerfile es un archivo de texto con instrucciones que Docker utiliza para crear una imagen. Cada instrucción agrega una nueva capa a la imagen.

Almacenamiento en caché de capas Ordene las instrucciones de menor a mayor frecuencia. Coloque COPY package.json y RUN npm install antes de COPY . . para maximizar la reutilización de la caché.

dockerfile
FROM node:20-alpine AS base
WORKDIR /app

# Install dependencies first (cached until package.json changes)
COPY package.json package-lock.json ./
RUN npm ci --only=production && npm cache clean --force

# Copy source code
COPY src/ ./src/
COPY config/ ./config/

# Create non-root user for security
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
USER appuser

# Runtime configuration
EXPOSE 8080
HEALTHCHECK --interval=30s --timeout=10s --start-period=15s --retries=3 \
  CMD wget -qO- http://localhost:8080/health || exit 1

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

Construcciones de varias etapas

Las compilaciones de varias etapas reducen drásticamente el tamaño de la imagen final mediante el uso de etapas de compilación y tiempo de ejecución separadas. Las herramientas de compilación, los compiladores y las dependencias de prueba permanecen en la etapa de compilación y nunca llegan a producción.

dockerfile
# Stage 1: Build
FROM golang:1.22-alpine AS builder
WORKDIR /build
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 GOOS=linux go build \
  -ldflags="-w -s" \
  -o /app/server ./cmd/server

# Stage 2: Production image (~12MB vs ~350MB)
FROM scratch
COPY --from=builder /app/server /server
COPY --from=builder /etc/ssl/certs/ca-certificates.crt /etc/ssl/certs/
EXPOSE 8080
ENTRYPOINT ["/server"]

Redes

Docker proporciona tres controladores de red integrados:

  • puente — Predeterminado. Red aislada en el host. Los contenedores pueden comunicarse por su nombre.
  • host: el contenedor comparte la pila de red del host. Máximo rendimiento, sin aislamiento.
  • ninguno: sin conexión a red. Se utiliza para trabajos por lotes que no necesitan acceso a la red.
bash
docker network create --driver bridge app-network

# Run containers on the same network (they resolve by name)
docker run -d --name postgres --network app-network postgres:16-alpine
docker run -d --name api --network app-network \
  -e DB_HOST=postgres \
  -p 8080:8080 \
  registry.maxiscomputers.com/api:2.1.0

# Inspect network
docker network inspect app-network

Componente acoplable

Docker Compose define y ejecuta aplicaciones de múltiples contenedores utilizando un archivo YAML. Ideal para desarrollo local y pruebas de integración.

yaml
services:
  api:
    build:
      context: .
      dockerfile: Dockerfile
      target: builder
    ports:
      - "8080:8080"
    environment:
      - NODE_ENV=development
      - DB_URL=postgresql://user:pass@postgres:5432/appdb
      - REDIS_URL=redis://redis:6379
    volumes:
      - ./src:/app/src:ro  # hot reload in dev
    depends_on:
      postgres:
        condition: service_healthy
      redis:
        condition: service_started
    restart: unless-stopped

  postgres:
    image: postgres:16-alpine
    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: pass
      POSTGRES_DB: appdb
    volumes:
      - postgres_data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U user -d appdb"]
      interval: 10s
      timeout: 5s
      retries: 5

  redis:
    image: redis:7-alpine
    command: redis-server --appendonly yes
    volumes:
      - redis_data:/data

volumes:
  postgres_data:
  redis_data:

Seguridad de contenedores

Nunca ejecute como root Cree siempre un usuario no root dedicado en su Dockerfile. Ejecutar como root dentro de un contenedor es un riesgo de seguridad crítico.

  • Utilice imágenes base distroless o Alpine para minimizar la superficie de ataque.
  • Escanee imágenes con docker scout, trivy o grype en su canal de CI.
  • Utilice sistemas de archivos de solo lectura cuando sea posible: bandera --read-only.
  • Nunca conviertas secretos en imágenes. Utilice variables de entorno o montajes secretos.
  • Establezca --cap-drop=ALL y agregue solo las capacidades de Linux requeridas.
  • Habilite Docker Content Trust (DOCKER_CONTENT_TRUST=1) para la verificación de firma de imágenes.

Referencia de la CLI de Docker

bash
docker build -t registry.maxiscomputers.com/api:2.1.0 --platform linux/amd64 .
docker tag registry.maxiscomputers.com/api:2.1.0 registry.maxiscomputers.com/api:latest

# Push & Pull
docker push registry.maxiscomputers.com/api:2.1.0
docker pull registry.maxiscomputers.com/api:2.1.0

# Run
docker run -d --name api -p 8080:8080 --restart unless-stopped \
  -e NODE_ENV=production \
  registry.maxiscomputers.com/api:2.1.0

# Inspect & Debug
docker ps -a
docker logs -f --tail 200 api
docker exec -it api sh
docker inspect api | jq '.[0].NetworkSettings'
docker stats  # live resource usage

# Cleanup
docker system prune -af --volumes   # remove ALL unused resources
docker image prune -f               # remove dangling images only