Couverture de l'article Tuto Docker - Les commandes et Docker (partie 3)
Retour aux articles

L'agence

WanadevStudio

Tuto Docker - Les commandes et Docker (partie 3)

Article initialement publié en 2015, mis à jour en octobre 2026.

Cet article fait partie d'une série de billets portant sur Docker et son environnement:

Dans ce troisième article, nous allons regarder ce qui se cache derrière la commande docker : le Docker Engine et son API. Si vous n'avez pas lu les deux articles précédents, je vous conseille de le faire avant d'entamer celui-ci.

Sommaire

Introduction

Depuis que je travaille avec Docker, je n'ai cessé de découvrir des facettes peu visibles pour les non-initiés. C'est après deux meetups à Lyon (le premier présenté par David Gageot, le second par Jérôme Petazzoni dans le cadre du Docker Tour de France) que j'ai compris certaines subtilités de son fonctionnement.

Quand on installe Docker, on installe en réalité, de manière transparente, deux choses:

  • le client : la commande docker que vous tapez dans votre terminal, et que nous avons utilisée dans la partie 2
  • le serveur : le Docker Engine, un service (un démon) qui tourne en arrière-plan et fait tout le vrai travail. Sur Linux, il vous arrivera d'ailleurs de devoir le démarrer : sudo systemctl start docker.

Le client ne fait qu'envoyer des requêtes au serveur. Détaillons cette partie serveur.

Docker, un service avant tout

L'architecture du Docker Engine

Le Docker Engine est lui-même composé de plusieurs briques, qui s'appellent les unes les autres :

docker (client CLI)
   │  appels HTTP vers l'API
   ▼
dockerd (le démon Docker : images, réseaux, volumes, builds…)
   │
   ▼
containerd (gestion du cycle de vie des conteneurs)
   │
   ▼
runc (crée le conteneur via les namespaces et cgroups du noyau)
  • dockerd est le démon Docker. Il expose l'API, gère les images, les volumes, les réseaux et les builds.
  • containerd gère le cycle de vie des conteneurs (création, démarrage, arrêt). C'est un projet open source à part entière, utilisé aussi par Kubernetes.
  • runc est le petit outil qui crée réellement le conteneur, en s'appuyant sur les namespaces et les cgroups du noyau Linux (souvenez-vous de la partie 1). Il implémente le standard OCI.

