Docker sur Ubuntu : Guide complet d’installation et d’utilisation
Docker est une plateforme de conteneurisation open-source qui empaquète les applications et leurs dépendances dans des unités isolées et portables appelées conteneurs. Contrairement aux machines virtuelles, les conteneurs partagent le noyau OS de l’hôte, ce qui les rend considérablement plus légers, plus rapides au démarrage et plus efficaces en termes de ressources — une distinction essentielle pour quiconque exécute des charges de travail dans un environnement VPS Hosting où les ressources de calcul affectent directement les coûts et les performances.
Ce guide couvre l’intégralité du processus d’installation de Docker sur Ubuntu 20.04, 22.04 et 24.04 LTS, y compris le durcissement post-installation, les flux de travail Docker Compose et les modèles de commandes pertinents pour la production que la plupart des tutoriels omettent.
Prérequis et configuration système requise
Avant d’exécuter la moindre commande, vérifiez les points suivants :
- Version Ubuntu : 20.04 LTS (Focal), 22.04 LTS (Jammy) ou 24.04 LTS (Noble). La commande `lsb_release -cs` utilisée lors de la configuration du dépôt détectera automatiquement votre nom de code.
- Architecture : `amd64`, `arm64` et `armhf` sont tous pris en charge par le dépôt officiel de Docker.
- Version du noyau : Docker nécessite le noyau Linux 3.10 ou supérieur. Exécutez `uname -r` pour confirmer.
- Privilèges utilisateur : `sudo` ou un accès root est obligatoire pour l’installation et la gestion du démon.
- Espace disque : Au minimum 2 GB libres sur la partition hébergeant `/var/lib/docker`, qui est l’endroit où Docker stocke les images, les conteneurs, les volumes et le cache de construction. Sur les systèmes de production, montez ce répertoire sur une partition ou un volume dédié.
Étape critique avant l’installation : Si vous avez précédemment installé Docker depuis le dépôt `apt` par défaut d’Ubuntu (le paquet `docker.io`), supprimez-le d’abord pour éviter les conflits avec les paquets officiels Docker CE :
“`bash
sudo apt remove docker docker-engine docker.io containerd runc
“`
Étape 1 : Mettre à jour les paquets système
Mettez à jour l’index des paquets et les paquets installés vers leurs dernières versions avant d’ajouter un nouveau dépôt :
“`bash
sudo apt update
sudo apt upgrade -y
“`
Cela garantit que le résolveur de dépendances de `apt` fonctionne avec les métadonnées de paquets actuelles et que les bibliothèques de votre système de base ne sont pas obsolètes — une source courante d’erreurs d’exécution subtiles avec les applications conteneurisées.
Étape 2 : Installer Docker Engine depuis le dépôt officiel
Les dépôts `apt` par défaut d’Ubuntu fournissent un paquet appelé `docker.io`, maintenu par Canonical et généralement en retard de plusieurs versions par rapport à la version officielle de Docker. Pour une utilisation en production, installez toujours depuis le dépôt propre à Docker.
2.1 Installer les dépendances de transport et de vérification
“`bash
sudo apt install apt-transport-https ca-certificates curl software-properties-common gnupg lsb-release -y
“`
Pourquoi `gnupg` ? À partir d’Ubuntu 22.04, `gpg` n’est pas toujours présent par défaut. L’inclure explicitement empêche l’importation de la clé GPG d’échouer silencieusement.
2.2 Ajouter la clé GPG officielle de Docker
“`bash
sudo install -m 0755 -d /usr/share/keyrings
curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg –dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
sudo chmod a+r /usr/share/keyrings/docker-archive-keyring.gpg
“`
L’étape `chmod a+r` est fréquemment omise dans les tutoriels, mais elle est nécessaire sur les systèmes où `apt` s’exécute dans un contexte utilisateur restreint — sans elle, le gestionnaire de paquets ne peut pas lire le trousseau de clés et générera une erreur `NO_PUBKEY` lors de `apt update`.
2.3 Ajouter le dépôt stable de Docker
“`bash
echo
"deb [arch=$(dpkg –print-architecture) signed-by=/usr/share/keyrings/docker-archive-keyring.gpg]
https://download.docker.com/linux/ubuntu
$(lsb_release -cs) stable" |
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
“`
La substitution `arch=$(dpkg –print-architecture)` est essentielle sur les serveurs basés sur ARM. Coder en dur `amd64` ici est une erreur courante qui provoque des échecs silencieux de résolution de paquets sur les instances ARM.
2.4 Installer Docker Engine, CLI et les plugins
“`bash
sudo apt update
sudo apt install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin -y
“`
Détail des paquets :
| Paquet | Rôle |
|---|
| — | — |
|---|
| `docker-ce` | Démon Docker Engine (`dockerd`) |
|---|
| `docker-ce-cli` | CLI client (commande `docker`) |
|---|
| `containerd.io` | Runtime de conteneur de bas niveau (conforme OCI) |
|---|
| `docker-buildx-plugin` | Capacités de construction étendues (multi-plateforme, BuildKit) |
|---|
| `docker-compose-plugin` | Compose V2 intégré comme plugin CLI Docker |
|---|
Remarque sur `containerd.io` : Ce n’est pas la même chose que le paquet `containerd` dans le dépôt par défaut d’Ubuntu. Le `containerd.io` de Docker est une version spécifique et testée du runtime containerd. Mélanger les deux est une source connue d’échecs au démarrage du démon.
Étape 3 : Vérifier l’installation
Confirmez que le démon est actif et configuré pour démarrer au démarrage du système :
“`bash
sudo systemctl status docker
sudo systemctl enable docker
“`
Vérifiez la version installée :
“`bash
sudo docker –version
sudo docker info
“`
`docker info` est plus informatif que `–version` seul — il révèle le pilote de stockage utilisé (généralement `overlay2`), le pilote cgroup (`systemd` vs `cgroupfs`), ainsi que le nombre de CPU et la mémoire auxquels Docker peut accéder.
Exécutez le test de vérification canonique :
“`bash
sudo docker run hello-world
“`
Une exécution réussie affiche un message « Hello from Docker ! » et confirme que le démon Docker, le téléchargement d’image depuis Docker Hub et l’exécution du conteneur fonctionnent tous correctement.
Étape 4 : Configurer Docker pour un accès sans root
Par défaut, le socket Docker (`/var/run/docker.sock`) appartient à `root` et au groupe `docker`. Tout utilisateur n’appartenant pas au groupe `docker` doit utiliser `sudo` pour chaque commande Docker.
“`bash
sudo usermod -aG docker $USER
“`
Appliquez l’appartenance au groupe sans vous déconnecter :
“`bash
newgrp docker
“`
Vérifiez :
“`bash
docker run hello-world
“`
Avertissement de sécurité : L’appartenance au groupe `docker` est effectivement équivalente à un accès `sudo` sans mot de passe. Un utilisateur dans le groupe `docker` peut facilement monter le système de fichiers hôte dans un conteneur et contourner tous les contrôles d’accès au niveau du système de fichiers. Sur les systèmes multi-locataires ou les serveurs partagés, envisagez plutôt d’utiliser Docker rootless :
“`bash
dockerd-rootless-setuptool.sh install
“`
Le mode rootless exécute le démon Docker et les conteneurs sous un espace de noms utilisateur non privilégié, réduisant considérablement la surface d’attaque. Il s’agit de la configuration recommandée pour tout environnement où plusieurs utilisateurs partagent le même hôte.
Étape 5 : Référence des commandes Docker essentielles
Gestion des images
“`bash
Pull a specific image version from Docker Hub
docker pull nginx:1.27-alpine
List locally cached images
docker images
Remove a specific image
docker rmi nginx:1.27-alpine
Remove all dangling (untagged) images to reclaim disk space
docker image prune
Remove all unused images (not just dangling)
docker image prune -a
“`
Conseil de production : Utilisez toujours des tags versionnés (par ex., `nginx:1.27-alpine`) plutôt que `latest` dans tout flux de travail automatisé ou de production. Le tag `latest` est mutable — il peut pointer vers une image différente après un push dans le registre, compromettant la reproductibilité.
Cycle de vie des conteneurs
“`bash
Run a container interactively with a pseudo-TTY
docker run -it ubuntu:22.04 /bin/bash
Run a container in detached mode with port mapping and a name
docker run -d -p 8080:80 –name my-nginx nginx:1.27-alpine
List running containers
docker ps
List all containers (including stopped)
docker ps -a
Stop a running container gracefully (SIGTERM, then SIGKILL after timeout)
docker stop my-nginx
Start a stopped container
docker start my-nginx
Remove a stopped container
docker rm my-nginx
Force-remove a running container (sends SIGKILL immediately)
docker rm -f my-nginx
View real-time logs
docker logs -f my-nginx
Execute a command inside a running container
docker exec -it my-nginx /bin/sh
“`
Inspection des ressources et du système
“`bash
Display real-time resource usage statistics
docker stats
Inspect detailed container metadata (JSON)
docker inspect my-nginx
Display disk usage by Docker objects
docker system df
Remove all stopped containers, unused networks, dangling images, and build cache
docker system prune
“`
`docker system prune` est l’une des commandes de maintenance les plus importantes pour les serveurs à longue durée de fonctionnement. Sans nettoyage périodique, le cache de construction de Docker et les conteneurs arrêtés peuvent consommer des dizaines de gigaoctets sur un hôte de développement ou CI actif.
Étape 6 : Docker Compose — Orchestration d’applications multi-conteneurs
Docker Compose V2 (le `docker-compose-plugin` installé précédemment) est invoqué avec `docker compose` (avec un espace), et non avec l’ancienne syntaxe `docker-compose` (avec un tiret). Les deux syntaxes fonctionnent si vous avez le plugin installé, mais V2 est la norme actuelle.
6.1 Comprendre la structure du fichier Compose
Créez un répertoire de projet et un fichier `compose.yml` (le nom de fichier préféré dans Compose V2 ; `docker-compose.yml` reste pris en charge pour la compatibilité ascendante) :
“`bash
mkdir ~/my-web-app && cd ~/my-web-app
nano compose.yml
“`
Un exemple réaliste pour la production avec Nginx et un service backend :
“`yaml
services:
web:
image: nginx:1.27-alpine
ports:
- "8080:80"
volumes:
- ./nginx.conf:/etc/nginx/nginx.conf:ro
- ./html:/usr/share/nginx/html:ro
depends_on:
- app
restart: unless-stopped
app:
image: node:20-alpine
working_dir: /usr/src/app
volumes:
- ./app:/usr/src/app
command: node server.js
environment:
- NODE_ENV=production
restart: unless-stopped
“`
Explication des directives Compose clés :
- `restart: unless-stopped` — Le conteneur redémarre automatiquement après un crash ou un redémarrage du système, sauf s’il a été explicitement arrêté par l’opérateur. Il s’agit de la politique correcte pour les services à longue durée de fonctionnement ; `always` redémarrera même les conteneurs intentionnellement arrêtés.
- `depends_on` — Contrôle l’ordre de démarrage mais n’attend pas que le service soit *prêt* (par ex., une base de données acceptant des connexions). Pour le contrôle de disponibilité, utilisez `healthcheck` combiné avec `condition: service_healthy`.
- `volumes` avec `:ro` — Monter les fichiers de configuration en lecture seule empêche un processus de conteneur compromis de modifier sa propre configuration.
6.2 Commandes du flux de travail Compose
“`bash
Start all services in detached mode
docker compose up -d
View logs for all services
docker compose logs -f
View logs for a specific service
docker compose logs -f web
List running Compose services
docker compose ps
Scale a specific service to multiple replicas
docker compose up -d –scale app=3
Stop services without removing containers
docker compose stop
Stop and remove containers, networks, and volumes
docker compose down –volumes
Rebuild images before starting (useful after code changes)
docker compose up -d –build
“`
6.3 Vérifier le service en cours d’exécution
“`bash
curl -I http://localhost:8080
“`
Une réponse `200 OK` confirme que Nginx fonctionne correctement. Pour les services s’exécutant sur une instance VPS Hosting distante, remplacez `localhost` par l’adresse IP publique de votre serveur et assurez-vous que le port concerné est ouvert dans votre pare-feu (`ufw allow 8080/tcp`).
Étape 7 : Fondamentaux du réseau Docker
Comprendre le modèle réseau de Docker est essentiel pour créer des applications multi-conteneurs qui communiquent de manière sécurisée.
Pilotes réseau par défaut :
| Pilote | Cas d’utilisation |
|---|
| — | — |
|---|
| `bridge` | Par défaut pour les conteneurs autonomes ; espace de noms réseau isolé sur l’hôte |
|---|
| `host` | Le conteneur partage la pile réseau de l’hôte ; performances maximales, zéro isolation |
|---|
| `none` | Aucun accès réseau ; utile pour le traitement par lots ou les charges de travail sensibles à la sécurité |
|---|
| `overlay` | Réseau multi-hôtes pour les clusters Docker Swarm |
|---|
| `macvlan` | Attribue une adresse MAC au conteneur ; apparaît comme un périphérique physique sur le réseau |
|---|
Création et utilisation d’un réseau bridge personnalisé :
“`bash
Create an isolated network
docker network create my-app-network
Run containers attached to the custom network
docker run -d –name db –network my-app-network postgres:16-alpine
docker run -d –name api –network my-app-network my-api-image
Containers on the same custom bridge network can resolve each other by name
Inside 'api', you can connect to 'db' using the hostname 'db'
“`
Les réseaux bridge personnalisés fournissent une résolution DNS automatique entre les conteneurs par nom de conteneur. Le réseau `bridge` par défaut ne le fait pas — c’est une distinction essentielle qui provoque des échecs de connexion lorsque les développeurs supposent que les conteneurs sur le réseau par défaut peuvent se joindre mutuellement par nom.
Étape 8 : Données persistantes avec les volumes Docker
Les conteneurs sont éphémères par conception. Toute donnée écrite dans le système de fichiers d’un conteneur est perdue lorsque le conteneur est supprimé. Pour le stockage persistant, utilisez des volumes ou des montages liés.
“`bash
Create a named volume
docker volume create pgdata
Use the volume with a container
docker run -d
–name postgres-db
-e POSTGRES_PASSWORD=securepassword
-v pgdata:/var/lib/postgresql/data
postgres:16-alpine
List volumes
docker volume ls
Inspect a volume (shows mount point on host)
docker volume inspect pgdata
Remove unused volumes
docker volume prune
“`
Volumes vs. montages liés :
| Fonctionnalité | Volume nommé | Montage lié |
|---|
| — | — | — |
|---|
| Géré par Docker | Oui | Non |
|---|
| Chemin hôte requis | Non | Oui |
|---|
| Portable entre hôtes | Oui (avec pilotes de volume) | Non |
|---|
| Idéal pour | Données de base de données, état de l’application | Code de développement, fichiers de configuration |
|---|
| Mécanisme de sauvegarde | `docker run –volumes-from` | Outils système de fichiers standard |
|---|
Étape 9 : Maintenir Docker à jour
Le dépôt officiel de Docker gère les mises à jour via le mécanisme standard `apt` :
“`bash
sudo apt update
sudo apt upgrade -y
“`
Pour mettre à jour uniquement les paquets liés à Docker sans mettre à niveau l’ensemble du système :
“`bash
sudo apt install –only-upgrade docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin
“`
Consultez les notes de version de Docker avant les mises à niveau de versions majeures, en particulier pour les modifications apportées au pilote de stockage, à la gestion des versions cgroup ou aux versions d’API obsolètes susceptibles d’affecter les fichiers `compose.yml` existants.
Docker vs. approches alternatives de conteneurisation
| Fonctionnalité | Docker Engine | Podman | LXC/LXD | containerd (autonome) |
|---|
| — | — | — | — | — |
|---|
| Architecture du démon | Démon centralisé | Sans démon | Basé sur un démon | Basé sur un démon |
|---|
| Prise en charge rootless | Oui (v20+) | Natif | Limitée | Oui |
|---|
| Prise en charge Docker Compose | Natif | Via `podman-compose` | Non | Non |
|---|
| Conformité OCI | Oui | Oui | Non (format LXC) | Oui |
|---|
| Intégration Kubernetes | Via le shim CRI-dockerd | CRI natif | Non | CRI natif |
|---|
| Prise en charge Windows/macOS | Docker Desktop | Limitée | Non | Non |
|---|
| Meilleure adéquation | Développement général et production | Axé sur la sécurité, rootless | Conteneurs système, VMs | Nœuds Kubernetes |
|---|
Pour les équipes exécutant des charges de travail conteneurisées à grande échelle sur du matériel bare metal, un environnement Dedicated Servers vous donne un contrôle total sur les paramètres du noyau, la planification des E/S de stockage et la configuration réseau — tous ces éléments affectant directement la densité des conteneurs et les performances.
Liste de contrôle pour le durcissement en production
Avant d’exécuter Docker dans un environnement de production, traitez les points suivants :
Configuration du démon (`/etc/docker/daemon.json`) :
“`json
{
"log-driver": "json-file",
"log-opts": {
"max-size": "10m",
"max-file": "3"
},
"storage-driver": "overlay2",
"userns-remap": "default",
"live-restore": true,
"no-new-privileges": true
}
“`
- `log-opts` avec `max-size` et `max-file` : Sans rotation des journaux, les fichiers journaux JSON de Docker rempliront votre disque. C’est l’une des causes les plus courantes de pannes de serveur inattendues sur les hôtes conteneurisés.
- `userns-remap: "default"` : Active le remappage des espaces de noms utilisateur, de sorte que le root du conteneur (UID 0) corresponde à un UID non privilégié sur l’hôte.
- `live-restore: true` : Permet aux conteneurs de continuer à fonctionner si le démon Docker plante ou est redémarré lors d’une mise à niveau — essentiel pour une maintenance sans interruption de service.
- `no-new-privileges: true` : Empêche les processus de conteneur d’obtenir des privilèges supplémentaires via des binaires `setuid` ou `setgid`.
Considérations réseau et pare-feu :
Docker manipule `iptables` directement et contourne les règles `ufw` par défaut. Un conteneur avec un port publié (`-p 8080:80`) sera accessible depuis Internet même si `ufw deny 8080` est défini. Pour appliquer les règles `ufw` sur la manipulation `iptables` de Docker, ajoutez `"iptables": false` à `daemon.json` et gérez le routage manuellement, ou utilisez le `–network host` de Docker avec des règles `ufw` explicites.
Pour les projets nécessitant une terminaison HTTPS, associez votre application conteneurisée à un proxy inverse correctement configuré (Nginx ou Traefik) et un certificat valide. Les SSL Certificates sont un prérequis pour tout service web de production s’exécutant derrière une pile conteneurisée.
Si votre charge de travail implique l’inférence d’apprentissage automatique, la diffusion de modèles ou le traitement de données accéléré par GPU dans des conteneurs, le NVIDIA Container Toolkit s’intègre directement avec Docker Engine. Le GPU Hosting fournit le matériel sous-jacent requis pour ces charges de travail.
Pour les équipes gérant plusieurs projets avec une gestion de conteneurs basée sur le web, le VPS with cPanel offre un environnement de panneau de contrôle géré qui peut compléter les déploiements basés sur Docker pour des piles d’applications plus simples.
Points techniques clés et matrice de décision
Quand utiliser Docker sur un VPS plutôt que sur un serveur dédié :
- Utilisez un VPS pour les environnements de développement, la mise en scène et les charges de travail de production à trafic faible à moyen où la densité des conteneurs est de 10 à 50 conteneurs.
- Utilisez un serveur dédié lorsque la densité des conteneurs dépasse 50 instances, lorsque vous avez besoin de performances d’E/S prévisibles (pas d’effet de voisin bruyant), ou lorsque le réglage des paramètres du noyau (`sysctl`) est requis pour votre charge de travail.
Liste de contrôle opérationnelle avant la mise en production :
- Configurer la rotation des journaux dans `daemon.json` (`max-size`, `max-file`)
- Activer `live-restore` pour survivre aux redémarrages du démon sans interruption des conteneurs
- Utiliser des volumes nommés, et non des montages liés, pour les données de services avec état
- Épingler les versions d’images dans tous les fichiers `compose.yml` — ne jamais utiliser `latest` en production
- Activer `userns-remap` ou exécuter Docker rootless sur les hôtes multi-locataires
- Auditer les règles `iptables` après l’installation de Docker pour confirmer que la politique de pare-feu n’est pas contournée
- Définir `restart: unless-stopped` sur tous les services à longue durée de fonctionnement
- Exécuter `docker system prune` dans une tâche cron planifiée pour éviter l’épuisement du disque
- Utiliser des réseaux bridge personnalisés pour toutes les communications inter-conteneurs — ne jamais s’appuyer sur le bridge par défaut pour la découverte de services
FAQ
Docker sur Ubuntu utilise-t-il `systemd` ou `cgroupfs` comme pilote cgroup par défaut ?
Depuis Docker Engine 20.10, le pilote cgroup par défaut sur les systèmes basés sur `systemd` (y compris toutes les versions LTS modernes d’Ubuntu) est `systemd`. Cela s’aligne sur les exigences de Kubernetes et évite l’instabilité causée par l’exécution simultanée de deux gestionnaires cgroup. Vous pouvez vérifier avec `docker info | grep -i cgroup`.
Quelle est la différence entre `docker compose down` et `docker compose stop` ?
`docker compose stop` arrête les conteneurs en cours d’exécution mais les préserve ainsi que leurs réseaux associés. `docker compose down` arrête les conteneurs puis les supprime ainsi que les réseaux créés par Compose. Ajouter `–volumes` à `down` supprime également les volumes nommés définis dans le fichier Compose — utilisez cet indicateur avec précaution en production, car il supprime définitivement les données persistantes.
Pourquoi Docker contourne-t-il les règles de pare-feu `ufw` sur Ubuntu ?
Docker insère ses propres règles `iptables` dans les chaînes `DOCKER` et `DOCKER-USER`, qui sont évaluées avant les règles de la chaîne `INPUT` de `ufw`. Cela signifie qu’un port publié avec `-p` est accessible depuis Internet quelle que soit la politique `ufw`. La bonne solution est d’ajouter des règles directement à la chaîne `DOCKER-USER`, ou de lier les ports publiés à une interface spécifique (par ex., `-p 127.0.0.1:8080:80`) lorsque l’accès externe n’est pas requis.
Comment limiter le CPU et la mémoire qu’un conteneur Docker peut consommer ?
Utilisez des indicateurs de contrainte de ressources à l’exécution : `docker run –memory="512m" –cpus="1.5" my-image`. Dans Compose, définissez-les sous la clé `deploy.resources` (Compose V2) ou les clés de niveau supérieur `mem_limit` et `cpus`. Sans limites, un seul conteneur incontrôlé peut épuiser les ressources de l’hôte et faire tomber tous les autres conteneurs sur le même hôte.
Puis-je exécuter Docker dans un conteneur Docker (Docker-in-Docker) ?
Oui, mais cela est fortement déconseillé pour une utilisation en production. Le modèle courant pour les pipelines CI consiste à monter le socket Docker de l’hôte (`-v /var/run/docker.sock:/var/run/docker.sock`) dans le conteneur CI, ce qui donne au conteneur un contrôle total sur le démon Docker de l’hôte — un risque de sécurité important. Une alternative plus sûre consiste à utiliser l’indicateur `–allow security.insecure` de BuildKit ou des outils dédiés comme Kaniko ou Buildah, qui construisent des images OCI sans nécessiter de démon Docker.
