DataSkills Hub

Docker

Docker es la plataforma de contenedores para empaquetar, distribuir y ejecutar aplicaciones. Servicios como Airflow, Trino, NiFi y Superset corren como contenedores Docker orquestados por Kubernetes.

#Getting Started

#Verificar instalación

$ docker --version
$ docker info
$ docker compose version

#Ejecutar un contenedor

Crear y correr en background (modo detached)

$ docker run -d -p <puerto-host>:<puerto-contenedor> --name mi-nginx nginx:alpine

  • -d - Modo detached (background)
  • -p <puerto-host>:<puerto-contenedor> - Mapear puerto del host al del contenedor
  • --name mi-nginx - Asignar nombre al contenedor
  • nginx:alpine - Imagen a utilizar

Correr en modo interactivo

$ docker run -it --rm ubuntu:22.04 bash

  • -it - Modo interactivo con terminal
  • --rm - Eliminar contenedor al salir

#Comandos esenciales

Comando Descripción
docker ps Listar contenedores en ejecución
docker ps -a Listar todos los contenedores
docker images Listar imágenes locales
docker logs <contenedor> Ver logs del contenedor
docker logs -f <contenedor> Seguir logs en tiempo real
docker exec -it <contenedor> bash Abrir shell dentro del contenedor
docker inspect <contenedor> Ver configuración detallada (JSON)
docker stats Monitorear recursos (CPU, RAM, I/O)

El parámetro <contenedor> puede ser el ID o el nombre

#Ciclo de vida de un contenedor

# Crear sin iniciar
$ docker create --name mi-app mi-imagen:latest

# Iniciar
$ docker start mi-app

# Pausar / reanudar
$ docker pause mi-app
$ docker unpause mi-app

# Detener (graceful)
$ docker stop mi-app

# Forzar detención
$ docker kill mi-app

# Reiniciar
$ docker restart mi-app

# Eliminar (debe estar detenido)
$ docker rm mi-app

# Eliminar forzado (incluso corriendo)
$ docker rm -f mi-app

#Contenedores

#Crear contenedores con opciones

$ docker run -d \
    --name airflow-worker \
    -p <puerto>:<puerto> \
    -e AIRFLOW__CORE__EXECUTOR=CeleryExecutor \
    -e AIRFLOW__DATABASE__SQL_ALCHEMY_CONN=postgresql+psycopg2://... \
    -v /opt/airflow/dags:/opt/airflow/dags \
    -v /opt/airflow/logs:/opt/airflow/logs \
    --network data-net \
    --restart unless-stopped \
    apache/airflow:2.8.1

  • -e - Variables de entorno
  • -v - Montar volumen (host:contenedor)
  • --network - Conectar a red específica
  • --restart - Política de reinicio automático

#Políticas de reinicio

Política Comportamiento
no No reiniciar nunca (default)
on-failure Reiniciar solo si falla (exit code != 0)
on-failure:5 Reiniciar máximo 5 veces si falla
unless-stopped Reiniciar siempre excepto si se detuvo manual
always Reiniciar siempre sin importar el exit code

#Copiar archivos

# Del host al contenedor
$ docker cp config.yaml mi-app:/app/config.yaml

# Del contenedor al host
$ docker cp mi-app:/app/logs/output.log ./output.log

#Inspeccionar contenedores

# Ver IP del contenedor
$ docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' mi-app

# Ver puertos mapeados
$ docker port mi-app

# Ver procesos internos
$ docker top mi-app

# Ver cambios en el filesystem
$ docker diff mi-app

# Ver uso de recursos
$ docker stats mi-app --no-stream

#Logs avanzados

# Últimas 100 líneas
$ docker logs --tail 100 mi-app

# Logs desde hace 30 minutos
$ docker logs --since 30m mi-app

# Logs con timestamps
$ docker logs -t mi-app

# Combinar opciones
$ docker logs -f --tail 50 --since 1h mi-app

#Imágenes

#Gestión de imágenes

Comando Descripción
docker images Listar imágenes locales
docker images -a Listar todas (incluye intermedias)
docker pull nginx:alpine Descargar imagen del registry
docker push <tu-url>/mi-img:v1 Subir imagen al registry
docker tag mi-img:latest mi-img:v1.0 Etiquetar imagen
docker rmi nginx:alpine Eliminar imagen
docker image prune Eliminar imágenes sin usar
docker image prune -a Eliminar TODAS las no usadas
docker history mi-img:latest Ver historial de capas
docker save mi-img > mi-img.tar Exportar imagen a archivo tar
docker load < mi-img.tar Importar imagen desde tar

