---
title: "Docker Compose — Référence pratique"
domain: devops
subdomain: docker
type: snippet
tags: [docker, docker-compose, containers, devops, orchestration]
difficulty: beginner
status: stable
updated: "2025-05-10"
---
## Commandes essentielles

```bash
# Démarrer la stack
docker compose up -d

# Reconstruire les images et redémarrer
docker compose up -d --build

# Arrêter et supprimer les conteneurs
docker compose down

# Avec suppression des volumes
docker compose down -v

# Logs
docker compose logs -f
docker compose logs -f {{SERVICE}}

# État des services
docker compose ps

# Exécuter une commande dans un service
docker compose exec {{SERVICE}} bash
docker compose exec {{SERVICE}} sh

# Redémarrer un service spécifique
docker compose restart {{SERVICE}}

# Rebuild un seul service
docker compose up -d --build {{SERVICE}}

# Scaling
docker compose up -d --scale {{SERVICE}}=3
```

## Structure docker-compose.yml

```yaml
# docker-compose.yml
version: '3.9'

services:

  # Application
  app:
    build:
      context: .
      dockerfile: Dockerfile
    image: myapp:latest
    container_name: myapp
    restart: unless-stopped
    ports:
      - "3000:3000"
    environment:
      - NODE_ENV=production
      - DATABASE_URL=postgresql://user:pass@db:5432/mydb
    env_file:
      - .env
    depends_on:
      db:
        condition: service_healthy
    volumes:
      - ./uploads:/app/uploads
    networks:
      - frontend
      - backend
    labels:
      - "traefik.enable=true"

  # Base de données
  db:
    image: postgres:16-alpine
    container_name: myapp-db
    restart: unless-stopped
    environment:
      POSTGRES_USER: ${DB_USER}
      POSTGRES_PASSWORD: ${DB_PASSWORD}
      POSTGRES_DB: ${DB_NAME}
    volumes:
      - postgres_data:/var/lib/postgresql/data
      - ./init.sql:/docker-entrypoint-initdb.d/init.sql:ro
    networks:
      - backend
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U ${DB_USER} -d ${DB_NAME}"]
      interval: 10s
      timeout: 5s
      retries: 5

  # Cache
  redis:
    image: redis:7-alpine
    container_name: myapp-redis
    restart: unless-stopped
    command: redis-server --requirepass ${REDIS_PASSWORD}
    volumes:
      - redis_data:/data
    networks:
      - backend

  # Reverse proxy
  nginx:
    image: nginx:alpine
    container_name: myapp-nginx
    restart: unless-stopped
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
      - ./certs:/etc/nginx/certs:ro
    depends_on:
      - app
    networks:
      - frontend

volumes:
  postgres_data:
    driver: local
  redis_data:
    driver: local

networks:
  frontend:
    driver: bridge
  backend:
    driver: bridge
    internal: true   # pas d'accès internet direct
```

## Patterns courants

### Variables d'environnement

```bash
# .env (jamais commité en git)
DB_USER=myapp
DB_PASSWORD=super_secret_password
DB_NAME=myapp_db
REDIS_PASSWORD=redis_secret

# Référencer dans compose
environment:
  - DB_PASSWORD=${DB_PASSWORD}
# ou
environment:
  DB_PASSWORD: ${DB_PASSWORD:-default_value}
```

### Override par environnement

```yaml
# docker-compose.override.yml (dev — auto-chargé)
services:
  app:
    volumes:
      - .:/app     # hot reload en dev
    environment:
      - DEBUG=true
    command: npm run dev

# docker-compose.prod.yml
# docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d
```

### Profiles (services optionnels)

```yaml
services:
  app:
    # Toujours démarré

  adminer:
    image: adminer
    profiles: ["debug"]   # seulement avec --profile debug

# Démarrer avec un profil
docker compose --profile debug up -d
```

### Healthchecks

```yaml
healthcheck:
  test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
  interval: 30s
  timeout: 10s
  retries: 3
  start_period: 40s
```

## Ressources et limites

```yaml
services:
  app:
    deploy:
      resources:
        limits:
          cpus: '1.0'
          memory: 512M
        reservations:
          cpus: '0.25'
          memory: 128M
```

## Debug et troubleshooting

```bash
# Inspecter un conteneur
docker compose exec {{SERVICE}} env
docker compose exec {{SERVICE}} cat /etc/hosts

# Voir les événements
docker compose events

# Stats de ressources
docker stats

# Réseau — inspecter
docker network inspect myapp_backend

# Volumes — inspecter
docker volume inspect myapp_postgres_data

# Logs avec timestamp
docker compose logs -f --timestamps {{SERVICE}}

# Entrer dans un conteneur arrêté
docker run -it --entrypoint sh image_name
```

<Tip>
Utiliser `restart: unless-stopped` plutôt que `always` — cela permet d'arrêter manuellement un conteneur pour debug sans qu'il redémarre automatiquement. En prod, utiliser des secrets Docker (`docker secret`) plutôt que des variables d'environnement pour les données sensibles.
</Tip>
