Article Image
Dockers sur le vieux port de Marseille - Georges POMERAT
read

Parmi toutes les fonctionnalités disponibles, il en est une qui explique pour beaucoup le dynamisme phénoménal de l’écosystème Docker. Il s’agit de Docker Remote API, une API REST extrêmement bien conçue exposant toutes les fonctionnalités du moteur Docker et permettant ainsi de piloter un hôte Docker depuis une machine ou une application distante.

Toutes les solutions d’orchestration de conteneurs Docker utilisent directement ou indirectement l’API Docker Remote, raison pour laquelle je vous propose d’y jeter un oeil attentif.

Dans cet article, nous verrons :

  • comment fonctionne l’interaction avec le démon Docker
  • comment activer Docker Remote API avec et sans certificats TLS
  • comment utiliser Docker Machine avec un hôte Docker déjà provisionné sur un réseau local d’entreprise

La communication avec le démon Docker

Le schéma ci-dessous représente l’architecture type d’un serveur Linux (sous Ubuntu) hébergeant un hôte Docker. Le moteur Docker (serveur) est un démon écoutant par défaut sur un socket UNIX (/var/run/docker.sock).
Pour mémoire, les sockets UNIX permettent à deux ou plusieurs processus d’échanger des données de façon bi-directionnelle.

Ainsi, le client Docker installé localement interagit avec le démon via le socket UNIX /var/run/docker.sock. Sans surprise, le protocole d’échange utilisé par l’API Docker est de type REST comme nous allons le voir ci-après.

Exécutons par exemple la commande GET /info, permettant d’obtenir des informations système de l’hôte Docker.
Pour ce faire, j’utilise l’utilitaire Netcat (commande nc) afin d’envoyer la requête au socket /var/run/docker.sock :

echo -e “GET /info HTTP/1.0rn” | sudo nc -U /var/run/docker.sock

Voici un extrait de la réponse obtenue :

HTTP/1.0 200 OK
Content-Type: application/json
Job-Name: info
Date: Tue, 12 May 2015 19:56:14 GMT
Content-Length: 889

{”Containers”:118,[…]”Name”:”orion”,”OperatingSystem”:”Ubuntu 14.04.2 LTS”,”RegistryConfig”:
{”IndexConfigs”:{”docker.io”:{”Mirrors”:null,”Name”:”docker.io”,”Official”:true,”Secure”:true}},
“InsecureRegistryCIDRs”:[”127.0.0.0/8″]},”SwapLimit”:0,
“SystemTime”:”2015-05-12T21:56:14.735623265+02:00″}

On remarquera que le corps de la réponse est au format JSON.

Maintenant, voyons à quoi ressemblerait une combinaison associant :

  • un hôte Docker avec activation de Docker Remote API
  • un client Docker localisé sur une machine distante

Voyons comment activer et utiliser Docker Remote API avec et sans certificats TLS.

Activer Docker Remote API sans certificat TLS

Cette configuration n’est pas recommandée en production car la communication entre client et hôte Docker est en clair. Elle est néanmoins fort utile à des fins de test. Voici comment la mettre en oeuvre :

Côté serveur (orion.local sous Ubuntu) :

  • éditer le fichier /etc/default/docker puis renseigner la variable d’environnement DOCKER_OPTS comme suit :
DOCKER_OPTS="-H tcp://0.0.0.0:2375 -H unix:///var/run/docker.sock"
  • redémarrer le démon docker :
**ksahnine@orion:~$** sudo service docker restart

A ce stade, le démon écoute sur le port TCP 2375 ainsi que sur le socket UNIX /var/run/docker.sock.

Note : Le fichier /etc/default/docker n’est présent que sous Ubuntu. A défaut, il faudra renseigner et exporter la variable d’environnement DOCKER_OPTS.

Côté client (laptop.local) :

  • pour interroger l’hôte Docker depuis une autre machine, utiliser la commande docker en renseignant l’option -H avec l’adresse et le port d’écoute de l’hôte Docker distant.
    L’exemple ci-dessous permet d’afficher la liste des conteneurs actifs sur l’hôte Docker distant :
ksahnine@laptop:~$ docker -H=192.168.0.29:2375 ps
CONTAINER ID        IMAGE               COMMAND                CREATED             STATUS              PORTS               NAMES
6faede9c46af        nginx:latest        “nginx -g ‘daemon of   12 minutes ago      Up 12 minutes       80/tcp, 443/tcp     sleepy_lalande

Note : On peut aussi renseigner la variable d’environnement DOCKER_HOST sur le poste client (export DOCKER_HOST=192.168.0.29:2375) et lancer tout simplement la commande docker ps sans l’option -H

A l’aide de tcpdump, interceptons les échanges entre le client Docker et l’hôte Docker distant :

sudo tcpdump -c 20 -s 0 -i en1 -A host 192.168.0.29 and tcp port 2375

On remarquera que la requête issue de la commande docker ps est la suivante :

GET /v1.18/containers/json HTTP/1.1
Host: 192.168.0.29:2375
User-Agent: Docker-Client/1.6.0
Accept-Encoding: gzip

On pourrait donc se passer du client Docker et utiliser directement l’utilitaire cURL, dont la commande équivalente à docker ps serait :

curl -X GET http://192.168.0.29:2375/v1.18/containers/json

Activer Docker Remote API avec certificat TLS

Il nous faut tout d’abord produire 3 certificats :

  • le certificat racine utilisé comme autorité de certification. Il sera utilisé pour signer les certificats client et serveur.
  • le certificat serveur installé et utilisé par l’hôte Docker
  • le certificat client installé et utilisé par le client Docker