Ce découpage a un avantage : vous pouvez redémarrer ou mettre à jour dockerd sans forcément arrêter vos conteneurs (avec l'option live-restore).

Une API avant tout

Comme tout service, avant de répondre à des commandes user-friendly, le Docker Engine expose une API HTTP : la Docker Engine API. Elle est versionnée et échange du JSON.

Par défaut, cette API écoute sur un socket Unix local : /var/run/docker.sock. Chaque commande docker que vous tapez se traduit par une ou plusieurs requêtes HTTP sur ce socket.

Vous pouvez d'ailleurs l'interroger directement, sans passer par le client docker:

# Version du Docker Engine
$ curl --unix-socket /var/run/docker.sock http://localhost/version

# Liste des conteneurs en cours, l'équivalent de "docker ps"
$ curl --unix-socket /var/run/docker.sock http://localhost/containers/json

Vous obtenez du JSON brut : exactement ce que reçoit le client docker avant de le mettre en forme pour vous.

Le point technique !

Avoir accès au socket Docker, c'est avoir les droits root sur la machine : quiconque peut parler à l'API peut lancer un conteneur qui monte le disque de l'hôte. C'est pour cela que seuls root et les membres du groupe docker y ont accès.

Ajouter un utilisateur au groupe docker revient donc à lui donner les droits root. Et monter /var/run/docker.sock dans un conteneur (ce que font certains outils de monitoring ou de CI) donne à ce conteneur le contrôle total de l'hôte : faites-le en connaissance de cause. Pour limiter les risques, Docker propose aussi un mode rootless, où le démon tourne sans les droits root.

Configurer le démon

Le démon se configure principalement via le fichier /etc/docker/daemon.json. Par exemple :

{
  "data-root": "/mnt/docker-data",
  "log-driver": "json-file",
  "log-opts": {
    "max-size": "10m",
    "max-file": "3"
  },
  "registry-mirrors": ["https://mirror.example.com"],
  "live-restore": true
}
  • data-root : l'emplacement où Docker stocke images, conteneurs et volumes (par défaut /var/lib/docker) ;
  • log-driver et log-opts : la gestion des logs des conteneurs. Limiter leur taille évite de remplir le disque, un grand classique en production !
  • registry-mirrors : un miroir de registry, par exemple pour un réseau d'entreprise ;
  • live-restore : garder les conteneurs actifs pendant un redémarrage du démon.

Après modification, on redémarre le service avec sudo systemctl restart docker. La référence de dockerd liste toutes les options disponibles.

Piloter un Docker distant

Puisque le client docker ne fait que parler à une API, rien ne l'oblige à parler au Docker de votre machine. Il peut tout aussi bien piloter le Docker Engine d'un serveur distant.

La bonne méthode : les contextes Docker et SSH

La méthode recommandée passe par SSH, que vous utilisez déjà pour administrer vos serveurs. Les contextes Docker permettent d'enregistrer plusieurs cibles et de passer de l'une à l'autre :

# Déclarer le serveur de production
$ docker context create prod --docker "host=ssh://deploy@prod.example.com"

# Lancer une commande sur la prod, ponctuellement
$ docker --context prod ps

# Ou basculer toutes les commandes suivantes sur la prod
$ docker context use prod
$ docker ps

# Revenir en local
$ docker context use default

Pas de port supplémentaire à ouvrir, pas de certificats à gérer : l'authentification et le chiffrement sont ceux de votre connexion SSH. On peut aussi, plus simplement, utiliser la variable d'environnement DOCKER_HOST=ssh://deploy@prod.example.com.

Et cela fonctionne aussi avec Compose : docker --context prod compose up -d déploie votre stack sur le serveur distant.

Attention !

Il est techniquement possible de faire écouter le démon sur un port TCP (-H tcp://0.0.0.0:2375). Ne le faites jamais sans TLS : vous offririez un accès root à votre serveur à quiconque peut joindre ce port, et des robots scannent Internet en permanence à la recherche de ces API ouvertes. Si vous avez vraiment besoin d'un accès TCP, suivez le guide Protect the Docker daemon socket (TLS avec certificats clients, port 2376). Sinon, utilisez SSH.

Un peu plus loin dans l'utilisation de l'API

Taper des commandes à la main dans un terminal, c'est une chose. Mais peut-être aurez-vous besoin de créer une application qui gère vos images et vos conteneurs plus facilement, ou qui automatise certaines tâches.

À l'époque, j'avais testé l'API avec un petit projet « maison », docker-panel : une application web qui permettait de mettre en pause et d'arrêter des conteneurs. C'est peu, mais c'est un extrait de ce que l'on peut faire.

Aujourd'hui, pas besoin d'appeler l'API HTTP à la main : il existe des SDK officiels, en Go et en Python, ainsi que de nombreuses bibliothèques communautaires pour les autres langages. En Python, par exemple:

import docker

client = docker.from_env()  # utilise le socket local, ou DOCKER_HOST

for container in client.containers.list():
    print(container.name, container.status)

Des interfaces graphiques

Même si Docker est d'abord un outil en ligne de commande, il est parfois agréable d'avoir un peu de visuel. Plusieurs outils s'appuient sur l'API :

  • Docker Desktop, qui intègre une interface pour gérer images, conteneurs et volumes.
  • Portainer, une interface web très répandue pour gérer un ou plusieurs serveurs Docker.
  • lazydocker, une interface dans le terminal, pour les barbus qui ne veulent pas quitter leur console.

Surveiller ses conteneurs

Pour le monitoring, Docker s'appuie sur les cgroups du noyau, qui mesurent la consommation de ressources de chaque conteneur :

  • docker stats affiche en direct la consommation CPU, mémoire, réseau et disque de vos conteneurs.
  • cAdvisor collecte ces mêmes métriques en continu.
  • le démon peut exposer ses propres métriques au format Prometheus (option metrics-addr dans daemon.json), pour les afficher ensuite dans Grafana.

Et pour plusieurs serveurs ?

Vous pouvez imaginer toutes sortes d'applications, jusqu'à piloter un cluster de serveurs depuis une seule console. Pour cela, inutile de réinventer la roue:

  • Docker Swarm, intégré au Docker Engine (docker swarm init), permet de regrouper plusieurs serveurs et d'y déployer des services, avec une syntaxe proche de Compose. Simple et efficace pour des besoins modestes.
  • Kubernetes est devenu le standard pour orchestrer des conteneurs à grande échelle. Plus puissant, mais aussi beaucoup plus complexe: il mérite sa propre série d'articles !

Conclusion

Docker est avant tout un service, le Docker Engine, qui expose une API. La commande docker n'est qu'un client parmi d'autres: vous pouvez piloter un serveur distant avec les contextes et SSH, automatiser vos tâches avec les SDK, ou utiliser des interfaces graphiques comme Portainer.

N'oubliez pas qu'accéder à cette API revient à être root sur la machine : protégez-la en conséquence.

Pour aller plus loin, toute la documentation de l'API est disponible ici.