#Construir imágenes

# Build básico
$ docker build -t mi-app:latest .

# Build con Dockerfile específico
$ docker build -f Dockerfile.prod -t mi-app:prod .

# Build con argumentos
$ docker build --build-arg ENV=production -t mi-app:prod .

# Build sin cache
$ docker build --no-cache -t mi-app:latest .

# Build multi-plataforma
$ docker buildx build --platform linux/amd64,linux/arm64 -t mi-app:latest .

#Dockerfile ejemplo (Python)

FROM python:3.11-slim AS base

# Dependencias del sistema
RUN apt-get update && apt-get install -y --no-install-recommends \
    gcc libpq-dev curl \
    && rm -rf /var/lib/apt/lists/*

# Crear usuario no-root
RUN useradd -m -s /bin/bash appuser

WORKDIR /app

# Instalar dependencias Python
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# Copiar código
COPY --chown=appuser:appuser . .

USER appuser

EXPOSE <puerto>

HEALTHCHECK --interval=30s --timeout=10s --retries=3 \
    CMD curl -f http://<host>:<puerto>/health || exit 1

CMD ["python", "-m", "uvicorn", "main:app", "--host", "<bind-address>", "--port", "<puerto>"]

#Buenas prácticas para Dockerfiles

  • Usar imágenes base slim/alpine para reducir tamaño
  • Multi-stage builds para separar build de runtime
  • Copiar requirements.txt antes del código (cache de capas)
  • Nunca correr como root en producción (USER appuser)
  • Incluir HEALTHCHECK para orquestadores
  • Usar .dockerignore para excluir archivos innecesarios

#Volúmenes y Redes

#Volúmenes

# Crear volumen
$ docker volume create datos-trino

# Listar volúmenes
$ docker volume ls

# Inspeccionar volumen
$ docker volume inspect datos-trino

# Eliminar volumen
$ docker volume rm datos-trino

# Eliminar volúmenes huérfanos
$ docker volume prune

#Tipos de montaje

# Volumen nombrado (recomendado para datos persistentes)
$ docker run -d -v datos-trino:/data trino:latest

# Bind mount (archivos del host)
$ docker run -d -v /opt/configs/trino:/etc/trino trino:latest

# Montaje de solo lectura
$ docker run -d -v /opt/configs:/config:ro mi-app:latest

# tmpfs (solo en memoria, no persiste)
$ docker run -d --tmpfs /tmp:rw,size=256m mi-app:latest

#Redes

# Crear red
$ docker network create data-net

# Crear red con subnet específica
$ docker network create --driver bridge \
    --subnet=<subnet-cidr> \
    data-net

# Listar redes
$ docker network ls

# Inspeccionar red
$ docker network inspect data-net

# Conectar contenedor a red existente
$ docker network connect data-net mi-app

# Desconectar contenedor de red
$ docker network disconnect data-net mi-app

# Eliminar red
$ docker network rm data-net

# Limpiar redes sin usar
$ docker network prune

#Tipos de red

Driver Uso
bridge Red por defecto, contenedores en el mismo host
host Comparte la red del host directamente
overlay Comunicación entre nodos en Swarm/Kubernetes
none Sin red, contenedor aislado
macvlan Asigna MAC address propia al contenedor

#Docker Compose

#Comandos principales

Comando Descripción
docker compose up -d Levantar todos los servicios
docker compose up -d --build Levantar y reconstruir imágenes
docker compose down Detener y eliminar contenedores
docker compose down -v Detener y eliminar contenedores + vol.
docker compose ps Listar servicios del compose
docker compose logs -f Seguir logs de todos los servicios
docker compose logs -f airflow Logs de un servicio específico
docker compose exec airflow bash Shell en servicio corriendo
docker compose pull Descargar imágenes actualizadas
docker compose restart airflow Reiniciar un servicio
docker compose config Validar y ver config resultante

#docker-compose.yml ejemplo

version: '3.8'

services:
  trino:
    image: trinodb/trino:438
    container_name: trino
    ports:
      - '<puerto>:<puerto>'
    volumes:
      - ./config/trino:/etc/trino
      - trino-data:/data/trino
    environment:
      - JAVA_OPTS=-Xmx4g
    networks:
      - data-net
    restart: unless-stopped
    healthcheck:
      test: ['CMD', 'curl', '-f', 'http://<host>:<puerto>/v1/info']
      interval: 30s
      timeout: 10s
      retries: 5

  superset:
    image: apache/superset:3.1.0
    container_name: superset
    ports:
      - '<puerto>:<puerto>'
    environment:
      - SUPERSET_SECRET_KEY=${SUPERSET_SECRET_KEY}
    volumes:
      - superset-data:/app/superset_home
    networks:
      - data-net
    depends_on:
      trino:
        condition: service_healthy
    restart: unless-stopped

volumes:
  trino-data:
  superset-data:

networks:
  data-net:
    driver: bridge

#Variables de entorno en Compose

# Opción 1: archivo .env (recomendado)
# docker-compose.yml
services:
  app:
    env_file:
      - .env
      - .env.local

# Opción 2: inline
services:
  app:
    environment:
      - DB_HOST=postgres
      - DB_PORT=<puerto>

# Opción 3: interpolación desde .env
services:
  app:
    environment:
      - DB_PASSWORD=${DB_PASSWORD}

#Escalar servicios

# Escalar workers de Airflow
$ docker compose up -d --scale airflow-worker=3

# Ver estado de réplicas
$ docker compose ps

#Patrones comunes

#Limpieza de recursos

# Limpieza segura (solo recursos huérfanos)
$ docker system prune

# Limpieza agresiva (incluye imágenes sin usar)
$ docker system prune -a

# Ver espacio usado por Docker
$ docker system df

# Limpieza selectiva
$ docker container prune   # Contenedores detenidos
$ docker image prune -a    # Imágenes sin contenedor
$ docker volume prune      # Volúmenes huérfanos
$ docker network prune     # Redes sin usar

#Troubleshooting servicios

# Ver logs de un servicio específico
$ docker logs trino --tail 200 -f

# Inspeccionar estado de salud
$ docker inspect --format='{{.State.Health.Status}}' trino

# Ver variables de entorno del contenedor
$ docker exec trino env | sort

# Verificar conectividad entre contenedores
$ docker exec superset ping trino

# Verificar resolución DNS interna
$ docker exec superset nslookup trino

# Monitorear recursos de todo el stack
$ docker stats --format "table {{.Name}}\t{{.CPUPerc}}\t{{.MemUsage}}"

#Registry privado

# Login al registry corporativo
$ docker login <tu-url>

# Etiquetar para registry privado
$ docker tag mi-app:latest <tu-url>/data-team/mi-app:v1.0

# Push al registry privado
$ docker push <tu-url>/data-team/mi-app:v1.0

# Pull desde registry privado
$ docker pull <tu-url>/data-team/mi-app:v1.0

#Convenciones de nombres

Recurso Convención Ejemplo
Contenedor <servicio> trino, superset
Imagen data-team/<app>:<version> data-team/etl-runner:v2.1
Volumen <servicio>-data trino-data, superset-data
Red <propósito>-net data-net, monitor-net
Compose file docker-compose.yml Raíz del proyecto

#Backups de volúmenes

# Backup de un volumen a tar
$ docker run --rm \
    -v trino-data:/source:ro \
    -v $(pwd):/backup \
    alpine tar czf /backup/trino-data-backup.tar.gz -C /source .

# Restaurar volumen desde tar
$ docker run --rm \
    -v trino-data:/target \
    -v $(pwd):/backup \
    alpine tar xzf /backup/trino-data-backup.tar.gz -C /target

#Servicios comunes del stack de datos

Servicio Imagen Puerto Función
Airflow apache/airflow:2.8.x <puerto> Orquestación de pipelines
Trino trinodb/trino:438 <puerto> Motor de consultas SQL
NiFi apache/nifi:1.25.x <puerto> Ingesta y flujos de datos
Superset apache/superset:3.1.x <puerto> Visualización y dashboards
MinIO minio/minio:latest <puerto> Almacenamiento S3-compatible
PostgreSQL postgres:15 <puerto> Metastore y catálogos

#Also see