Je mets à disposition un script shell permettant de générer les certificats de test et dont voici le mode opératoire d’utilisation correspondant à notre cas :

**ksahnine@orion:~$** wget https://raw.githubusercontent.com/ksahnine/docker/master/gen-docker-certs.sh
**ksahnine@orion:~$** sh gen-docker-certs.sh
- Nom de l’hôte Docker : orion
- Adresse IP de l’hôte Docker : 192.168.0.29

Le script produit :

  • le certificat racine (clé publique ca.pem)
  • le certificat client (clé publique cert.pem / clé privée key.pem)
  • le certificat serveur (clé publique server.pem / clé privée server-key.pem)

Passons à la configuration du serveur et du client Docker.

Côté serveur (orion.local sous Ubuntu) :

  • copier les fichier ca.pem, server.pem et server-key.pem dans le répertoire /root/.docker (ou tout autre répertoire sécurisé)
  • éditer le fichier /etc/default/docker puis renseigner la variable d’environnement DOCKER_OPTS comme suit :
DOCKER_OPTS="--tlsverify --tlscacert=/root/.docker/ca.pem --tlscert=/root/.docker/server.pem \\
     --tlskey=/root/.docker/server-key.pem -H=unix:///var/run/docker.sock -H=0.0.0.0:2376"
  • redémarrer le démon docker :
**ksahnine@orion:~$** sudo service docker restart

A ce stade, le démon écoute sur le socket UNIX /var/run/docker.sock ainsi que sur le port TCP 2376, port utilisé par convention pour les échanges sécurisés.

Côté client (laptop.local) :

  • copier les fichiers ca.pem, cert.pem et key.pem dans le répertoire ~/.docker
  • utiliser la commande docker avec le flag --tlsverify pour passer en mode TLS.
    L’exemple ci-dessous permet d’afficher la liste des conteneurs actifs sur l’hôte Docker distant :
**ksahnine@laptop:~$** docker –tlsverify -H=192.168.0.29:2376 ps
CONTAINER ID        IMAGE               COMMAND                CREATED             STATUS              PORTS               NAMES
6faede9c46af        nginx:latest        “nginx -g ‘daemon of   12 minutes ago      Up 12 minutes       80/tcp, 443/tcp     sleepy_lalande

Note : Vous avez noté que je n’ai pas passé explicitement les clés dans la ligne de commande. Par défaut, le client docker s’attend à trouver le certificat racine sous ~/.docker/ca.pem, le certificat client sous ~/.docker/cert.pem et la clé privée sous ~/.docker/key.pem. Si les noms des clés diffèrent ou s’ils sont localisés dans un autre répertoire, il faudra utiliser respectivement les options --tlscacert, --tlscert et --tlskey. Le flag --tlsverify peut être omis si la variable d’environnement DOCKER_TLS_VERIFY est valorisée à 1.

Utilisation avec Docker Machine

Si vous gérez plusieurs hôtes Docker répartis sur un LAN et/ou dans un cloud public, il est beaucoup plus pratique de travailler avec Docker Machine depuis un simple ordinateur portable.
Dans le cas de cet article, un hôte Docker est déjà provisionné sur le serveur Linux orion.local (192.168.0.29).
Rajoutons l’hôte sous le nom orionbox :

**ksahnine@laptop:~$** docker-machine create –driver none –url=tcp://192.168.0.29:2376 orionbox

La commande docker-machine ls le confirme :

**ksahnine@laptop:~$** docker-machine ls
NAME       ACTIVE   DRIVER   STATE   URL                       SWARM
orionbox   *        none             tcp://192.168.0.29:2376

Copier les certificats client, serveur et racine précédemment générés (fichiers ca.pem, cert.pem, key.pem, server.pem et server-key.pem) dans le répertoire ~/.docker/machine/machines/orionbox.

La commande docker-machine env affiche les variables d’environnement à positionner pour forcer le client docker à interagir avec une machine particulière, orionbox dans notre cas :

ksahnine@laptop:~$ docker-machine env orionbox
Bad port ‘0′
ERRO[0002] Error running SSH command to get /etc/os-release: exit status 255
export DOCKER_TLS_VERIFY=1
export DOCKER_CERT_PATH=”/Users/ksahnine/.docker/machine/machines/orionbox”
export DOCKER_HOST=tcp://192.168.0.29:2376

Note : Remarquez l’erreur d’exécution obtenue en sortie. A ma connaissance, l’utilisation de l’option --driver none ne permet pas de configurer d’authentification par clés SSH afin que Docker Machine puisse exécuter des commandes à distance. A ce jour, Docker Machine est encore en version bêta (v 0.20). Sauf erreur de ma part, il faudra attendre la publication du driver generic actuellement en cours de développement. Il devrait permettre de provisionner un hôte Docker sur n’importe quel serveur existant accessible par SSH, un peu à la manière d’Ansible.

Mise à jour 29/06/2015 : Le driver generic est désormais disponible depuis la version 0.3 de Docker Machine.

Passons outre le message d’erreur et positionnons les variables d’environnements comme suit :

export DOCKER_TLS_VERIFY=1
export DOCKER_CERT_PATH="/Users/ksahnine/.docker/machine/machines/orionbox"
export DOCKER_HOST=tcp://192.168.0.29:2376

ou plus simplement :

eval $(docker-machine env orionbox)

C’est terminé. Notre client Docker est configuré pour interagir avec l’hôte docker distant.

Blog Logo

Kadda SAHNINE


Publié le

Image

Inovia Blog

Excursions technologiques, par Kadda SAHNINE

Accueil