🖥 Infrastructure

Installer Docker sur WSL Debian

📅 15 juin 202520 min de lecture
dockerwsl2debianrootless

Docker Root vs Rootless

️ Risques du Docker root
  • Le démon s'exécute avec les privilèges maximums
  • Un conteneur compromis peut accéder à l'hôte entier
  • Modification possible des fichiers système
  • Escalade de privilèges jusqu'à root possible
Avantages de Rootless
  • Démon et conteneurs sans privilèges root
  • En cas de faille, droits limités à l'utilisateur
  • Isolation stricte entre utilisateurs
  • Recommandé pour tout environnement

Prérequis

  • Windows 10/11 avec WSL2 activé
  • Une distribution Debian installée depuis le Microsoft Store
  • Un accès sudo

WSL1 vs WSL2 Assurez-vous d'utiliser WSL2 et non WSL1. Docker rootless et les performances réseau sont bien meilleurs sous WSL2. Vérifiez avec wsl -l -v depuis PowerShell.

Première installation ? Si Docker était déjà installé sur le système, désinstallez les anciennes versions avant de commencer :

sudo apt remove docker docker-engine docker.io containerd runc

01. Mise à jour du système

Avant toute chose, on s'assure que le système est à jour.

sudo apt update
sudo apt upgrade
✅ Vérification

Aucune erreur ne doit apparaître. Si apt update échoue, vérifiez votre connexion réseau avec ping 8.8.8.8.

02. Installation de bash-completion

Pour profiter de l'autocomplétion dans le terminal.

sudo apt install bash-completion

Vérifiez ensuite que les lignes suivantes sont présentes et décommentées dans votre ~/.bashrc :

if [ -f /etc/bash_completion ]; then
    . /etc/bash_completion
fi
source ~/.bashrc
✅ Vérification

Tapez docker puis appuyez sur Tab — vous devriez voir les sous-commandes s'afficher (après l'installation de Docker).

Tip — Zsh Pour une autocomplétion encore plus puissante (suggestions en grisé, complétion git, docker…), envisagez Zsh avec Oh My Zsh :

sudo apt install zsh && sh -c "$(curl -fsSL https://raw.githubusercontent.com/ohmyzsh/ohmyzsh/master/tools/install.sh)"

03. Création des utilisateurs et groupes

On crée un utilisateur dédié à Docker ainsi qu'un groupe developers pour gérer les accès proprement.

sudo adduser admin_docker
sudo groupadd developers
sudo usermod -aG developers admin_docker
sudo usermod -aG developers developer

On crée également le répertoire de données des conteneurs :

sudo mkdir -p /opt/docker-data

Pourquoi un utilisateur dédié ? Séparer l'utilisateur qui fait tourner Docker de votre utilisateur courant est une bonne pratique de sécurité, surtout en mode rootless. Cela isole clairement les permissions et les données Docker.

✅ Vérification
getent group developers

04. Installation des dépendances

Dépendances de base

sudo apt install curl wget gnupg ca-certificates lsb-release -y

Dépendances pour Docker rootless et le réseau

sudo apt install apt-transport-https uidmap dbus-user-session fuse-overlayfs slirp4netns iproute2 iptables acl systemd-container

À quoi servent ces paquets ?

  • uidmap — remappage des UIDs pour le mode rootless
  • fuse-overlayfs — driver de système de fichiers pour rootless
  • slirp4netns — réseau en espace utilisateur pour rootless
  • dbus-user-session — nécessaire pour systemd user
  • acl — gestion fine des permissions sur les fichiers

05. Ajout de la clé GPG Docker

Cette étape configure le dépôt officiel Docker avec vérification GPG, ce qui garantit que les paquets téléchargés sont authentiques et n'ont pas été modifiés.

sudo curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg
✅ Vérification — empreinte de la clé

Vérifiez que l'empreinte correspond bien à la clé officielle Docker :

gpg --show-keys /usr/share/keyrings/docker-archive-keyring.gpg

L'empreinte officielle Docker est : 9DC8 5822 9FC7 DD38 854A E2D8 8D81 803C 0EBF CD88

✅ Vérification — fichier présent
ls -lh /usr/share/keyrings/docker-archive-keyring.gpg

Erreur possible Si curl échoue avec une erreur SSL, vérifiez que ca-certificates est bien installé :

sudo apt install --reinstall ca-certificates

06. Ajout du dépôt Docker

On ajoute le dépôt officiel Docker correspondant à votre architecture et version de Debian.

echo "deb [arch=$(dpkg --print-architecture) \
signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] \
https://download.docker.com/linux/debian \
$(lsb_release -cs) stable" | \
sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
✅ Vérification
cat /etc/apt/sources.list.d/docker.list

