En el ecosistema actual del desarrollo de software, la capacidad de crear, probar y desplegar aplicaciones de forma consistente y aislada es una competencia esencial. Los contenedores Docker han emergido como la herramienta de referencia para lograrlo, permitiendo que tu código y todas sus dependencias se empaqueten en una unidad reproducible que funciona en cualquier entorno que soporte Docker.
¿Qué es Docker y por qué deberías importarte?
Docker es una plataforma de código abierto que facilita la creación, distribución y ejecución de contenedores. Un contenedor es una instancia ligera y aislada de una aplicación que comparte el kernel del sistema operativo host, pero mantiene su propio sistema de archivos, red y procesos. Las principales ventajas son:
- Portabilidad: lo que funciona en tu laptop funciona en producción.
- Consistencia: elimina el clásico “funciona en mi máquina”.
- Eficiencia: los contenedores son mucho más ligeros que las máquinas virtuales.
- Escalabilidad: se integran perfectamente con orquestadores como Kubernetes.
Conceptos básicos que necesitas dominar
Imagen vs Contenedor
Una imagen es una plantilla inmutable que describe cómo debe construirse un contenedor (sistema de archivos, variables de entorno, puertos expuestos, etc.). Cuando Docker ejecuta una imagen, crea un contenedor, que es una instancia en ejecución de esa imagen.
Dockerfile
El Dockerfile es un archivo de texto con una serie de instrucciones que Docker interpreta para construir una imagen. Cada instrucción crea una capa intermedia que se almacena en caché, lo que acelera reconstrucciones posteriores.
Registro (Registry)
Un registro es un repositorio donde se almacenan y comparten imágenes. Docker Hub es el registro público por defecto, pero puedes usar registros privados como GitHub Container Registry o Harbor.
Instalación y primer contacto
- Descargar Docker Desktop (Windows/macOS) o instalar Docker Engine en Linux siguiendo la documentación oficial.
- Verificar la instalación con
docker --versionydocker run hello-world. - Configurar tu entorno (variables de entorno, permisos de usuario en Linux, etc.).
Construyendo tu primera imagen
Supongamos que queremos crear una aplicación Node.js sencilla. A continuación, se muestra un Dockerfile paso a paso:
# Usa una imagen oficial de Node.js como base
FROM node:20-alpine
# Establece el directorio de trabajo dentro del contenedor
WORKDIR /app
# Copia el package.json y package-lock.json
COPY package*.json ./
# Instala dependencias
RUN npm ci --only=production
# Copia el resto del código fuente
COPY . .
# Expone el puerto en el que escuchará la aplicación
EXPOSE 3000
# Define el comando por defecto al iniciar el contenedor
CMD ["node", "index.js"]
Para construir la imagen, ejecuta:
docker build -t mi-app-node:1.0 .Y para correrla:
docker run -p 3000:3000 mi-app-node:1.0Gestión de contenedores en la práctica
Comandos esenciales
docker ps– Lista los contenedores en ejecución.docker ps -a– Lista todos los contenedores, incluidos los detenidos.docker stop <container_id>– Detiene un contenedor.docker rm <container_id>– Elimina un contenedor.docker rmi <image_id>– Elimina una imagen.docker logs <container_id>– Muestra los logs del contenedor.docker exec -it <container_id> sh– Abre una shell interactiva dentro del contenedor.
Volúmenes y persistencia de datos
Los contenedores son efímeros; al destruirlos, todo lo que esté dentro del sistema de archivos se pierde. Para datos persistentes, usa volúmenes:
# Creación de un volumen
docker volume create db-data
# Montaje del volumen al iniciar un contenedor PostgreSQL
docker run -d \
-e POSTGRES_PASSWORD=secret \
-v db-data:/var/lib/postgresql/data \
-p 5432:5432 \
postgres:15
Redes en Docker
Docker crea una red predeterminada (bridge) para los contenedores. En entornos más complejos, puedes definir redes personalizadas:
# Crear una red llamada "backend"
docker network create backend
# Ejecutar dos contenedores y conectarlos a la red
docker run -d --name api --network backend my-api-image
docker run -d --name db --network backend my-db-image
Con la red personalizada, los contenedores pueden comunicarse entre sí usando sus nombres de host (api y db).
Buenas prácticas para proyectos reales
- Mantén los Dockerfiles lo más pequeños posible. Usa imágenes base minimalistas como
alpineodistroless. - Ordena las capas eficientemente. Copia primero los archivos que cambian menos (por ejemplo,
package.json) para aprovechar la caché. - No almacenes secretos en la imagen. Usa variables de entorno en tiempo de ejecución o herramientas como Docker Secrets.
- Especifica versiones exactas. Evita usar
latesten producción; fija versiones de imágenes y dependencias. - Utiliza archivos .dockerignore. Excluye archivos innecesarios (node_modules, .git, etc.) para reducir el contexto de construcción.
Integración con CI/CD
La mayoría de los pipelines modernos incluyen etapas de construcción y publicación de imágenes Docker. Un ejemplo básico con GitHub Actions:
name: Build & Push Docker Image
on:
push:
branches: [ main ]
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout code
uses: actions/checkout@v3
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v2
- name: Login to Docker Hub
uses: docker/login-action@v2
with:
username: ${{ secrets.DOCKERHUB_USER }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v4
with:
context: .
push: true
tags: myuser/mi-app:latest
Orquestación con Docker Compose
Para aplicaciones compuestas de varios contenedores (API, base de datos, cache), Docker Compose simplifica la definición y ejecución:
services:
api:
build: ./api
ports:
- "8080:8080"
environment:
- DATABASE_URL=postgres://user:pass@db:5432/appdb
depends_on:
- db
db:
image: postgres:15
volumes:
- db-data:/var/lib/postgresql/data
environment:
- POSTGRES_USER=user
- POSTGRES_PASSWORD=pass
- POSTGRES_DB=appdb
volumes:
db-data:
Ejecuta todo el stack con docker compose up -d y detén con docker compose down.
Depuración y monitoreo
- Logs:
docker logs -f <container_id>para seguir la salida en tiempo real. - Inspección:
docker inspect <container_id>muestra la configuración completa. - Herramientas externas: Prometheus + Grafana, cAdvisor o Elastic Stack para métricas y trazas.
Casos de uso típicos
- Entornos de desarrollo reproducibles. Cada desarrollador levanta la misma pila con
docker compose up. - Microservicios. Cada microservicio se empaqueta como un contenedor independiente.
- CI/CD pipelines. Construcción automática de imágenes y despliegues a entornos de staging/producción.
- Ejecutar herramientas de línea de comandos. Utiliza contenedores como entornos temporales para pruebas o análisis.
Próximos pasos para llevar tu dominio al siguiente nivel
- Aprende Kubernetes. Docker te brinda los contenedores; Kubernetes te ofrece la orquestación a gran escala.
- Explora Docker Swarm. Si buscas una solución más ligera que Kubernetes, Swarm sigue siendo viable.
- Implementa seguridad en contenedores. Usa escáneres de vulnerabilidades (Trivy, Clair) y políticas de firma de imágenes.
- Adopta el enfoque “GitOps”. Gestiona la infraestructura de contenedores mediante código versionado.
Conclusión
Dominar Docker es un paso fundamental para cualquier desarrollador que aspire a trabajar con arquitecturas modernas, microservicios y despliegues continuos. Desde la creación de una simple imagen hasta la orquestación completa con Docker Compose o Kubernetes, los conceptos presentados aquí forman la base para que puedas experimentar, iterar y, sobre todo, entregar software de alta calidad con mayor velocidad y consistencia.
¡Ahora es tu turno! Crea tu primer Dockerfile, ejecuta docker compose up y siente la diferencia que supone trabajar con contenedores. Cada proyecto será más predecible, cada despliegue más fiable y, lo más importante, cada equipo podrá colaborar sin los típicos problemas de “funciona en mi máquina”.




