Requêter l'API du Docker Engine

Requêter l'API du Docker Engine

Lorsque nous utilisons les commandes Docker, en réalité, il s'agit tout simplement d'un client qui interroge une API. Regardons dans cet article comment interroger l'API du Docker Engine sans utiliser le client Docker.

Introduction

Nous le savons, l'architecture de Docker est un peu complexe aux premiers abords. Il embarque plein de composants avec notamment le Docker Engine, le Docker Proxy ou encore le Docker Daemon.
Voici un schéma rappelant une partie de l'architecture de Docker :

Docker Architecture

Intérêt

Le fait d'interroger l'API du Docker Engine n'est pas juste là pour faire joli. En effet, cela présente un réel intérêt dans certains cas. En voici une liste non exhaustive :

  • Pouvoir requêter l'API sans installer le client Docker.
  • Intégration dans des scripts ou des outils d'automatisation.
  • Gain de performance : L'utilisation de l'API du Docker Engine peut s'avérer plus rapide selon la requête effectuée, et élimine la surcharge liée au traitement des requêtes par le client.
  • Accès à des informations plus détaillées remontées par l'API et non pas par le client Docker.
  • Obtenir les informations dans un même format (JSON principalement).

Les conteneurs

Place à la pratique avec des requêtes API en utilisant le client HTTP curl.
Dans chacune des requêtes, je déclare au préalable une variable api_version afin de récupérer la version de l'API de Docker. Il est tout à fait possible d'adapter ces requêtes dans d'autres langages de programmation comme le GO ou encore le Python. Il est également possible de se connecter à la socket unix d'un autre Daemon Docker.

Pour afficher la liste des conteneurs en cours d'exécution :

api_version=$(docker version --format '{{.Client.APIVersion}}') ; curl -s --unix-socket /var/run/docker.sock http:/v${api_version}/containers/json
Voici l'équivalent avec le client Docker :
docker ps

Pour créer un conteneur, cela s'effectue en plusieurs étapes, et donc plusieurs requêtes. Il faut d'abord créer le conteneur, puis le lancer. La première requête à exécuter est celle-ci :

api_version=$(docker version --format '{{.Client.APIVersion}}') ; curl --unix-socket /var/run/docker.sock -H "Content-Type: application/json" -d '{"Image": "hello-world"}' http:/v${api_version}/containers/create
Le retour :
{"Id":"c2c4a20c0e91b72865f32966b5715dbb916ac32e10dbac4040f920fb17c39d14","Warnings":[]}

Et la deuxième requête à exécuter doit récupérer l'id du conteneur que nous venons de créer (au moins les 6 premiers caractères) comme ceci :

curl --unix-socket /var/run/docker.sock -X POST http:/v${api_version}/containers/c2c4a20/start
Voici l'équivalent de ces deux requêtes avec le client Docker en une seule commande :
docker run -d hello-world

Les images Docker

Attardons-nous sur les images Docker avec quelques exemples de requêtes API.

Une requête API qui semble être intéressante à intégrer dans des scripts est celle sur la recherche d'images sur le Docker Hub.
Pour ce faire, exécuter la requête API suivante :

api_version=$(docker version --format '{{.Client.APIVersion}}') ; curl --unix-socket /var/run/docker.sock http:/v${api_version}/images/search?term=redis

Il vous suffit de remplacer la valeur du paramètre term pour rechercher l'image Docker que vous souhaitez.

Voici l'équivalent de cette requête API avec le client Docker :
docker search redis

Exécutons maintenant cette requête afin de récupérer une image depuis le Docker Hub :

api_version=$(docker version --format '{{.Client.APIVersion}}') ; curl --unix-socket /var/run/docker.sock -X POST "http://localhost/v${api_version}/images/create?fromImage=alpine:latest"
Voici l'équivalent de cette requête API avec le client Docker :
docker pull alpine:latest

Les volumes

Manipulons les volumes Docker avec tout d'abord une requête API permettant de lister les volumes présents sur la machine. Pour ce faire exécuter la requête API suivante :

api_version=$(docker version --format '{{.Client.APIVersion}}') ; curl --unix-socket /var/run/docker.sock "http://localhost/v${api_version}/volumes"
Voici l'équivalent de cette requête API avec le client Docker :
docker volume ls

Créons maintenant un volume avec la requête suivante :

api_version=$(docker version --format '{{.Client.APIVersion}}') ; curl --unix-socket /var/run/docker.sock -H "Content-Type: application/json" -d '{"Name": "mon-volume"}' http:/v${api_version}/volumes/create
Voici l'équivalent de cette requête API avec le client Docker :
docker volume create mon-volume

Les SDK

Il est aussi possible d'utiliser l'API du Docker Engine avec des SDK. L'intérêt d'utiliser un SDK est la simplicité du code ainsi que la documentation simplifiée qui repose sur le SDK et non sur l'API.

💡
A titre personnel, je n'utilise pas de wrappers car cela ajoute une couche d'abstraction supplémentaire à maintenir. Il est parfois préférable d'utiliser l'API uniquement.

Voici un exemple du wrapper Python qui liste les conteneurs :

import docker

client = docker.from_env()

containers = client.containers.list()

Si vous souhaitez approfondir sur les SDK disponible pour l'API du Docker Engine, voici le lien de la documentation officielle :

Examples using the Docker Engine SDKs and Docker API
Examples on how to perform a given Docker operation using the Go and Python SDKs and the HTTP API using curl.

En espérant que cet article vous aura permis de mieux comprendre le fonctionnement du client et de l'API Docker !