9 min de lecture · 1 778 mots

Docker et Docker Compose : Commandes et configurations

Installation

Installation Docker

# Ubuntu/Debian
sudo apt-get update
sudo apt-get install docker.io docker-compose
sudo systemctl start docker
sudo systemctl enable docker

# Ajouter utilisateur au groupe docker
sudo usermod -aG docker $USER
newgrp docker

# Vérifier installation
docker --version
docker-compose --version
docker run hello-world

# macOS (via Homebrew)
brew install --cask docker

# Windows
# Télécharger Docker Desktop depuis docker.com

Configuration de base

# Voir info système
docker info
docker version

# Configuration daemon
sudo nano /etc/docker/daemon.json
{
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  },
  "storage-driver": "overlay2",
  "dns": ["8.8.8.8", "8.8.4.4"]
}
# Redémarrer Docker
sudo systemctl restart docker

Commandes Docker essentielles

Images

# Lister images
docker images
docker image ls
docker images -a  # Inclure intermédiaires

# Rechercher images
docker search ubuntu
docker search nginx

# Télécharger image
docker pull ubuntu
docker pull ubuntu:22.04
docker pull nginx:latest

# Construire image
docker build -t mon-app:1.0 .
docker build -t mon-app:latest -f Dockerfile.prod .
docker build --no-cache -t mon-app .

# Tag image
docker tag mon-app:1.0 mon-app:latest
docker tag mon-app:1.0 registry.example.com/mon-app:1.0

# Pousser image vers registry
docker push registry.example.com/mon-app:1.0

# Supprimer images
docker rmi nginx
docker rmi $(docker images -q)  # Toutes les images
docker image prune  # Images non utilisées
docker image prune -a  # Toutes les images non utilisées

# Inspecter image
docker inspect nginx
docker history nginx

# Sauvegarder/Charger image
docker save -o mon-app.tar mon-app:1.0
docker load -i mon-app.tar

# Exporter/Importer conteneur
docker export conteneur > conteneur.tar
docker import conteneur.tar mon-image:latest

Conteneurs

# Lister conteneurs
docker ps  # Actifs
docker ps -a  # Tous
docker ps -aq  # IDs seulement
docker ps --filter "status=running"

# Créer et démarrer conteneur
docker run nginx
docker run -d nginx  # Détaché
docker run -d --name mon-nginx nginx
docker run -d -p 8080:80 nginx  # Map de ports
docker run -d -p 8080:80 -v $(pwd):/usr/share/nginx/html nginx

# Options run avancées
docker run -d 
  --name mon-app 
  -p 3000:3000 
  -e NODEENV=production 
  -e DBHOST=db 
  -v /data:/app/data 
  --restart unless-stopped 
  --network mon-network 
  --memory="512m" 
  --cpus="1.5" 
  mon-app:latest

# Démarrer/Arrêter
docker start mon-nginx
docker stop mon-nginx
docker restart mon-nginx
docker pause mon-nginx
docker unpause mon-nginx

# Supprimer conteneurs
docker rm mon-nginx
docker rm -f mon-nginx  # Force
docker rm $(docker ps -aq)  # Tous
docker container prune  # Arrêtés

# Exécuter commande dans conteneur
docker exec mon-nginx ls -la
docker exec -it mon-nginx bash
docker exec -it mon-nginx sh

# Voir logs
docker logs mon-nginx
docker logs -f mon-nginx  # Follow
docker logs --tail 100 mon-nginx
docker logs --since 30m mon-nginx

# Inspecter conteneur
docker inspect mon-nginx
docker top mon-nginx
docker stats mon-nginx
docker stats  # Tous les conteneurs

# Copier fichiers
docker cp fichier.txt mon-nginx:/app/
docker cp mon-nginx:/app/fichier.txt ./

# Commit conteneur en image
docker commit mon-nginx mon-nginx-modifie:1.0

# Créer conteneur sans démarrer
docker create --name mon-app nginx

# Attacher/Détacher
docker attach mon-nginx
# Ctrl+P puis Ctrl+Q pour détacher

# Événements
docker events
docker events --filter 'type=container'

Volumes

# Lister volumes
docker volume ls

# Créer volume
docker volume create mon-volume

# Inspecter volume
docker volume inspect mon-volume

# Utiliser volume
docker run -v mon-volume:/data nginx

# Volume bind mount
docker run -v $(pwd):/app nginx
docker run -v /host/path:/container/path:ro nginx  # Read-only

# Tmpfs mount (mémoire)
docker run --tmpfs /app/temp nginx

# Supprimer volumes
docker volume rm mon-volume
docker volume prune  # Non utilisés

