Docker et Docker Compose : Commandes et configurations

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 CGO
ENABLED=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 .DS
Store .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 container
name: 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 NPM
TOKEN 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: env
file: .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

Laisser un commentaire