¿Qué problema resuelve Docker?
Si alguna vez oíste "en mi máquina funciona" sabes exactamente el problema. Una aplicación depende de versiones específicas de librerías, configuraciones del sistema operativo y variables de entorno. Reproducir ese entorno en otro servidor era un trabajo tedioso y propenso a errores.
Docker empaqueta la aplicación junto con todo lo que necesita en un contenedor: unidad aislada, ligera y reproducible que funciona igual en cualquier máquina que tenga Docker instalado.
Conceptos básicos
- Imagen: plantilla de solo lectura con el sistema de archivos y configuración. Piénsala como una "foto" del entorno
- Contenedor: instancia en ejecución de una imagen. Puedes tener varios contenedores de la misma imagen
- Dockerfile: archivo de texto que define cómo construir una imagen
- Docker Hub: registro público de imágenes. Como npm o PyPI pero para contenedores
- Volumen: almacenamiento persistente que sobrevive a la destrucción del contenedor
Comandos esenciales
# Descargar y ejecutar una imagen
docker run nginx
docker run -d -p 8080:80 --name mi-nginx nginx
# -d: en segundo plano, -p: mapear puerto host:contenedor
# Gestionar contenedores
docker ps # Contenedores en ejecución
docker ps -a # Todos (incluidos parados)
docker stop mi-nginx
docker start mi-nginx
docker rm mi-nginx # Eliminar contenedor
# Ver logs
docker logs mi-nginx
docker logs -f mi-nginx # Seguir en tiempo real
# Entrar en un contenedor
docker exec -it mi-nginx bash
# Gestionar imágenes
docker images
docker pull ubuntu:22.04
docker rmi ubuntu:22.04
# Limpiar todo lo que no se usa
docker system prune -a
Dockerfile: construir tu propia imagen
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY . .
EXPOSE 3000
CMD ["node", "server.js"]
# Construir y ejecutar
docker build -t mi-app:1.0 .
docker run -d -p 3000:3000 mi-app:1.0
Buenas prácticas en el Dockerfile:
- Usa imágenes base
alpine(más pequeñas y seguras) - Pon
COPY package.jsonantes del código para aprovechar la caché de capas - No ejecutes como root — añade un usuario sin privilegios
- Usa
.dockerignorepara excluirnode_modules,.git, etc.
Docker Compose: orquestar múltiples servicios
La mayoría de aplicaciones necesitan varios servicios: web, base de datos, caché... Docker Compose los define en un archivo compose.yml:
services:
web:
build: .
ports:
- "3000:3000"
environment:
- DATABASE_URL=postgres://user:pass@db:5432/miapp
depends_on:
- db
db:
image: postgres:16-alpine
volumes:
- postgres_data:/var/lib/postgresql/data
environment:
- POSTGRES_USER=user
- POSTGRES_PASSWORD=pass
- POSTGRES_DB=miapp
volumes:
postgres_data:
docker compose up -d # Arrancar todo
docker compose down # Parar y eliminar
docker compose logs -f # Ver logs de todos los servicios
docker compose ps # Estado de todos los servicios
Seguridad básica en Docker
- No uses la imagen
latesten producción. Especifica versiones - Escanea imágenes con
docker scouto Trivy antes de usarlas - No montes el socket de Docker (
/var/run/docker.sock) en contenedores sin necesidad absoluta - Lee-only filesystem cuando el contenedor no necesita escribir:
--read-only - Limita recursos:
--memory="512m" --cpus="0.5"
Casos de uso que más uso
En mi homelab uso Docker Compose para casi todo:
- Nextcloud (almacenamiento personal)
- Portainer (interfaz web para gestionar Docker)
- Nginx Proxy Manager (reverse proxy con SSL automático)
- Vaultwarden (Bitwarden self-hosted)
- Grafana + Prometheus (monitorización)
Docker convirtió lo que antes requería horas de configuración en un docker compose up de 2 minutos.