Containeriza tu aplicación web con Docker para garantizar que el entorno de desarrollo es idéntico al de producción. Con el Dockerfile óptimo, el docker-compose para desarrollo local, la imagen mínima para producción y los patrones que evitan los errores más comunes.
Cuándo usarlo: Docker, containerización, DevOps, docker-compose, producción
Herramienta recomendada: Claude
Eres un DevOps Engineer con experiencia containerizando aplicaciones de Node.js, Python, PHP y Go para producción con Docker y Kubernetes. Mi stack: - Aplicación: [Node.js / Python Flask/Django / PHP Laravel / Go / Ruby on Rails / otro] - Base de datos: [PostgreSQL / MySQL / MongoDB / Redis / combinación] - Entorno actual: [sin Docker / docker run manual / quiero docker-compose / ya tengo Docker pero el Dockerfile es mejorable] - Destino de producción: [VPS / AWS ECS / Kubernetes / Railway / Render / otro] ## Docker para Aplicaciones Web — [Tu stack] ### 🧠 Los conceptos que necesitas tener claros **Imagen:** la plantilla inmutable. Como una clase en programación. **Contenedor:** una instancia en ejecución de una imagen. Como un objeto de esa clase. **Dockerfile:** las instrucciones para construir la imagen. **docker-compose:** orquesta múltiples contenedores (app + base de datos + cache) en desarrollo. ### 📄 El Dockerfile óptimo por stack **Node.js (con multi-stage build para imagen de producción mínima):** ```dockerfile # Stage 1: dependencias y build FROM node:20-alpine AS builder WORKDIR /app COPY package*.json ./ RUN npm ci --only=production COPY . . RUN npm run build # si tienes build step (TypeScript, Next.js, etc.) # Stage 2: imagen de producción mínima FROM node:20-alpine AS runner WORKDIR /app ENV NODE_ENV=production # Solo copiamos lo necesario del stage anterior COPY --from=builder /app/node_modules ./node_modules COPY --from=builder /app/dist ./dist COPY --from=builder /app/package.json ./ # Nunca uses root en producción USER node EXPOSE 3000 CMD ["node", "dist/index.js"] ``` **PHP Laravel:** ```dockerfile FROM php:8.3-fpm-alpine # Extensiones PHP necesarias RUN docker-php-ext-install pdo pdo_pgsql opcache && \ apk add --no-cache nginx supervisor # Composer COPY --from=composer:2 /usr/bin/composer /usr/bin/composer WORKDIR /var/www/html COPY . . RUN composer install --no-dev --optimize-autoloader # Permisos correctos RUN chown -R www-data:www-data storage bootstrap/cache EXPOSE 80 CMD ["/usr/bin/supervisord", "-c", "/etc/supervisord.conf"] ``` **Python FastAPI/Flask:** ```dockerfile FROM python:3.12-slim WORKDIR /app # Dependencias primero (mejor caché) COPY requirements.txt . RUN pip install --no-cache-dir -r requirements.txt COPY . . USER 1000 EXPOSE 8000 CMD ["uvicorn", "main:app", "--host", "0.0.0.0", "--port", "8000"] ``` ### 🔧 docker-compose para desarrollo local ```yaml # docker-compose.yml version: '3.9' services: app: build: context: . target: builder # usa el stage de desarrollo, no el de producción volumes: - .:/app # monta el código local → hot reload - /app/node_modules # excluye node_modules del montaje ports: - "3000:3000" environment: - NODE_ENV=development - DATABASE_URL=postgresql://user:password@db:5432/myapp - REDIS_URL=redis://cache:6379 depends_on: db: condition: service_healthy cache: condition: service_started db: image: postgres:16-alpine environment: POSTGRES_USER: user POSTGRES_PASSWORD: password POSTGRES_DB: myapp volumes: - postgres_data:/var/lib/postgresql/data healthcheck: test: ["CMD-SHELL", "pg_isready -U user"] interval: 5s timeout: 5s retries: 5 cache: image: redis:7-alpine volumes: - redis_data:/data volumes: postgres_data: redis_data: ``` **Comandos esenciales:** ```bash docker compose up -d # arranca todo en background docker compose logs -f app # logs de la app en tiempo real docker compose exec app sh # shell dentro del contenedor docker compose down -v # para todo y borra los volúmenes docker compose build --no-cache # reconstruye la imagen desde cero ``` ### ⚠️ Los errores más comunes (y cómo evitarlos) **Error 1 — COPY . . antes que las dependencias:** ```dockerfile # ❌ Cada cambio de código invalida el caché de las dependencias COPY . . RUN npm install # ✅ Las dependencias se cachean si package.json no cambia COPY package*.json ./ RUN npm install COPY . . ``` **Error 2 — Imagen base no específica:** ```dockerfile # ❌ node:latest cambia sin aviso y rompe builds FROM node:latest # ✅ Versión fija, alpine para imagen mínima FROM node:20-alpine ``` **Error 3 — Credenciales en el Dockerfile:** ```dockerfile # ❌ NUNCA ENV API_KEY="sk-1234567890" # ✅ Variables de entorno en tiempo de ejecución ENV API_KEY="" # vacía en la imagen, inyectada al arrancar ```