# Backup volume
docker run --rm 
  -v mon-volume:/data 
  -v $(pwd):/backup 
  ubuntu tar czf /backup/backup.tar.gz /data

# Restore volume
docker run --rm 
  -v mon-volume:/data 
  -v $(pwd):/backup 
  ubuntu tar xzf /backup/backup.tar.gz -C /

Networks

# Lister réseaux
docker network ls

# Créer réseau
docker network create mon-network
docker network create --driver bridge mon-bridge
docker network create --driver overlay mon-overlay

# Options avancées
docker network create 
  --driver bridge 
  --subnet 172.20.0.0/16 
  --gateway 172.20.0.1 
  mon-network

# Connecter conteneur au réseau
docker network connect mon-network mon-nginx
docker network disconnect mon-network mon-nginx

# Inspecter réseau
docker network inspect mon-network

# Supprimer réseau
docker network rm mon-network
docker network prune  # Non utilisés

# Exécuter avec réseau spécifique
docker run --network mon-network nginx
docker run --network host nginx  # Utilise réseau host
docker run --network none nginx  # Pas de réseau

Dockerfile

Syntaxe de base

# Commentaire
FROM node:18-alpine

# Métadonnées
LABEL maintainer="email@example.com"
LABEL version="1.0"
LABEL description="Mon application Node.js"

# Variables d'environnement
ENV NODEENV=production
ENV PORT=3000
ENV APPDIR=/app

# Utilisateur
USER node

# Répertoire de travail
WORKDIR /app

# Copier fichiers
COPY package.json ./
COPY . .

# Exécuter commandes (chaque RUN crée une couche)
RUN npm install --production

# Port exposé (documentation)
EXPOSE 3000

# Volume (documentation)
VOLUME ["/app/data"]

# Commande de démarrage
CMD ["node", "server.js"]
# ou
ENTRYPOINT ["node"]
CMD ["server.js"]

Exemples pratiques

# Node.js avec multi-stage build
FROM node:18-alpine AS builder
WORKDIR /app
COPY package.json ./
RUN npm ci --only=production

FROM node:18-alpine
WORKDIR /app
COPY --from=builder /app/nodemodules ./nodemodules
COPY . .
USER node
EXPOSE 3000
CMD ["node", "server.js"]

# Python avec optimisations
FROM python:3.11-slim
WORKDIR /app

# Installer dépendances système
RUN apt-get update && 
    apt-get install -y --no-install-recommends gcc && 
    rm -rf /var/lib/apt/lists/

# Copier requirements et installer
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt

# Copier code
COPY . .

# Utilisateur non-root
RUN useradd -m appuser && 
    chown -R appuser:appuser /app
USER appuser

EXPOSE 8000
CMD ["python", "app.py"]

# PHP avec Apache
FROM php:8.2-apache
WORKDIR /var/www/html

# Installer extensions
RUN docker-php-ext-install pdo pdomysql mysqli

# Activer modules Apache
RUN a2enmod rewrite

# Copier code
COPY . .

# Permissions
RUN chown -R www-data:www-data /var/www/html

EXPOSE 80
CMD ["apache2-foreground"]

# Go avec build optimisé
FROM golang:1.21-alpine AS builder
WORKDIR /app
COPY go. ./
RUN go mod download
COPY . .
RUN CGOENABLED=0 GOOS=linux go build -a -installsuffix cgo -o main .

FROM alpine:latest
RUN apk --no-cache add ca-certificates
WORKDIR /root/
COPY --from=builder /app/main .
EXPOSE 8080
CMD ["./main"]

# React build
FROM node:18-alpine AS build
WORKDIR /app
COPY package.json ./
RUN npm ci
COPY . .
RUN npm run build

FROM nginx:alpine
COPY --from=build /app/build /usr/share/nginx/html
COPY nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]

.dockerignore

# Fichier .dockerignore
nodemodules
npm-debug.log
.git
.gitignore
.env
.env.local
.md
README.md
.DSStore
.vscode
.idea
pycache
.pyc
.pyo
dist
build
coverage
.pytestcache

Docker Compose

Syntaxe de base

# docker-compose.yml
version: '3.8'

services:
  # Service web
  web:
    build: .
    # ou
    image: nginx:latest
    containername: mon-web
    ports:
      - "8080:80"
    environment:
      - NODEENV=production
      - APIKEY=secret
    envfile:
      - .env
    volumes:
      - ./app:/app
      - web-data:/var/www
    networks:
      - frontend
    dependson:
      - db
    restart: unless-stopped
    command: npm start

  # Base de données
  db:
    image: postgres:15
    containername: mon-db
    environment:
      POSTGRESDB: myapp
      POSTGRESUSER: user
      POSTGRESPASSWORD: password
    volumes:
      - db-data:/var/lib/postgresql/data
      - ./init.sql:/docker-entrypoint-initdb.d/init.sql
    networks:
      - backend
    restart: always

