Comment (et pourquoi) exécuter Docker Inside Docker – CloudSavvy IT
L’exécution de Docker dans Docker vous permet de créer des images et de démarrer des conteneurs dans un environnement déjà conteneurisé. Il existe deux approches possibles pour y parvenir selon que vous souhaitez démarrer des conteneurs enfants ou frères.
L’accès à Docker depuis l’intérieur d’un conteneur Docker est le plus souvent souhaitable dans le contexte des systèmes CI et CD. Il est courant d’héberger les agents qui exécutent votre pipeline dans un conteneur Docker. Vous finirez par utiliser une stratégie Docker-in-Docker si l’une de vos étapes de pipeline crée ensuite une image ou interagit avec des conteneurs.
Sommaire
L’image Docker-in-Docker
Docker est fourni sous forme d’image autonome via le docker:dind
tag sur Docker Hub. Le démarrage de cette image vous donnera une installation fonctionnelle du démon Docker dans votre nouveau conteneur. Il fonctionnera indépendamment du démon de votre hôte qui exécute le dind
conteneur, donc docker ps
à l’intérieur du conteneur donnera des résultats différents à docker ps
sur votre hôte.
docker run -d --privileged --name docker -e DOCKER_TLS_CERTDIR=/certs -v docker-certs-ca:/certs/ca -v docker-certs-client:/certs/client docker:dind
L’utilisation de Docker-in-Docker de cette manière s’accompagne d’un inconvénient majeur : vous devez utiliser le mode privilégié. Cette contrainte s’applique même si vous utilisez des conteneurs sans racine. Le mode privilégié est activé par le --privileged
flag dans la commande ci-dessus.
L’utilisation du mode privilégié donne au conteneur un accès complet à votre système hôte. Cela est nécessaire dans un scénario Docker-in-Docker afin que votre Docker interne puisse créer de nouveaux conteneurs. Cependant, cela peut représenter un risque de sécurité inacceptable dans certains environnements.
Il y a d’autres problèmes avec dind
trop. Certains systèmes peuvent rencontrer des conflits avec les modules de sécurité Linux (LSM) tels qu’AppArmor et SELinux. Cela se produit lorsque le Docker interne applique des politiques LSM que le démon externe ne peut pas anticiper.
Un autre défi concerne les systèmes de fichiers conteneurs. Le démon externe s’exécutera sur le système de fichiers normal de votre hôte, tel que ext4
. Cependant, tous ses conteneurs, y compris le démon Docker interne, reposeront sur un système de fichiers de copie sur écriture (CoW). Cela peut créer des incompatibilités si le démon interne est configuré pour utiliser un pilote de stockage qui ne peut pas être utilisé sur un système de fichiers CoW existant.
Monter la prise Docker de votre hôte à la place
Les défis associés à dind
sont mieux traités en évitant complètement son utilisation. Dans de nombreux scénarios, vous pouvez obtenir l’effet escompté en montant le socket Docker de votre hôte dans un docker
récipient:
docker run -d --name docker -v /var/run/docker.sock:/var/run/docker.sock docker:latest
Le Docker CLI à l’intérieur du docker
l’image interagit avec le socket du démon Docker qu’elle trouve à /var/run/docker.sock
. Monter le socket de votre hôte sur ce chemin signifie docker
les commandes exécutées à l’intérieur du conteneur s’exécuteront sur votre démon Docker existant.
Cela signifie que les conteneurs créés par le Docker interne résideront sur votre système hôte, à côté du conteneur Docker lui-même. Tous les conteneurs existeront en tant que frères, même s’il semble que le Docker imbriqué est un enfant du parent. Fonctionnement docker ps
produira les mêmes résultats, qu’il soit exécuté sur l’hôte ou à l’intérieur de votre conteneur.
Cette technique atténue les difficultés de mise en œuvre de dind
. Cela supprime également le besoin d’utiliser le mode privilégié, bien que le montage du socket Docker soit en soi un problème de sécurité potentiel. Tout ce qui a accès au socket peut envoyer des instructions au démon Docker, offrant la possibilité de démarrer des conteneurs sur votre hôte, d’extraire des images ou de supprimer des données.
Quand utiliser chaque approche
Docker-in-Docker via dind
a toujours été largement utilisé dans les environnements CI. Cela signifie que les conteneurs « intérieurs » ont une couche d’isolement par rapport à l’hôte. Un seul conteneur d’exécution CI prend en charge chaque conteneur de pipeline sans polluer le démon Docker de l’hôte.
Bien que cela fonctionne souvent, cela est lourd d’effets secondaires et n’est pas le cas d’utilisation prévu pour dind
. Il a été ajouté pour faciliter le développement de Docker lui-même, et non pour fournir une assistance aux utilisateurs finaux pour les installations Docker imbriquées.
Selon Jérôme Petazzoni, le créateur de la dind
mise en œuvre, l’adoption de l’approche basée sur les sockets devrait être votre solution préférée. Le montage par liaison du socket démon de votre hôte est plus sûr, plus flexible et tout aussi complet que le démarrage d’un dind
récipient.
Si votre cas d’utilisation signifie que vous avez absolument besoin dind
, il existe un moyen plus sûr de le déployer. Le projet Sysbox moderne est un runtime de conteneur dédié qui peut imbriquer d’autres runtimes sans utiliser le mode privilégié. Les conteneurs Sysbox deviennent semblables à des machines virtuelles, ils peuvent donc prendre en charge des logiciels qui s’exécutent généralement sans système d’exploitation sur une machine physique ou virtuelle. Cela inclut Docker et Kubernetes sans aucune configuration spéciale.
Conclusion
L’exécution de Docker dans Docker est une exigence relativement courante. Vous le verrez probablement lors de la configuration des serveurs CI qui doivent prendre en charge les constructions d’images de conteneur à partir de pipelines créés par l’utilisateur.
À l’aide de docker:dind
vous donne un démon Docker indépendant s’exécutant dans son propre conteneur. Il crée efficacement des conteneurs enfants qui ne sont pas directement visibles depuis l’hôte. Bien qu’il semble offrir un fort isolement, dind
abrite en fait de nombreux problèmes de cas périphériques et des problèmes de sécurité. Ceux-ci sont dus aux interactions du système d’exploitation de Docker.
Monter le socket Docker de votre hôte dans un conteneur qui inclut le docker
binaire est une alternative plus simple et plus prévisible. Cela permet au processus Docker imbriqué de démarrer des conteneurs qui deviennent ses propres frères et sœurs. Aucun autre paramètre n’est nécessaire lorsque vous utilisez l’approche basée sur les sockets.