Fundamentos de Docker
Cómo containerizar una aplicación, escribir un Dockerfile y ejecutar contenedores con Docker Compose.
Overview
Docker empaqueta tu aplicación y sus dependencias en un contenedor ligero y portable que se ejecuta consistentemente en desarrollo, staging y producción. Un Dockerfile es una receta para construir esa imagen de contenedor, y Docker Compose te permite ejecutar configuraciones multi-contenedor con un solo comando.
Lo siguiente cubre las instrucciones esenciales del Dockerfile, el layering de imágenes y un ejemplo práctico de Docker Compose para una aplicación web con base de datos.
When to Use
Usa esta receta cuando:
- Quieras eliminar problemas de “funciona en mi máquina”. Consulta Environment Variables para gestionar configuración de contenedores.
- Configures un entorno de desarrollo local que refleje producción. Consulta Docker Compose Local Dev para entornos multi-servicio.
- Prepares una aplicación para deployment en Kubernetes, AWS ECS o plataformas similares. Consulta Serverless Functions para despliegues function-as-a-service.
- Ejecutes pruebas de integración que dependan de bases de datos, caches o brokers de mensajes. Consulta Integration Testing para estrategias de aislamiento de tests.
Solution
Dockerfile para una App Node.js
# syntax=docker/dockerfile:1
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
FROM node:20-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/package*.json ./
RUN npm ci --omit=dev
EXPOSE 3000
USER node
CMD ["node", "dist/main.js"]
Dockerfile para una App Python
# syntax=docker/dockerfile:1
FROM python:3.12-slim
WORKDIR /app
ENV PYTHONDONTWRITEBYTECODE=1
ENV PYTHONUNBUFFERED=1
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
EXPOSE 8000
CMD ["python", "-m", "uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"]
Docker Compose (Web + Base de Datos)
version: "3.9"
services:
app:
build: .
ports:
- "3000:3000"
environment:
- DATABASE_URL=postgres://user:pass@db:5432/mydb
depends_on:
- db
db:
image: postgres:16-alpine
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: pass
POSTGRES_DB: mydb
volumes:
- pgdata:/var/lib/postgresql/data
ports:
- "5432:5432"
volumes:
pgdata:
Ejecutar: docker compose up --build
Explanation
- Builds multi-etapa (
AS builder,AS runner) mantienen las imágenes de producción pequeñas al excluir herramientas de build, source maps y dependencias de desarrollo. - Caché de capas: Docker cachea cada capa de instrucciones. Coloca
COPY package*.jsonyRUN npm ciantes deCOPY . .para que la instalación de dependencias se cachee a menos que los archivos de paquete cambien. - Usuario no-root:
USER node(o un usuario personalizado) reduce la superficie de ataque si el contenedor es comprometido. .dockerignore: créalo para excluirnode_modules,.gity archivos de entorno local — inflan el contexto de build y pueden filtrar secretos.
Variants
| Objetivo | Enfoque |
|---|---|
| Imagen más pequeña | Usar imágenes base alpine o distroless |
| Build más rápido | Ordenar instrucciones del Dockerfile de menos a más frecuentemente cambiadas |
| Inyección de secretos | Usar secretos de BuildKit (--secret) o variables de entorno en runtime, nunca COPY de secretos |
| Health checks | Agregar instrucción HEALTHCHECK o bloque healthcheck de Docker Compose |
Lo que funciona
- Fija tags de imágenes base:
node:20-alpinees mejor quenode:latestpara evitar cambios breaking inesperados. - Un proceso por contenedor: deja que Docker gestione el ciclo de vida del proceso; usa Compose u un orquestador para setups multi-proceso.
- Usa mounts de volumen para desarrollo: monta el código fuente en el contenedor para hot-reload durante desarrollo.
- Escanea imágenes: ejecuta
docker scano Trivy para detectar vulnerabilidades del SO y dependencias en tus imágenes. - Apagado graceful: maneja
SIGTERMen tu aplicación para que Docker pueda detener contenedores limpiamente.
Common Mistakes
- Imágenes gigantes: copiar archivos innecesarios (logs, datos de prueba,
.git) infla el tamaño de imagen y tiempo de build. - Ejecutar como root: los usuarios por defecto en imágenes base suelen ser root. Crea y cambia a un usuario no-root.
- Secretos hardcodeados: incrustar contraseñas de base de datos en la imagen las hace visibles para cualquiera que la descargue.
- Ignorar
.dockerignore: sin él,COPY . .envía todo tu repo — incluyendo archivos sensibles — al daemon de Docker. - No manejar señales: aplicaciones que ignoran
SIGTERMson matadas conSIGKILLdespués de un timeout, arriesgando corrupción de datos.
Tips de Rendimiento
- Usa BuildKit para builds más rápidos. Habilítalo con
DOCKER_BUILDKIT=1odocker buildx:
$ DOCKER_BUILDKIT=1 docker build -t myapp:latest .
- Ordena las capas del Dockerfile de menos a más cambiante. Las dependencias cambian raramente; el código fuente cambia seguido:
# Bien: deps primero, código al final
COPY package*.json ./
RUN npm ci
COPY . .
- Usa
--targetpara builds parciales. Construye solo la etapa que necesitas:
$ docker build --target builder -t myapp:builder .
- Usa
docker compose up --builden dev. Reconstruye solo las capas cambiadas:
$ docker compose up --build --watch # Rebuild on file changes (Compose v2.22+)
- Usa
docker saveydocker loadpara transferencia offline. Mueve imágenes entre máquinas sin registry:
$ docker save myapp:latest | gzip > myapp.tar.gz
$ docker load < myapp.tar.gz Preguntas frecuentes
¿Cuál es la diferencia entre una imagen Docker y un contenedor?
Una imagen es una plantilla de solo lectura con tu código y dependencias. Un contenedor es una instancia en ejecución de esa imagen. Puedes ejecutar muchos contenedores de la misma imagen.
¿Debería usar Docker Compose en producción?
Docker Compose es excelente para deployments de producción de un solo host y desarrollo local. Para cargas de producción multi-host y alta disponibilidad, usa Kubernetes o un servicio de contenedores gestionado.
¿Cómo reduzco el tamaño de mi imagen Docker?
Usa builds multi-etapa, imágenes base alpine o distroless, y asegúrate de que tu .dockerignore excluya artefactos de build y caches de dependencias.
Recursos Relacionados
Aislamiento de Red Docker y Seguridad Entre Contenedores
Asegura la comunicación entre contenedores con redes Docker personalizadas, segmentación de red y políticas de control de acceso.
RecipeInfraestructura Inmutable
Construye infraestructura inmutable con imágenes de máquina versionadas y containers para eliminar configuration drift y asegurar despliegues reproducibles.
RecipeVariables de Entorno
Cómo leer, establecer y gestionar variables de entorno de forma segura en Python, JavaScript y Java.
RecipeGitHub Actions: CI/CD
Cómo construir y desplegar con GitHub Actions usando workflows, matrices, caching y secrets.
RecipePlaybook de Ansible para Configuración de Servidores
Cómo escribir y ejecutar playbooks de Ansible para provisionar, configurar y gestionar servidores con tareas idempotentes, roles y archivos de inventario.
RecipeConfigurar Certificados SSL con Let's Encrypt
Cómo obtener, instalar y renovar automáticamente certificados SSL usando Certbot con Nginx, Apache y modos standalone para despliegues con HTTPS.