volumes:
  web-data:
  db-data:

networks:
  frontend:
  backend:

Stack complète (MERN)

version: '3.8'

services:
  # MongoDB
  mongo:
    image: mongo:7
    containername: mongo
    restart: always
    environment:
      MONGOINITDBROOTUSERNAME: admin
      MONGOINITDBROOTPASSWORD: password
    ports:
      - "27017:27017"
    volumes:
      - mongo-data:/data/db
    networks:
      - backend

  # Redis
  redis:
    image: redis:7-alpine
    containername: redis
    restart: always
    ports:
      - "6379:6379"
    networks:
      - backend

  # Backend (Express)
  api:
    build:
      context: ./backend
      dockerfile: Dockerfile
    containername: api
    restart: always
    ports:
      - "5000:5000"
    environment:
      NODEENV: production
      MONGOURI: mongodb://admin:password@mongo:27017/myapp?authSource=admin
      REDISHOST: redis
      JWTSECRET: ${JWTSECRET}
    dependson:
      - mongo
      - redis
    volumes:
      - ./backend:/app
      - /app/nodemodules
    networks:
      - backend
      - frontend

  # Frontend (React)
  client:
    build:
      context: ./frontend
      dockerfile: Dockerfile
    containername: client
    restart: always
    ports:
      - "3000:80"
    environment:
      REACTAPPAPIURL: http://localhost:5000/api
    dependson:
      - api
    networks:
      - frontend

  # Nginx (Reverse Proxy)
  nginx:
    image: nginx:alpine
    containername: nginx
    restart: always
    ports:
      - "80:80"
      - "443:443"
    volumes:
      - ./nginx/nginx.conf:/etc/nginx/nginx.conf
      - ./nginx/ssl:/etc/nginx/ssl
    dependson:
      - api
      - client
    networks:
      - frontend

volumes:
  mongo-data:

networks:
  frontend:
  backend:

Stack Laravel

version: '3.8'

services:
  # Nginx
  nginx:
    image: nginx:alpine
    containername: nginx
    restart: unless-stopped
    ports:
      - "80:80"
    volumes:
      - ./:/var/www
      - ./docker/nginx/nginx.conf:/etc/nginx/conf.d/default.conf
    dependson:
      - php
      - mysql
    networks:
      - laravel

  # PHP-FPM
  php:
    build:
      context: .
      dockerfile: docker/php/Dockerfile
    containername: php
    restart: unless-stopped
    volumes:
      - ./:/var/www
    networks:
      - laravel

  # MySQL
  mysql:
    image: mysql:8.0
    containername: mysql
    restart: unless-stopped
    environment:
      MYSQLDATABASE: laravel
      MYSQLROOTPASSWORD: root
      MYSQLUSER: laravel
      MYSQLPASSWORD: password
    ports:
      - "3306:3306"
    volumes:
      - mysql-data:/var/lib/mysql
    networks:
      - laravel

  # Adminer (DB management)
  adminer:
    image: adminer
    containername: adminer
    restart: unless-stopped
    ports:
      - "8080:8080"
    networks:
      - laravel

volumes:
  mysql-data:

networks:
  laravel:
    driver: bridge

Stack WordPress

version: '3.8'

services:
  # WordPress
  wordpress:
    image: wordpress:latest
    containername: wordpress
    restart: always
    ports:
      - "8000:80"
    environment:
      WORDPRESSDBHOST: db
      WORDPRESSDBUSER: wordpress
      WORDPRESSDBPASSWORD: wordpress
      WORDPRESSDBNAME: wordpress
    volumes:
      - ./wordpress:/var/www/html
      - ./php.ini:/usr/local/etc/php/conf.d/custom.ini
    dependson:
      - db
    networks:
      - wordpress

  # MySQL
  db:
    image: mysql:8.0
    containername: wordpress-db
    restart: always
    environment:
      MYSQLDATABASE: wordpress
      MYSQLUSER: wordpress
      MYSQLPASSWORD: wordpress
      MYSQLROOTPASSWORD: rootpassword
    volumes:
      - db-data:/var/lib/mysql
    networks:
      - wordpress

  # phpMyAdmin
  phpmyadmin:
    image: phpmyadmin:latest
    containername: phpmyadmin
    restart: always
    ports:
      - "8080:80"
    environment:
      PMAHOST: db
      PMAUSER: wordpress
      PMAPASSWORD: wordpress
    dependson:
      - db
    networks:
      - wordpress