Vous devriez voir :

deb [arch=amd64 signed-by=...docker-archive-keyring.gpg] https://download.docker.com/linux/debian trixie stable

Erreurs classiques dans cette commande

  • Simples quotes '...' au lieu de doubles "..." — les substitutions $(...) ne s'exécutent pas
  • Écrire ${dpkg ...} au lieu de $(dpkg ...) — mélange des syntaxes
  • Faute de frappe : /usr/share/keyring/ au lieu de /usr/share/keyrings/ (avec un s)

07. Installation de Docker

On met à jour la liste des paquets pour inclure le nouveau dépôt, puis on installe Docker et ses plugins.

sudo apt update
 
sudo apt install -y \
  docker-ce \
  docker-ce-cli \
  containerd.io \
  docker-buildx-plugin \
  docker-ce-rootless-extras \
  uidmap \
  dbus-user-session

À quoi servent ces paquets ?

  • docker-ce — le démon Docker (Community Edition)
  • docker-ce-cli — l'outil en ligne de commande docker
  • containerd.io — le runtime de conteneurs
  • docker-buildx-plugin — builds multi-architecture
  • docker-ce-rootless-extras — outils nécessaires au mode rootless

08. Vérification de l'installation

docker --version
docker compose version
✅ Résultat attendu
Docker version 29.3.0, build ...
Docker Compose version v5.1.1

09. Ajout de l'utilisateur au groupe Docker

On ajoute admin_docker au groupe docker pour lui permettre d'exécuter des commandes Docker sans sudo.

sudo usermod -aG docker admin_docker

Ce changement de groupe ne prend effet qu'à la prochaine connexion de l'utilisateur. Il suffit d'ouvrir un nouveau shell.

✅ Vérification
groups admin_docker

Configuration du mode rootless

10. Configuration des UIDs/GIDs subordonnés

Ces plages permettent au démon Docker rootless de mapper les utilisateurs à l'intérieur des conteneurs sans avoir besoin de droits root.

echo "admin_docker:100000:65536" | sudo tee -a /etc/subuid
echo "admin_docker:100000:65536" | sudo tee -a /etc/subgid

La valeur 65536 représente le nombre d'UIDs réservés (de 100000 à 165535). C'est la plage standard recommandée par Docker.

Activation du linger

Le linger permet aux services systemd de l'utilisateur de démarrer automatiquement sans qu'il soit connecté.

sudo loginctl enable-linger admin_docker

Désactivation du Docker root

On désactive le service Docker root pour n'utiliser que la version rootless.

sudo systemctl disable --now docker.service docker.socket

11. Vérifications de la configuration rootless

✅ Vérifier les subuid/subgid
grep admin_docker /etc/subuid /etc/subgid

Résultat attendu :

/etc/subuid:admin_docker:100000:65536
/etc/subgid:admin_docker:100000:65536
✅ Vérifier le linger
loginctl show-user admin_docker | grep Linger

Résultat attendu : Linger=yes

12. Basculer vers l'utilisateur admin_docker

On utilise machinectl pour ouvrir un shell complet en tant que admin_docker, avec son environnement systemd user correctement initialisé.

sudo machinectl shell admin_docker@

Pourquoi machinectl et pas su ? su - admin_docker n'initialise pas correctement l'environnement systemd user (notamment XDG_RUNTIME_DIR). machinectl shell ouvre une vraie session utilisateur complète, indispensable pour Docker rootless.

✅ Vérifier XDG_RUNTIME_DIR
echo $XDG_RUNTIME_DIR

Vous devriez obtenir quelque chose comme /run/user/1002.

Si XDG_RUNTIME_DIR est vide Le linger n'est pas actif ou la session n'est pas correctement initialisée. Relancez : sudo loginctl enable-linger admin_docker

13. Installation de Docker rootless

On lance le script d'installation rootless depuis la session admin_docker.

dockerd-rootless-setuptool.sh install

Erreur — socket rootful encore présent Si vous obtenez [ERROR] Aborting because rootful Docker (/var/run/docker.sock) is running and accessible, le socket est encore présent sur le disque. Supprimez-le et relancez :

sudo rm /var/run/docker.sock
dockerd-rootless-setuptool.sh install

14. Configuration des variables d'environnement

Pour que les commandes docker utilisent bien le socket rootless, ajoutez ces variables dans le ~/.bashrc de admin_docker.

cat >> ~/.bashrc << 'EOF'
 
# Docker Rootless
export PATH=$HOME/bin:$PATH
export DOCKER_HOST=unix://$XDG_RUNTIME_DIR/docker.sock
EOF
 
source ~/.bashrc

