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