Blog

Docker dans Jenkins dans Docker !

Bien que le Hub de Docker permette de faire des builds automatisées, cette solution a aussi ses limites, dont une en particulier qui m’a fait chercher une méthode alternative : les tags sont fixes (dans le sens où on ne peut pas le définir dynamiquement) et la seule solution serait alors soit de dupliquer votre Dockerfile pour chaque nouveau tag, soit d’éditer la configuration de votre build automatisée pour changer le tag associé à votre Dockerfile.
Une solution serait donc de construire ces images « manuellement » avec la commande docker build et ensuite de les pousser sur le Hub ( docker push). J’ai donc opté pour une construction manuelle automatisée (je dis ce que je veux, c’est mon article) avec Jenkins.

Cependant un petit hic persiste : comment ça se passe quand Jenkins tourne lui même dans Docker (ce qui est mon cas) ? Cet article va répondre à cette question !

Docker dans Docker ?

Docker dans docker

En effet il faut d’abord par commencer à se renseigner sur la possibilité d’exécuter des commandes Docker à l’intérieur d’un conteneur.

Une première astuce serait d’installer le client Docker dans le conteneur et de partager le socket du serveur « parent » au conteneur avec un volume :

Ensuite faire un docker version dans le conteneur Jenkins devrait marcher sans problème.

Et là, en voyant ça ceux d’entre vous qui connaissent un peu Docker doivent approximativement faire cette tête là :
Ne faîtes jamais ça !

Ne faîtes jamais ça malheureux ! En exposant dans un conteneur le socket de votre hôte vous lui donnez aussi accès, ben à tout. Il peut voir les autres conteneurs, les arrêter, les supprimer (!), etc. Autant dire que vous venez de créer une bonne grosse faille de sécurité en plus d’avoir un des principes de base de Docker, à savoir la création de conteneurs indépendants (et donc inconscient de l’existence les uns des autres).

Docker dans Docker !

Alors tout d’abord, faire tourner un serveur Docker dans un conteneur Docker c’est pas simple ! Je suis loin d’être un expert Linux mais je sais que ça pose des problèmes avec les cgroup et tout et tout, des trucs de geeks quoi ;)

D’autant qu’au tout début ça semblait être impossible et il a fallu l’arriver de la version 0.6 de Docker pour que ce soit possible1.
Heureusement pour nous dès que ça a été possible un dépôt Github a été créé contenant le Dockerfile qui va bien pour générer une image avec un serveur Docker qui tourne à l’intérieur : https://github.com/jpetazzo/dind.
L’image existe aussi sur le Hub Docker, cependant je vous conseillerai plutôt de la générer vous-même à la demande puisque celle disponible sur le Hub n’est pas forcément fraiche et contient donc une version de Docker probablement obsolète.

Mise en pratique

On part du principe que vous disposez de Docker et Fig sur votre machine.

Commençons par le fichier fig.yml :

Du côté des configurations, rien de magique : on ne fait qu’utiliser les configurations décrites dans les README des images respectives.

Ensuite on clone le dépôt DIND : git clone https://github.com/jpetazzo/dind.git docker/dind. Ceci ayant pour objectif, comme dit plus haut, de générer l’image à la demande pour d’avoir un Docker à jour.

Enfin le Dockerfile de Jenkins qui n’a rien d’exceptionnel, on ne fait qu’installer Docker dans l’image Jenkins :

Ensuite, construisez les images : fig build

Prochaine étape, se connecter au Hub Docker. Commencez par créer le fichier .dockercfg spécifié dans le fig.yml, puis utilisez simplement Docker :

On peut maintenant lancer Jenkins ! fig up -d

Exemple de configuration Jenkins

Créez un projet dans Jenkins et ajoutez une étape « Execute shell » avec le contenu suivant :

Lancez une build Jenkins et tada !

Docker dans Jenkins dans Docker

Docker dans Jenkins dans Docker


Voila, vous savez désormais comment utiliser Docker à l’intérieur d’un autre conteneur Docker et en particulier Jenkins, et ce de manière propre.
Le fait que l’exemple soit fait avec Jenkins est là pour vous faire imaginer les possibilités que peut offrir cette solution : n’installez plus PHP/Ruby/Node directement sur Jenkins mais utilisez maintenant Docker pour générer les images qui vont bien et faites passer vos builds à grands coups de conteneurs ! ;)

[1] http://blog.docker.com/2013/09/docker-can-now-run-within-docker/