Docker para Desarrollo Web: Guía Práctica Completa
14 de diciembre de 2025
Osman Jimenez
Docker DevOps Desarrollo Web
Containerización con Docker
Docker revolucionó el desarrollo web al permitir entornos consistentes y reproducibles. Aprende a usar Docker efectivamente en tus proyectos.
Dockerfile para Node.js
# Multi-stage build para optimizar tamaño
FROM node:20-alpine AS builder
WORKDIR /app
# Copiar package files primero (cache layer)
COPY package*.json ./
RUN npm ci --only=production
# Copiar código fuente
COPY . .
RUN npm run build
# Imagen final
FROM node:20-alpine
WORKDIR /app
# Copiar solo lo necesario
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY package*.json ./
# Usuario no-root por seguridad
USER node
EXPOSE 3000
CMD ["node", "dist/main.js"]Dockerfile para Angular
# Build stage
FROM node:20-alpine AS build
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build -- --configuration=production
# Production stage
FROM nginx:alpine
COPY --from=build /app/dist/my-app /usr/share/nginx/html
COPY nginx.conf /etc/nginx/nginx.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]Docker Compose para Stack Completo
version: '3.8'
services:
# Frontend
frontend:
build:
context: ./frontend
dockerfile: Dockerfile
ports:
- "4200:80"
depends_on:
- backend
networks:
- app-network
# Backend API
backend:
build:
context: ./backend
dockerfile: Dockerfile
ports:
- "3000:3000"
environment:
- DATABASE_URL=postgresql://user:pass@db:5432/mydb
- REDIS_URL=redis://redis:6379
depends_on:
- db
- redis
networks:
- app-network
volumes:
- ./backend:/app
- /app/node_modules
# PostgreSQL
db:
image: postgres:15-alpine
environment:
POSTGRES_USER: user
POSTGRES_PASSWORD: pass
POSTGRES_DB: mydb
ports:
- "5432:5432"
volumes:
- postgres-data:/var/lib/postgresql/data
networks:
- app-network
# Redis
redis:
image: redis:7-alpine
ports:
- "6379:6379"
networks:
- app-network
volumes:
postgres-data:
networks:
app-network:
driver: bridgeComandos Esenciales
# Build imagen
docker build -t my-app:latest .
# Run container
docker run -d -p 3000:3000 --name my-app my-app:latest
# Ver logs
docker logs -f my-app
# Ejecutar comando en container
docker exec -it my-app sh
# Docker Compose
docker-compose up -d
docker-compose down
docker-compose logs -f backend
# Limpiar
docker system prune -a
docker volume pruneHot Reload en Desarrollo
# docker-compose.dev.yml
version: '3.8'
services:
backend:
build:
context: ./backend
dockerfile: Dockerfile.dev
ports:
- "3000:3000"
volumes:
- ./backend:/app
- /app/node_modules
environment:
- NODE_ENV=development
command: npm run devDockerfile.dev con Hot Reload
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
EXPOSE 3000
CMD ["npm", "run", "dev"].dockerignore
node_modules
npm-debug.log
dist
.git
.gitignore
.env
.env.local
.DS_Store
coverage
*.md
.vscode
.ideaOptimizaciones
1. Layer Caching
# ❌ Malo: Invalida cache en cada cambio
COPY . .
RUN npm install
# ✅ Bueno: Cache de dependencias
COPY package*.json ./
RUN npm ci
COPY . .2. Multi-stage Builds
# Reduce tamaño final de imagen
FROM node:20 AS builder
# ... build steps ...
FROM node:20-alpine
COPY --from=builder /app/dist ./dist3. Usar Alpine
# node:20 = ~900MB
# node:20-alpine = ~170MB
FROM node:20-alpineHealth Checks
FROM node:20-alpine
# ...
HEALTHCHECK --interval=30s --timeout=3s --start-period=40s --retries=3 \
CMD node healthcheck.jsSecrets y Variables de Entorno
# .env
DATABASE_URL=postgresql://user:pass@localhost:5432/db
JWT_SECRET=my-secret
# docker-compose.yml
services:
backend:
env_file:
- .env
# O específicas
environment:
- NODE_ENV=production
- PORT=3000Networking
# Crear red personalizada
docker network create my-network
# Conectar containers
docker run --network my-network --name backend backend:latest
docker run --network my-network --name frontend frontend:latest
# Frontend puede acceder a backend via:
fetch('http://backend:3000/api')Debugging
# Inspeccionar container
docker inspect my-app
# Ver procesos
docker top my-app
# Estadísticas en tiempo real
docker stats
# Acceder a shell
docker exec -it my-app sh
# Ver cambios en filesystem
docker diff my-appCI/CD con Docker
# .github/workflows/docker.yml
name: Docker Build and Push
on:
push:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Build Docker image
run: docker build -t myapp:${{ github.sha }} .
- name: Push to registry
run: |
echo ${{ secrets.DOCKER_PASSWORD }} | docker login -u ${{ secrets.DOCKER_USERNAME }} --password-stdin
docker push myapp:${{ github.sha }}Mejores Prácticas
- Una aplicación por container: Sigue el principio de responsabilidad única
- Usa .dockerignore: Reduce tamaño y tiempo de build
- Multi-stage builds: Para imágenes más pequeñas
- No uses latest en producción: Usa tags específicos
- Health checks: Para monitoreo y auto-healing
- Logs a stdout/stderr: Para mejor observabilidad
- Usuario no-root: Por seguridad
Conclusión
Docker es esencial en el desarrollo web moderno. Proporciona consistencia entre entornos, facilita el deployment y mejora la colaboración en equipo. Dominar Docker te hace un desarrollador más versátil y valioso.