volumes:
  db-data:

networks:
  wordpress:

Commandes Docker Compose

Gestion de stack

# Démarrer services
docker-compose up
docker-compose up -d  # Détaché
docker-compose up --build  # Rebuild images
docker-compose up --force-recreate  # Recréer conteneurs

# Arrêter services
docker-compose down
docker-compose down -v  # Avec volumes
docker-compose down --rmi all  # Avec images

# Démarrer/Arrêter services spécifiques
docker-compose start web
docker-compose stop web
docker-compose restart web

# Pause/Unpause
docker-compose pause
docker-compose unpause

# Lister services
docker-compose ps
docker-compose ps -a

# Logs
docker-compose logs
docker-compose logs -f  # Follow
docker-compose logs web  # Service spécifique
docker-compose logs --tail=100 web

# Build
docker-compose build
docker-compose build --no-cache
docker-compose build web

# Exécuter commande
docker-compose exec web sh
docker-compose exec web npm install
docker-compose run web npm test

# Scale services
docker-compose up -d --scale web=3

# Config
docker-compose config  # Valider et afficher config
docker-compose config --services  # Lister services

# Pull images
docker-compose pull

# Événements
docker-compose events

Fichiers multiples

# Utiliser plusieurs fichiers
docker-compose -f docker-compose.yml -f docker-compose.prod.yml up

# docker-compose.override.yml (automatiquement chargé)
version: '3.8'
services:
  web:
    volumes:
      - ./app:/app
    environment:
      DEBUG: "true"

Patterns avancés

Health checks

services:
  web:
    image: nginx
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost"]
      interval: 30s
      timeout: 10s
      retries: 3
      startperiod: 40s

  db:
    image: postgres
    healthcheck:
      test: ["CMD-SHELL", "pgisready -U postgres"]
      interval: 10s
      timeout: 5s
      retries: 5

Depends on avec conditions

services:
  web:
    dependson:
      db:
        condition: servicehealthy
      redis:
        condition: servicestarted

  db:
    healthcheck:
      test: ["CMD-SHELL", "pgisready"]
      interval: 10s

Profiles

services:
  web:
    image: nginx
    # Toujours démarré

  debug:
    image: alpine
    profiles:
      - debug
    # Démarré seulement avec --profile debug

# Utilisation
docker-compose --profile debug up

Extension fields

# Réutiliser configuration
x-common-variables: &common-vars
  NODEENV: production
  LOGLEVEL: info

x-logging: &default-logging
  driver: json-file
  options:
    max-size: "10m"
    max-file: "3"

services:
  api:
    environment:
      <<: common-vars
      APIPORT: 5000
    logging: default-logging

  worker:
    environment:
      <<: common-vars
      WORKERTHREADS: 4
    logging: default-logging

Secrets

version: '3.8'

services:
  db:
    image: postgres
    secrets:
      - dbpassword
    environment:
      POSTGRESPASSWORDFILE: /run/secrets/dbpassword

secrets:
  dbpassword:
    file: ./secrets/dbpassword.txt

Optimisation et sécurité

Multi-stage builds

# Build stage
FROM node:18-alpine AS builder
WORKDIR /app
COPY package.json ./
RUN npm ci --only=production
COPY . .
RUN npm run build

# Production stage
FROM node:18-alpine
WORKDIR /app

# Copier seulement nécessaire
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/nodemodules ./nodemodules
COPY package.json ./

# Utilisateur non-root
RUN addgroup -g 1001 -S nodejs && 
    adduser -S nodejs -u 1001
USER nodejs

EXPOSE 3000
CMD ["node", "dist/main.js"]

Layer caching

# Mauvais - Recréé toutes les couches à chaque changement
COPY . .
RUN npm install

# Bon - Cache npm install si package.json ne change pas
COPY package.json ./
RUN npm install
COPY . .

Réduire taille image

# Utiliser images Alpine
FROM node:18-alpine  # ~40MB vs ~900MB pour node:18

# Nettoyer dans même RUN
RUN apt-get update && 
    apt-get install -y package && 
    rm -rf /var/lib/apt/lists/

# Utiliser .dockerignore
# Ne pas copier nodemodules, .git, etc.

# Multi-stage pour exclure build tools
FROM golang:alpine AS builder
# build...

FROM alpine
COPY --from=builder /app/binary .
# Image finale sans Go compiler

Sécurité

# Ne pas run en root
RUN adduser -D appuser
USER appuser

# Scanner vulnérabilités
docker scan mon-image:latest