Sans DOCKER_HOST, le client Docker cherche par défaut /var/run/docker.sock (le socket root). Cette variable lui indique d'utiliser le socket de l'utilisateur courant.

15. Démarrage automatique de Docker rootless

systemctl --user enable docker
systemctl --user start docker

Erreur — Unit docker.service does not exist Les variables d'environnement ne sont pas encore chargées. Définissez-les manuellement, rechargez systemd, puis réessayez :

export PATH=$HOME/bin:$PATH
export DOCKER_HOST=unix://$XDG_RUNTIME_DIR/docker.sock
systemctl --user daemon-reload
systemctl --user enable docker
systemctl --user start docker

Pour éviter ce problème à chaque reconnexion, assurez-vous que les variables sont dans ~/.bashrc (voir étape 14).

✅ Vérification
systemctl --user status docker

Vous devriez voir active (running).

16. Vérification finale

docker info
docker info | grep -i rootless

✅ Points importants à vérifier

Warning cgroups (normal sous WSL2)

WARNING: Running in rootless-mode without cgroups...
WARNING: Support for cgroup v1 is deprecated... May 2029

Ce warning est sans conséquence immédiate. Pour l'éliminer, activez cgroup v2 dans %USERPROFILE%\.wslconfig sous Windows :

[wsl2]
kernelCommandLine = cgroup_no_v1=all

Puis : wsl --shutdown. Vérifiez avec cat /sys/fs/cgroup/cgroup.controllers.

⚠️ Cette modification affecte toutes vos distributions WSL.

17. Premier test

On vérifie que Docker est pleinement fonctionnel en lançant le conteneur de test officiel.

docker run --rm hello-world

Si vous voyez le message Hello from Docker! , l'installation est complète et opérationnelle.

L'option --rm supprime automatiquement le conteneur après son exécution. Utile pour les tests ponctuels afin de ne pas accumuler des conteneurs stoppés.

Configuration des permissions et réseaux

18. Permissions des données Docker

On configure le répertoire qui contiendra les données persistantes des conteneurs (volumes).

sudo chown -R admin_docker:developers /opt/docker-data/ignis/
sudo chmod -R 2775 /opt/docker-data/ignis/

Comprendre le 2775

  • 2 (setgid) — tout nouveau fichier héritera automatiquement du groupe developers
  • 7 — lecture, écriture, exécution pour le propriétaire
  • 7 — lecture, écriture, exécution pour le groupe
  • 5 — lecture et exécution pour les autres (pas d'écriture)
✅ Vérification
ls -la /opt/docker-data/

Vous devriez voir drwxrwsr-x (le s indique que le setgid est actif).

19. Configuration sécurisée du démon Docker

On crée un fichier daemon.json pour appliquer des paramètres de sécurité et de logs au démon Docker rootless.

mkdir -p ~/.config/docker
 
cat > ~/.config/docker/daemon.json << 'EOF'
{
  "storage-driver": "fuse-overlayfs",
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  },
  "no-new-privileges": true,
  "default-ulimits": {
    "nofile": {
      "Name": "nofile",
      "Hard": 65536,
      "Soft": 65536
    }
  }
}
EOF
 
systemctl --user restart docker

À quoi servent ces paramètres ?

  • storage-driver: fuse-overlayfs — driver optimisé pour le mode rootless
  • log-driver + log-opts — limite la taille des logs (3 fichiers de 10 Mo max)
  • no-new-privileges — empêche les conteneurs d'acquérir de nouveaux privilèges
  • default-ulimits — définit une limite raisonnable du nombre de fichiers ouverts

20. Création des réseaux Docker

On crée deux réseaux distincts selon leur rôle.

Réseau partagé — traefik-network

Réseau sur lequel Traefik sera connecté. Les conteneurs accessibles depuis l'extérieur y sont rattachés.

docker network create \
  --driver bridge \
  --subnet 172.247.193.0/24 \
  --gateway 172.247.193.254 \
  --opt com.docker.network.bridge.name=traefik-br \
  --opt com.docker.network.driver.mtu=1500 \
  traefik-network

Réseau isolé — ignis-network

Réseau --internal : aucun trafic entrant/sortant vers l'extérieur. Uniquement pour les services backend (BDD, cache…).

docker network create \
  --driver bridge \
  --internal \
  --subnet 172.247.194.0/24 \
  --gateway 172.247.194.254 \
  --opt com.docker.network.bridge.name=ignis-br \
  ignis-network

external: true vs --internal Ce sont deux concepts distincts : external: true dans le compose signifie que le réseau existe déjà (créé manuellement). --internal signifie que le réseau est isolé d'internet. Les deux s'appliquent en même temps pour ignis-network.

