Docker para Desarrolladores: Imágenes, Contenedores y Compose

DevOps2026-10-07TryQuickToolBox

Has oído hablar de Docker y los contenedores, pero cuando intentas usarlo, te abruman términos como imágenes, contenedores, volúmenes y Compose. O quizás ya usas Docker pero tus imágenes son enormes, las compilaciones son lentas y gestionar múltiples servicios se siente como una tarea pesada. Esta guía elimina el ruido. Cubriremos lo esencial de Docker para desarrolladores, centrándonos en lo que realmente necesitas saber para construir, ejecutar y gestionar aplicaciones en contenedores de forma eficiente.

¿Por qué Docker? El problema que resuelve

Antes de Docker, desplegar una aplicación significaba igualar el entorno exacto: versiones específicas del SO, bibliotecas y configuraciones. "Funciona en mi máquina" se convirtió en un cliché porque era cierto. Docker lo resuelve empaquetando tu aplicación con sus dependencias en una sola unidad portátil llamada contenedor. Los contenedores son ligeros, aislados y se ejecutan de forma consistente dondequiera que Docker esté instalado.

Imágenes vs. Contenedores: La distinción clave

Una imagen es una plantilla de solo lectura que contiene el código de tu aplicación, el entorno de ejecución, las bibliotecas y la configuración. Un contenedor es una instancia en ejecución de una imagen. Piensa en una imagen como una clase y en un contenedor como un objeto. Puedes ejecutar múltiples contenedores desde la misma imagen, cada uno aislado de los demás.

Cómo se construyen las imágenes

Las imágenes se construyen a partir de un Dockerfile, un archivo de texto con instrucciones. Aquí tienes un ejemplo mínimo para una app Node.js:

FROM node:18-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]

Cada instrucción crea una capa. Las capas se almacenan en caché, así que si solo cambias tu código fuente, Docker reutiliza las capas en caché para las dependencias, haciendo que las reconstrucciones sean rápidas.

Construir y ejecutar

Construye la imagen y ejecuta un contenedor:

docker build -t my-app .
docker run -p 3000:3000 my-app

La bandera -p mapea el puerto 3000 de tu host al puerto 3000 del contenedor.

Buenas prácticas para imágenes Docker eficientes

Las imágenes grandes ralentizan las compilaciones, los pushes y los despliegues. Sigue estas prácticas para mantener las imágenes ligeras:

Aquí tienes un Dockerfile multi-etapa para una aplicación Go:

# Build stage
FROM golang:1.21-alpine AS builder
WORKDIR /src
COPY go.mod go.sum ./
RUN go mod download
COPY . .
RUN CGO_ENABLED=0 go build -o /app/main .

# Final stage
FROM alpine:latest
COPY --from=builder /app/main /main
CMD ["/main"]

La imagen final contiene solo el binario compilado y Alpine, no el toolchain de Go.

Gestionar datos con volúmenes

Los contenedores son efímeros; cuando se eliminan, sus datos se pierden. Los volúmenes persisten los datos fuera del ciclo de vida del contenedor. Úsalos para bases de datos, subidas o cualquier estado que deba sobrevivir a los reinicios.

docker run -v my-data:/var/lib/postgresql/data postgres

Esto crea un volumen con nombre my-data que Docker gestiona. Para desarrollo, también puedes montar tu código fuente en el contenedor para recarga en vivo:

docker run -v $(pwd):/app -p 3000:3000 my-app

Docker Compose: Orquestar múltiples contenedores

Las aplicaciones reales a menudo necesitan múltiples servicios: un servidor web, una base de datos, una caché. Iniciar cada uno con docker run es tedioso y propenso a errores. Docker Compose te permite definir y ejecutar aplicaciones multi-contenedor con un solo archivo YAML.

Un docker-compose.yml práctico

Aquí tienes un archivo Compose para una app Node.js con PostgreSQL y Redis:

version: '3.8'
services:
  web:
    build: .
    ports:
      - "3000:3000"
    environment:
      - DATABASE_URL=postgres://user:pass@db:5432/mydb
      - REDIS_URL=redis://cache:6379
    depends_on:
      - db
      - cache
  db:
    image: postgres:15-alpine
    environment:
      POSTGRES_USER: user
      POSTGRES_PASSWORD: pass
      POSTGRES_DB: mydb
    volumes:
      - postgres_data:/var/lib/postgresql/data
  cache:
    image: redis:7-alpine
volumes:
  postgres_data:

Ejecuta docker compose up para iniciar todos los servicios. Compose crea una red predeterminada para que los contenedores puedan comunicarse entre sí por nombre de servicio (por ejemplo, db, cache).

Comandos comunes de Compose

Cuándo usar Docker Compose vs. Kubernetes

Docker Compose es ideal para desarrollo local, pruebas y despliegues pequeños. Kubernetes destaca en la orquestación de contenedores a través de clústeres para producción a escala. Para muchos desarrolladores, Compose es suficiente para el trabajo diario, y puedes pasar a Kubernetes cuando necesites auto-escalado, auto-reparación y redes avanzadas.

CaracterísticaDocker ComposeKubernetes
Caso de usoDesarrollo local, despliegues pequeñosClústeres de producción
ComplejidadBajaAlta
EscaladoManualAutomático
Curva de aprendizajeSuavePronunciada

Preguntas frecuentes

¿Cuál es la diferencia entre una imagen y un contenedor?

Una imagen es una plantilla de solo lectura con tu app y dependencias. Un contenedor es una instancia en ejecución de una imagen. Puedes ejecutar muchos contenedores desde una imagen.

¿Cómo reduzco el tamaño de una imagen Docker?

Usa imágenes base más pequeñas (como Alpine), compilaciones multi-etapa, combina comandos RUN y usa un archivo .dockerignore para excluir archivos innecesarios.

¿Puedo usar Docker Compose en producción?

Sí, para despliegues a pequeña escala. Para entornos más grandes y dinámicos, Kubernetes o Docker Swarm son más adecuados.

¿Listo para optimizar tu flujo de trabajo con Docker? Echa un vistazo a nuestro Analizador de Logs de Nginx para depurar y monitorizar tus servidores web en contenedores.