¿Por qué Docker?
Docker revolucionó la forma en que desarrollamos y desplegamos aplicaciones. Con contenedores, puedes:
- 🚀 Garantizar consistencia entre entornos
- 📦 Empaquetar dependencias junto con tu app
- 🔄 Escalar horizontalmente con facilidad
- ⚡ Acelerar el ciclo de desarrollo
Conceptos Fundamentales
Imágenes vs Contenedores
1
2
3
4
| +----------------+ docker run +----------------+
| IMAGEN | ----------------> | CONTENEDOR |
| (Blueprint) | | (Instancia) |
+----------------+ +----------------+
|
- Imagen: Template inmutable con el SO y tu aplicación
- Contenedor: Instancia ejecutable de una imagen
Arquitectura Docker
1
2
3
4
5
6
7
8
9
10
11
12
| ┌─────────────────────────────────────┐
│ Docker Client │
│ (docker CLI) │
└──────────────┬──────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ Docker Daemon │
│ (dockerd) │
├─────────────────────────────────────┤
│ Images │ Containers │ Networks │
└─────────────────────────────────────┘
|
Comandos Esenciales
Gestión de Imágenes
1
2
3
4
5
6
7
8
9
10
11
| # Descargar imagen
docker pull nginx:latest
# Listar imágenes
docker images
# Eliminar imagen
docker rmi nginx:latest
# Construir imagen desde Dockerfile
docker build -t mi-app:v1 .
|
Gestión de Contenedores
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
| # Ejecutar contenedor
docker run -d -p 8080:80 --name web nginx
# Listar contenedores
docker ps # En ejecución
docker ps -a # Todos
# Detener/Iniciar
docker stop web
docker start web
# Ver logs
docker logs -f web
# Ejecutar comando dentro del contenedor
docker exec -it web bash
# Eliminar contenedor
docker rm web
|
Dockerfile
El Dockerfile define cómo construir tu imagen:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
| # Imagen base
FROM node:18-alpine
# Metadata
LABEL maintainer="[email protected]"
# Directorio de trabajo
WORKDIR /app
# Copiar archivos de dependencias primero (cache optimization)
COPY package*.json ./
# Instalar dependencias
RUN npm ci --only=production
# Copiar código fuente
COPY . .
# Variable de entorno
ENV NODE_ENV=production
# Exponer puerto
EXPOSE 3000
# Usuario no-root (seguridad)
USER node
# Comando por defecto
CMD ["node", "server.js"]
|
Multi-stage Builds
Reduce el tamaño de tu imagen final:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
| # Stage 1: Build
FROM node:18 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# Stage 2: Production
FROM node:18-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
EXPOSE 3000
CMD ["node", "dist/server.js"]
|
Docker Compose
Para aplicaciones multi-contenedor, usa docker-compose.yml:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
| version: '3.8'
services:
# Aplicación web
app:
build: .
ports:
- "3000:3000"
environment:
- NODE_ENV=production
- DATABASE_URL=postgres://user:pass@db:5432/mydb
depends_on:
- db
- redis
restart: unless-stopped
networks:
- app-network
# Base de datos
db:
image: postgres:15-alpine
volumes:
- postgres_data:/var/lib/postgresql/data
environment:
- POSTGRES_USER=user
- POSTGRES_PASSWORD=pass
- POSTGRES_DB=mydb
networks:
- app-network
# Cache
redis:
image: redis:7-alpine
volumes:
- redis_data:/data
networks:
- app-network
# Reverse proxy
nginx:
image: nginx:alpine
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
depends_on:
- app
networks:
- app-network
volumes:
postgres_data:
redis_data:
networks:
app-network:
driver: bridge
|
Comandos Docker Compose
1
2
3
4
5
6
7
8
9
10
11
12
13
14
| # Iniciar servicios
docker-compose up -d
# Ver logs
docker-compose logs -f
# Escalar servicios
docker-compose up -d --scale app=3
# Detener
docker-compose down
# Eliminar todo (incluyendo volúmenes)
docker-compose down -v
|
Networking
Docker ofrece varios drivers de red:
1
2
3
4
5
6
7
8
| # Crear red personalizada
docker network create --driver bridge mi-red
# Conectar contenedor a red
docker network connect mi-red mi-contenedor
# Inspeccionar red
docker network inspect mi-red
|
Tipos de Red
| Driver |
Uso |
| bridge |
Red aislada (default) |
| host |
Comparte red del host |
| none |
Sin networking |
| overlay |
Multi-host (Swarm) |
Volúmenes
Persiste datos fuera del contenedor:
1
2
3
4
5
6
7
8
9
10
11
| # Crear volumen
docker volume create mi-data
# Montar volumen
docker run -v mi-data:/app/data nginx
# Bind mount (directorio local)
docker run -v $(pwd)/config:/app/config nginx
# Inspeccionar
docker volume inspect mi-data
|
Buenas Prácticas
1. Usa imágenes base pequeñas
1
2
3
4
5
6
7
| # ❌ Evitar
FROM ubuntu:latest
# ✅ Preferir
FROM alpine:3.18
FROM node:18-alpine
FROM python:3.11-slim
|
2. Minimiza capas
1
2
3
4
5
6
7
8
9
10
| # ❌ Múltiples RUN
RUN apt-get update
RUN apt-get install -y curl
RUN apt-get clean
# ✅ Un solo RUN
RUN apt-get update && \
apt-get install -y curl && \
apt-get clean && \
rm -rf /var/lib/apt/lists/*
|
3. No ejecutes como root
1
2
3
| # Crear usuario
RUN addgroup -S appgroup && adduser -S appuser -G appgroup
USER appuser
|
4. Usa .dockerignore
1
2
3
4
5
6
7
| # .dockerignore
node_modules
.git
.env
*.md
Dockerfile
docker-compose.yml
|
5. Health checks
1
2
| HEALTHCHECK --interval=30s --timeout=3s --start-period=5s --retries=3 \
CMD curl -f http://localhost:3000/health || exit 1
|
Seguridad
Prácticas de seguridad críticas:
1
2
3
4
5
6
7
8
9
10
11
| # Escanear vulnerabilidades
docker scan mi-imagen:latest
# Ejecutar con capacidades limitadas
docker run --cap-drop=ALL --cap-add=NET_BIND_SERVICE nginx
# Filesystem de solo lectura
docker run --read-only nginx
# Limitar recursos
docker run --memory=512m --cpus=1 nginx
|
Ejemplo Práctico: Stack MERN
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
| # docker-compose.yml para MERN Stack
version: '3.8'
services:
frontend:
build: ./frontend
ports:
- "3000:3000"
environment:
- REACT_APP_API_URL=http://localhost:5000
depends_on:
- backend
backend:
build: ./backend
ports:
- "5000:5000"
environment:
- MONGODB_URI=mongodb://mongo:27017/myapp
- JWT_SECRET=${JWT_SECRET}
depends_on:
- mongo
mongo:
image: mongo:6
volumes:
- mongo_data:/data/db
ports:
- "27017:27017"
volumes:
mongo_data:
|
Debugging
1
2
3
4
5
6
7
8
9
10
11
12
| # Ver procesos en contenedor
docker top mi-contenedor
# Estadísticas en tiempo real
docker stats
# Inspeccionar contenedor
docker inspect mi-contenedor
# Copiar archivos desde/hacia contenedor
docker cp mi-contenedor:/app/logs ./logs
docker cp ./config.json mi-contenedor:/app/
|
Conclusión
Docker es una herramienta fundamental en el desarrollo moderno. Con estos conocimientos puedes:
- ✅ Crear entornos reproducibles
- ✅ Simplificar despliegues
- ✅ Mejorar la colaboración en equipo
- ✅ Escalar aplicaciones eficientemente
1
2
| $ docker run -it --rm alpine echo "¡Docker es genial! 🐳"
¡Docker es genial! 🐳
|