✅ Vérification
docker network ls
docker network inspect traefik-network
docker network inspect ignis-network

21. Redémarrage

On redémarre pour s'assurer que toutes les modifications (groupes, linger, systemd) sont bien prises en compte.

sudo reboot

WSL Sous WSL, sudo reboot ferme simplement la session. Relancez votre terminal Windows. Vous pouvez aussi faire wsl --shutdown depuis PowerShell.

Commandes utiles au quotidien

Conteneurs

docker ps                        # Lister les conteneurs en cours d'exécution
docker ps -a                     # Lister tous les conteneurs (y compris stoppés)
docker start <nom>               # Démarrer un conteneur stoppé
docker stop <nom>                # Arrêter un conteneur
docker restart <nom>             # Redémarrer un conteneur
docker rm <nom>                  # Supprimer un conteneur stoppé
docker rm -f <nom>               # Forcer la suppression (même si actif)
docker logs <nom>                # Afficher les logs d'un conteneur
docker logs -f <nom>             # Suivre les logs en temps réel
docker exec -it <nom> bash       # Ouvrir un shell dans un conteneur actif
docker inspect <nom>             # Afficher toutes les infos d'un conteneur
docker stats                     # Voir la consommation CPU/RAM en temps réel

Images

docker images                    # Lister les images locales
docker pull <image>              # Télécharger une image
docker rmi <image>               # Supprimer une image
docker image prune               # Supprimer les images non utilisées
docker scout cves <image>        # Scanner une image pour les vulnérabilités

Volumes

docker volume ls                 # Lister les volumes
docker volume inspect <nom>      # Détails d'un volume
docker volume rm <nom>           # Supprimer un volume
docker volume prune              # Supprimer les volumes non utilisés
 
# Sauvegarder un volume
docker run --rm \
  -v <nom-volume>:/data \
  -v $(pwd):/backup \
  alpine tar czf /backup/backup.tar.gz /data

Nettoyage

docker system df                 # Voir l'espace utilisé par Docker
docker system prune              # Supprimer conteneurs, images et réseaux non utilisés
docker system prune -a --volumes # Nettoyage complet (attention, irréversible)

Docker Compose

docker compose up -d             # Démarrer les services en arrière-plan
docker compose down              # Arrêter et supprimer les conteneurs
docker compose down -v           # Idem + suppression des volumes
docker compose ps                # État des services
docker compose logs -f           # Suivre les logs de tous les services
docker compose pull              # Mettre à jour les images
docker compose restart           # Redémarrer les services

Réseaux

docker network ls                              # Lister tous les réseaux
docker network inspect <nom>                   # Détails d'un réseau
docker network create <nom>                    # Créer un réseau bridge simple
docker network rm <nom>                        # Supprimer un réseau
docker network prune                           # Supprimer les réseaux non utilisés
docker network connect <réseau> <conteneur>    # Connecter un conteneur
docker network disconnect <réseau> <conteneur> # Déconnecter un conteneur
ip link show                                   # Voir les interfaces réseau

Service Docker rootless

systemctl --user status docker   # État du service Docker
systemctl --user restart docker  # Redémarrer le démon Docker
systemctl --user stop docker     # Arrêter le démon Docker
journalctl --user -u docker      # Logs du démon Docker

Erreurs fréquentes et solutions

ErreurCauseSolution
permission denied /var/run/docker.sockUtilisateur pas dans le groupe dockersudo usermod -aG docker $USER puis reconnexion
Cannot connect to the Docker daemonLe démon Docker n'est pas démarrésystemctl --user start docker
XDG_RUNTIME_DIR not setSession mal initialiséeUtiliser machinectl shell au lieu de su
rootful Docker is running and accessibleSocket /var/run/docker.sock présentsudo rm /var/run/docker.sock
Tab ne complète pasbash-completion absent ou non chargésudo apt install bash-completion + vérifier ~/.bashrc
lsb_release: command not foundPaquet absentsudo apt install lsb-release
DOCKER_HOST non définiVariables d'env manquantesVérifier ~/.bashrc et relancer source ~/.bashrc

Checklist de sécurité

  • Docker Rootless installé et fonctionnel (docker info | grep rootless)
  • Dépôt officiel avec clé GPG vérifiée
  • no-new-privileges activé dans daemon.json
  • Logs limités (max-size, max-file) dans daemon.json
  • Conteneurs tournant avec un utilisateur non-root
  • Filesystem read_only activé là où c'est possible
  • Réseaux isolés pour le backend (--internal)
  • Secrets dans .env (non commité dans git)
  • Health checks configurés sur les conteneurs critiques
  • Images scannées pour les vulnérabilités (docker scout cves)
  • Sauvegardes des volumes en place