
Docker-in-Docker est un environnement virtualisĂ© du dĂ©mon Docker, exĂ©cutĂ© Ă l'intĂ©rieur d'un conteneur pour crĂ©er des images de conteneur. L'objectif principal de la crĂ©ation de Docker-in-Docker Ă©tait d'aider au dĂ©veloppement de Docker lui-mĂȘme. Beaucoup de gens l'utilisent pour exĂ©cuter Jenkins CI. Au dĂ©part, cela semble normal, mais des problĂšmes surviennent, que l'on peut Ă©viter en installant Docker dans le conteneur Jenkins CI. Cet article explique comment faire cela. Si vous ĂȘtes intĂ©ressĂ© par la solution finale sans dĂ©tails, lisez simplement la derniĂšre section de l'article intitulĂ©e « RĂ©solution du problĂšme ».

Docker-in-Docker : « Bon »
Il y a plus de deux ans, j'ai insĂ©rĂ© Docker âprivileged et j'ai Ă©crit . L'objectif Ă©tait d'aider l'Ă©quipe principale Ă dĂ©velopper Docker plus rapidement. Avant l'avĂšnement de Docker-in-Docker, le cycle de dĂ©veloppement typique Ă©tait le suivant :
- hackity hack;
- construction (build);
- arrĂȘt du dĂ©mon Docker en cours d'exĂ©cution;
- lancement d'un nouveau démon Docker;
- test;
- répéter le cycle.
Cependant, si vous vouliez faire une construction propre et reproductible (c'est-Ă -dire dans un conteneur), cela devenait plus complexe :
- hackity hack;
- s'assurer qu'une version opérationnelle de Docker est en cours d'exécution;
- construire un nouveau Docker avec l'ancien Docker;
- arrĂȘter le dĂ©mon Docker;
- lancer un nouveau démon Docker;
- tester;
- arrĂȘter le nouveau dĂ©mon Docker;
- répéter.
Avec l'arrivée de Docker-in-Docker, le processus s'est simplifié :
- hackity hack;
- construction + lancement en une étape;
- répéter le cycle.
N'est-il pas vrai que c'est beaucoup mieux ?

Docker-in-Docker : « Mauvais »
Cependant, contrairement Ă la croyance populaire, Docker-in-Docker n'est pas composĂ© Ă 100% d'Ă©toiles, de poneys et de licornes. Je veux dire qu'il y a plusieurs problĂšmes dont le dĂ©veloppeur doit ĂȘtre conscient.
L'une d'elles concerne LSM (modules de sĂ©curitĂ© Linux), tels qu'AppArmor et SELinux : lors du lancement d'un conteneur, le « Docker interne » peut tenter d'appliquer des profils de sĂ©curitĂ© qui entreront en conflit ou troubleront le « Docker externe ». C'est le problĂšme le plus complexe Ă rĂ©soudre lors de la tentative de combiner la mise en Ćuvre d'origine du drapeau âprivileged. Mes modifications fonctionnaient, et tous les tests auraient Ă©galement rĂ©ussi sur ma machine Debian et mes machines virtuelles de test Ubuntu, mais elles se seraient effondrĂ©es sur la machine de Michael Crosby (si je me souviens bien, il avait Fedora). Je ne peux pas me souvenir de la cause exacte du problĂšme, mais il est possible qu'il soit survenu parce que Mike est un homme sage qui fonctionne avec SELINUX=enforce (j'ai utilisĂ© AppArmor), et mes modifications ne prenaient pas en compte les profils SELinux.
Docker-in-Docker : le « maléfique »
Le deuxiÚme problÚme est lié aux pilotes de stockage Docker. Lorsque vous exécutez Docker-in-Docker, le Docker externe fonctionne au-dessus d'un systÚme de fichiers traditionnel (EXT4, BTRFS ou tout autre que vous avez), tandis que le Docker interne fonctionne sur un systÚme de copy-on-write (AUFS, BTRFS, Device Mapper, etc., selon ce que le Docker externe est configuré pour utiliser). Cela entraßne de nombreuses combinaisons qui ne fonctionneront pas. Par exemple, vous ne pourrez pas exécuter AUFS au-dessus d'AUFS.
Si vous exĂ©cutez BTRFS au-dessus de BTRFS, cela devrait d'abord fonctionner, mais une fois que des sous-volumes imbriquĂ©s apparaissent, il ne sera pas possible de supprimer le sous-volume parent. Le module Device Mapper n'a pas d'espace de noms, donc si plusieurs instances de Docker l'utilisent sur une mĂȘme machine, elles pourront toutes voir (et influencer) les images les unes des autres et les dispositifs de sauvegarde des conteneurs. C'est problĂ©matique.
Il existe des solutions pour contourner bon nombre de ces problĂšmes. Par exemple, si vous souhaitez utiliser AUFS dans Docker interne, il suffit de transformer le dossier /var/lib/docker en volume, et tout ira bien. Docker a ajoutĂ© certains espaces de noms de base aux cibles de Device Mapper, de sorte que si plusieurs appels Docker sont effectuĂ©s sur une mĂȘme machine, ils ne se « marcheront » pas sur les pieds.
Cependant, une telle configuration n'est pas simple, comme vous pouvez le voir dans ces dans le dépÎt dind sur GitHub.
Docker-in-Docker : ça devient encore pire
Et qu'en est-il du cache de construction ? Cela peut ĂȘtre assez compliquĂ©. Les gens me demandent souvent « si je lance Docker-in-Docker, comment puis-je utiliser les images situĂ©es sur mon hĂŽte, plutĂŽt que de tout retĂ©lĂ©charger dans mon Docker interne ? »
Certaines personnes entreprenantes ont tenté de lier /var/lib/docker de l'hÎte dans le conteneur Docker-in-Docker. Parfois, elles partagent /var/lib/docker entre plusieurs conteneurs.

Voulez-vous corrompre des données ? Parce que c'est exactement ce qui nuira à vos données !
Le démon Docker a clairement été conçu pour avoir un accÚs exclusif à /var/lib/docker. Rien d'autre ne devrait « toucher, pokéer ou tripoter » les fichiers Docker se trouvant dans ce dossier.
Pourquoi est-ce le cas ? Parce que c'est le résultat de l'une des leçons les plus difficiles apprises lors du développement de dotCloud. Le moteur de conteneurs dotCloud fonctionnait avec plusieurs processus accédant simultanément à /var/lib/dotcloud. Des astuces comme le remplacement atomique de fichiers (au lieu de l'édition sur place), le « peppering » de code avec des verrous recommandés et obligatoires, ainsi que d'autres expériences avec des systÚmes sûrs comme SQLite et BDB, ne fonctionnaient pas toujours. Lorsque nous avons refait notre moteur de conteneurs, qui est finalement devenu Docker, l'un des principaux choix de conception a été de regrouper toutes les opérations de conteneurs sous un seul démon, afin de mettre fin à toute cette absurdité d'accÚs simultané.
Ne vous méprenez pas : il est tout à fait possible de faire quelque chose de bon, fiable et rapide, impliquant plusieurs processus et une gestion moderne du parallélisme. Mais nous pensons qu'il est plus simple et plus facile d'écrire et de maintenir du code en utilisant Docker comme seul acteur.
Cela signifie que si vous partagez le rĂ©pertoire /var/lib/docker entre plusieurs instances de Docker, vous rencontrerez des problĂšmes. Bien sĂ»r, cela peut fonctionner, en particulier aux premiers stades des tests. « Ăcoute, Ma, je peux faire tourner ubuntu avec âdockerâ ! » Mais essayez de faire quelque chose de plus complexe, comme tirer la mĂȘme image de deux instances diffĂ©rentes, et vous verrez le monde s'embraser.
Cela signifie que si votre systÚme CI effectue des constructions et des reconstructions, chaque fois que vous redémarrez le conteneur Docker-in-Docker, vous risquez de réinitialiser une bombe à retardement dans son cache. Ce n'est pas génial du tout !
Résoudre le problÚme
Faisons un pas en arriÚre. Avez-vous vraiment besoin de Docker-in-Docker ou voulez-vous simplement pouvoir exécuter Docker, c'est-à -dire construire et exécuter des conteneurs et des images depuis votre systÚme CI, pendant que ce systÚme CI se trouve dans un conteneur ?
Je parie que la plupart des gens ont besoin de la derniÚre option, c'est-à -dire qu'ils veulent que le systÚme CI, tel que Jenkins, puisse exécuter des conteneurs. Et le moyen le plus simple de le faire est d'insérer simplement le socket Docker dans votre conteneur CI, en le liant avec l'option -v.
En d'autres termes, lorsque vous démarrez votre conteneur CI (Jenkins ou autre), au lieu de bricoler quelque chose avec Docker-in-Docker, commencez-le avec la ligne:
docker run -v /var/run/docker.sock:/var/run/docker.sock ...Maintenant, ce conteneur aura accÚs au socket Docker et pourra donc exécuter des conteneurs. Sauf que, au lieu de lancer des conteneurs "enfants", il lancera des conteneurs "fraternels".
Essayez cela en utilisant l'image officielle docker (qui contient le fichier binaire Docker) :
docker run -v /var/run/docker.sock:/var/run/docker.sock
-ti dockerCela ressemble et fonctionne comme Docker-in-Docker, mais ce n'est pas Docker-in-Docker : lorsque ce conteneur créera des conteneurs supplémentaires, ils seront créés dans Docker de niveau supérieur. Vous n'aurez pas d'effets secondaires liés à l'imbrication, et le cache de construction sera partagé entre plusieurs appels.
Remarque : les versions précédentes de cet article conseillaient de lier le fichier binaire Docker de l'hÎte au conteneur. Cela est désormais devenu peu fiable, car le mécanisme Docker ne s'applique plus aux bibliothÚques statiques ou presque statiques.
Ainsi, si vous souhaitez utiliser Docker depuis Jenkins CI, vous avez 2 options :
installer Docker CLI en utilisant le systÚme de base de paquets d'image (c'est-à -dire si votre image est basée sur Debian, utilisez les paquets .deb), utiliser l'API Docker.
Un peu de publicitĂ© đ
Merci de rester avec nous. Aimez-vous nos articles ? Voulez-vous voir plus de contenu intĂ©ressant ? Soutenez-nous en passants une commande ou en nous recommandant Ă des amis, , un Ă©quivalent unique des serveurs d'entrĂ©e de gamme, conçu pour vous : (options disponibles avec RAID1 et RAID10, jusqu'Ă 24 cĆurs et jusqu'Ă 40 Go DDR4).
Dell R730xd deux fois moins cher dans le data center Equinix Tier IV Ă Amsterdam ? Uniquement chez nous aux Pays-Bas ! Dell R420 â 2x E5-2430 2.2GHz 6C 128Go DDR3 2x960Go SSD 1Gbps 100To â Ă partir de 99 $ ! Lisez sur
Source : habr.com
