Bonjour à tous! Dans mon article précédent , j'avais promis de parler du lancement de Docker dans Docker et des aspects pratiques de l'application de cette leçon. Il est temps de tenir notre promesse. Un développeur expérimenté dirait peut-être que ceux qui ont besoin de Docker à l'intérieur de Docker jettent simplement la prise démon Docker de l'hôte à l'intérieur du conteneur et cela suffit dans 99% des cas. Mais ne vous précipitez pas pour me lancer des cookies, car nous parlerons du vrai lancement de Docker dans Docker. Cette solution a de nombreux domaines d'application possibles et cet article concerne l'un d'entre eux, alors asseyez-vous et redressez vos bras devant vous.
Commencer
Tout a commencé par une soirée pluvieuse de septembre, alors que je nettoyais une voiture de location Digital Ocean pour 5 $, ce qui était bien parce que Docker remplissait les 24 gigaoctets d'espace disque disponible avec ses images et ses conteneurs. L'ironie, c'est que toutes ces images et conteneurs étaient transitoires et n'avaient besoin que de tester les performances de mon application chaque fois qu'une nouvelle version d'une bibliothèque ou d'un framework sortait. J'ai essayé d'écrire des scripts shell et de configurer le calendrier des couronnes pour le nettoyage des ordures, mais cela n'a pas sauvé: à chaque fois, tout finissait inévitablement par l'espace disque de mon serveur consommé et le serveur gelé (au mieux). À un moment donné, je suis tombé sur un article sur la façon d'exécuter Jenkins dans un conteneur et comment il peut créer et supprimer des pipelines d'assemblage via le socket du démon docker qui y est jeté. J'ai aimé l'idée, mais j'ai décidé d'aller de l'avant et d'essayer d'expérimenter le lancement direct de Docker dans Docker. Il m'a alors semblé tout à fait logique de pomper des images de docker et de créer des conteneurs de toutes les applications dont j'avais besoin pour tester à l'intérieur d'un autre conteneur (appelons-le un conteneur intermédiaire). L'idée était d'exécuter un conteneur intermédiaire avec l'indicateur -rm, qui supprime automatiquement le conteneur entier avec tout son contenu lorsqu'il s'arrête. J'ai fouillé l'image Docker du Docker lui-même ( https://hub.docker.com/_/docker ), mais elle s'est révélée trop volumineuse et je n'ai pas pu la faire fonctionner comme j'avais besoin et je voulais aller jusqu'au bout moi-même.
Pratique. Bosses
Je me suis mis à faire fonctionner le conteneur selon mes besoins et j'ai poursuivi mes expériences, qui ont abouti à une myriade de cônes. Le résultat de mon auto-torture a été l'algorithme suivant:
Nous lançons le conteneur Docker en mode interactif.
docker run --privileged -it docker:18.09.6
Faites attention à la version du récipient, un pas à droite ou à gauche et votre DinD se transforme en citrouille. En fait, tout tombe en panne assez souvent avec la sortie d'une nouvelle version.
Nous devons immédiatement entrer dans la coquille.
Essayer de savoir quels conteneurs sont en cours d'exécution (réponse: aucun), mais exécutons quand même la commande:
docker ps
Vous serez un peu surpris, mais il s'avère que le démon Docker ne fonctionne même pas:
error during connect: Get http://docker:2375/v1.40/containers/json: dial tcp: lookup docker on 192.168.65.1:53: no such host
Exécutons-le vous-même:
dockerd &
Une autre surprise désagréable:
failed to start daemon: Error initializing network controller: error obtaining controller instance: failed to create NAT chain DOCKER: Iptables not found
Installez les packages iptables et bash (c'est plus agréable de travailler dans le bash que dans sh):
apk add --no-cache iptables bash
Nous commençons bash. Enfin nous sommes de retour dans la coquille habituelle
essayez de lancer à nouveau docker:
dockerd &
Nous devrions voir une longue feuille de journal se terminer:
INFO[2019-11-25T19:51:19.448080400Z] Daemon has completed initialization INFO[2019-11-25T19:51:19.474439300Z] API listen on /var/run/docker.sock
Appuyez sur Entrée. Nous sommes de retour dans le bash.
À partir de maintenant, nous pouvons essayer de lancer d'autres conteneurs à l'intérieur de notre conteneur Docker, mais que se passe-t-il si nous voulons soulever un autre conteneur Docker à l'intérieur de notre conteneur Docker ou que quelque chose se passe mal et que le conteneur «s'envole»? Tout recommencer.
Propre conteneur DinD et nouvelles expériences
Afin de ne pas répéter les étapes ci-dessus encore et encore, j'ai créé mon propre conteneur DinD:
https://github.com/alekslitvinenk/dind
La solution DinD fonctionnelle m'a donné l'opportunité d'exécuter Docker à l'intérieur de Docker de manière récursive et de mener des expériences plus audacieuses.
Une telle expérience (réussie) avec l'exécution de MySQL et Nodejs, je vais décrire maintenant.
Les plus impatients peuvent voir comment c'était ici
Commençons donc:
Lancez DinD de manière interactive. Dans cette version de DinD, nous devons cartographier manuellement tous les ports que nos conteneurs enfants peuvent utiliser (j'y travaille déjà)
docker run --privileged -it \ -p 80:8080 \ -p 3306:3306 \ alekslitvinenk/dind
Nous nous retrouvons dans un bash, d'où nous pouvons immédiatement commencer à lancer des conteneurs subsidiaires.
Nous commençons MySQL:
docker run --name mysql -e MYSQL_ROOT_PASSWORD=strongpassword -d -p 3306:3306 mysql
Nous nous connectons à la base de données de la même manière que nous nous y connectons localement. Assurez-vous que tout fonctionne.
Nous lançons le deuxième conteneur:
docker run -d --rm -p 8080:8080 alekslitvinenk/hello-world-nodejs-server
Veuillez noter que le mappage de port ici sera exactement 8080: 8080 , car nous avons déjà mappé le port 80 de l'hôte au conteneur parent sur le port 8080.
Nous allons sur localhost dans le navigateur, nous sommes convaincus que le serveur répond "Hello World!".
Dans mon cas, l'expérience avec les conteneurs dockers enfermés a été assez positive, et je vais continuer à développer le projet et à l'utiliser pour la mise en scène. Il me semble que c'est une solution beaucoup plus légère que les mêmes Kubernetes et Jenkins X. Mais c'est mon opinion subjective.
Je pense que c'est tout pour l'article d'aujourd'hui. Dans le prochain article, je décrirai plus en détail des expériences avec le lancement récursif de Docker dans Docker et le montage de répertoires profondément dans des conteneurs imbriqués.
PS Si vous trouvez ce projet utile, alors donnez-lui un astérisque sur le GitHub, fork et dites à vos amis.
Edit1 Correction de bugs, concentré sur 2 vidéos