# Versions spécifiques
FROM node:18.17.0-alpine  # Pas :latest

# Secrets
# Ne JAMAIS mettre dans Dockerfile ou commit
# Utiliser build args pour build-time
ARG NPMTOKEN
RUN npm config set //registry.npmjs.org/:authToken=${NPMTOKEN}

# Runtime secrets avec Docker secrets ou env

Resources limits

services:
  web:
    image: nginx
    deploy:
      resources:
        limits:
          cpus: '0.5'
          memory: 512M
        reservations:
          cpus: '0.25'
          memory: 256M

Debugging

Logs et monitoring

# Logs en temps réel
docker logs -f conteneur

# Stats en temps réel
docker stats
docker stats --format "table {{.Container}}t{{.CPUPerc}}t{{.MemUsage}}"

# Événements
docker events --filter 'type=container'

# Inspecter état
docker inspect conteneur | jq '.[0].State'

# Processus dans conteneur
docker top conteneur

# Diff filesystem
docker diff conteneur

Troubleshooting

# Entrer dans conteneur qui crash
docker run --rm -it --entrypoint sh mon-image

# Override CMD
docker run --rm -it mon-image /bin/sh

# Network troubleshooting
docker network inspect mon-network

# Vérifier connectivité entre conteneurs
docker exec conteneur1 ping conteneur2
docker exec conteneur1 curl http://conteneur2:80

# Copier logs hors conteneur
docker cp conteneur:/var/log/app.log ./

# Restart policy
docker update --restart=always conteneur

# Voir changements dans image
docker history --no-trunc mon-image

CI/CD avec Docker

GitHub Actions

# .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: Login to DockerHub
        uses: docker/login-action@v2
        with:
          username: ${{ secrets.DOCKERHUBUSERNAME }}
          password: ${{ secrets.DOCKERHUBTOKEN }}

      - name: Build and push
        uses: docker/build-push-action@v4
        with:
          context: .
          push: true
          tags: |
            myapp:latest
            myapp:${{ github.sha }}
          cache-from: type=registry,ref=myapp:latest
          cache-to: type=inline

GitLab CI

# .gitlab-ci.yml
build:
  stage: build
  image: docker:latest
  services:
    - docker:dind
  beforescript:
    - docker login -u $CIREGISTRYUSER -p $CIREGISTRYPASSWORD $CIREGISTRY
  script:
    - docker build -t $CIREGISTRYIMAGE:$CICOMMITSHA .
    - docker push $CIREGISTRYIMAGE:$CICOMMITSHA
    - docker tag $CIREGISTRYIMAGE:$CICOMMITSHA $CIREGISTRYIMAGE:latest
    - docker push $CIREGISTRYIMAGE:latest

Astuces et bonnes pratiques

One process per container

# Mauvais - Multiple processus
services:
  app:
    command: >
      sh -c "nginx && php-fpm && node app.js"

# Bon - Un service par processus
services:
  nginx:
    image: nginx
  php:
    image: php-fpm
  node:
    image: node

Ordre des instructions Dockerfile

# Ordre optimal pour cache
FROM node:18-alpine

# 1. Metadata (change rarement)
LABEL maintainer="..."

# 2. Dependencies système (change rarement)
RUN apk add --no-cache git

# 3. Dependencies app (change modérément)
COPY package*.json ./
RUN npm ci

# 4. Code app (change souvent)
COPY . .

# 5. Build (dépend du code)
RUN npm run build

# 6. Runtime config
EXPOSE 3000
CMD ["node", "server.js"]

Variables d’environnement

# .env
POSTGRESUSER=admin
POSTGRESPASSWORD=secret
APIKEY=xyz123

# docker-compose.yml
services:
  db:
    envfile: .env
    # ou
    environment:
      - POSTGRESUSER=${POSTGRESUSER}
      - POSTGRESPASSWORD=${POSTGRESPASSWORD}

Commandes utiles

# Nettoyer tout
docker system prune -a --volumes

# Taille utilisée
docker system df

# Supprimer images danglinges
docker rmi $(docker images -f "dangling=true" -q)

# Supprimer conteneurs exited
docker rm $(docker ps -a -f status=exited -q)

# Copier entre conteneurs
docker cp conteneur1:/data/file.txt - | docker cp - conteneur2:/data/

# Export/Import complet
docker save $(docker images -q) -o all-images.tar
docker load -i all-images.tar

Version: Docker 24+, Compose 2.0+ | Ressources: docs.docker.com

Une remarque, un retour ?

Cet article est vivant — corrections, contre-arguments et retours de production sont les bienvenus. Trois canaux, choisissez celui qui vous convient.

Laisser un commentaire