
A Docker-in-Docker egy virtuális Docker-környezet, amely a Docker-álarcban fut, amelyet az érvek konténerébe építenek a konténerképek építéséhez. A Docker-in-Docker létrehozásának fő célja a Docker fejlesztésének elősegítése volt. Sokan használják a Jenkins CI indításához. Eleinte jónak tűnik, de problémák merülnek fel, amelyek elkerülhetők, ha a Dockert közvetlenül a Jenkins CI konténerében telepítjük. Ebben a cikkben bemutatjuk, hogyan kell ezt megtenni. Ha érdeklik az eredmény nélküli részletek, csak olvassa el a cikk végső szakaszát a 'Probléma megoldása' címmel.

Docker-in-Docker: "Jó"
Több mint két évvel ezelőtt csatlakoztam a Dockerhez –privileged kulcshoz és írtam A cél az volt, hogy segítsem a főcsapatot a Docker gyorsabb fejlesztésében. A Docker-in-Docker megjelenéséig a tipikus fejlesztési ciklus a következőképpen zajlott:
- hackity hack;
- építés (build);
- leállítani a futó Docker-át;
- új Docker-át indítani;
- tesztelés;
- kör újraindítása.
Ha pedig szép, reprodukálható építést akartál (azaz konténerben), akkor ez bonyolultabb lett:
- hackity hack;
- meg kell bizonyosodni, hogy működő Docker-verzió fut;
- új Dockert a régi Dockerből építeni;
- leállítani a Docker-át;
- új Docker-át indítani;
- tesztelni;
- leállítani az új Docker-át;
- ismételni.
A Docker-in-Docker megjelenésével a folyamat egyszerűsödött:
- hackity hack;
- építés + indítás egy lépésben;
- kör újraindítása.
Nem igaz, hogy így sokkal jobb?

Docker-in-Docker: "Rossz"
Azonban, ellentétben a köztudatban elterjedt meggyőződéssel, a Docker-in-Docker nem csak csillagokból, pónikból és egyszarvúkból áll. Úgy értem, vannak olyan problémák, amelyeket a fejlesztőknek tudniuk kell.
Az egyik a LSM-mel (Linux biztonsági modulok), mint például az AppArmor és az SELinux kapcsolatos: amikor elindít egy konténert, a „belső Docker” megpróbálhatja alkalmazni a biztonsági profilt, ami ellentmondásos vagy zavarba ejtő lehet a „külső Docker” számára. Ez a legbonyolultabb probléma, amit meg kellett oldani, amikor megpróbáltam egyesíteni a -privileged zászló eredeti megvalósítását. A változtatásaim működtek, és minden teszt is sikeres lett az én Debian gépemen és az Ubuntu teszt virtuális gépeken, de Michael Crosby gépén összeomlottak (amennyire emlékszem, neki Fedora-ja volt). Nem tudom pontosan a probléma okát, de lehet, hogy azért merült fel, mert Mike egy okos ember, aki SELINUX=enforce használ (én AppArmor-t használtam), és a változtatásaim nem vették figyelembe az SELinux profilokat.
Docker-in-Docker: „Gonosz”
A második probléma a Docker tárolómeghajtóival kapcsolatos. Amikor elindít egy Docker-in-Docker-t, a külső Docker a hagyományos fájlrendszer (EXT4, BTRFS vagy bármely más, amit használ) felett működik, míg a belső Docker íráskor másoló rendszer (AUFS, BTRFS, Device Mapper stb., attól függően, hogy mi van beállítva a külső Docker használatára) felett működik. Ez sok kombinációt okoz, amelyek nem fognak működni. Például nem tudja AUFS-t indítani AUFS felett.
Ha BTRFS-t indít BTRFS felett, először működnie kell, de amint létrejönnek a beágyazott alfejezetek, a szülő alfejezet szüntetése nem lesz lehetséges. A Device Mapper modulnak nincs névtér, ezért ha több Docker példány használja azt egy gépen, mindegyik látja (és hatással van) a másik képeire és a konténerek biztonsági mentési eszközeire. Ez ördögi.
Számos megoldás létezik sok ilyen probléma kezelésére. Például, ha AUFS-t szeretne használni a belső Dockerben, egyszerűen alakítsa át a /var/lib/docker mappát volume-vá, és minden rendben lesz. A Docker néhány alap névteret hozzáadott a Device Mapper célnevéhez, így ha több Docker hívást végeznek egy gépen, nem fognak egymásra „lépni”.
Ezeken a beállításokon való átbújás nem egyszerű, ahogy ez is látni lehet a dind GitHub tárolójában.
Docker-in-Docker: még rosszabbra fordul
Mi a helyzet a build cache-sel? Ez is elég bonyolult lehet. Az emberek gyakran megkérdezik tőlem: „ha Docker-in-Docker-t futtatok, hogyan tudom használni a gazdagépen található képeket, ahelyett, hogy mindent újra letöltenék a belső Dockeremhez?”
Néhány találékony ember megpróbálta összekapcsolni a /var/lib/docker-t a gazdagépről a Docker-in-Docker konténerrel. Néha megosztják a /var/lib/docker-t több konténer között.

Szeretnéd megsérteni az adatokat? Mert ez pontosan az, ami tönkreteszi az adataidat!
A Docker démon egyértelműen azért készült, hogy kizárólagos hozzáférése legyen a /var/lib/docker-hez. Semmi más nem érheti, piszkálhatja vagy érintheti meg a Docker fájlokat ebben a mappában.
Miért van ez így? Mert ez az egyik legnehezebb tanulsága a dotCloud fejlesztésének. A dotCloud konténermotorja úgy működött, hogy több folyamat egyszerre próbálta elérni a /var/lib/dotcloud-ot. Az olyan okos trükkök, mint a fájlok atomikus cseréje (ahelyett, hogy helyben szerkesztenénk), a kód „pepecselése” ajánlott és kötelező zárolásokkal és más kísérletekkel biztonságos rendszerekkel, mint az SQLite és a BDB, nem mindig működtek. Amikor átterveztük a konténermotorunkat, amely végül Dockerré vált, az egyik legfontosabb tervezési döntés az volt, hogy minden konténerrel kapcsolatos műveletet egyetlen démon alá vonjunk, hogy véget vessünk ennek a párhuzamos hozzáférésnek.
Ne érts félre: lehetséges valami jót, megbízhatót és gyorsat csinálni, ami párhuzamosan kezeli a több folyamatot. De úgy gondoljuk, hogy egyszerűbb és könnyebb kódot írni és karbantartani, ha a Dockert egyedüli szereplőként használjuk.
Ez azt jelenti, hogy ha megosztod a /var/lib/docker könyvtárat több Docker példány között, problémáid fognak adódni. Persze működhet, különösen a tesztelés korai szakaszában. „Figyelj, anya, el tudom indítani az ubuntu-t a dockeren!” De próbálj meg valami bonyolultat csinálni, például ugyanazt a képet lehúzni két különböző példányból, és meglátod, hogyan ég el a világ.
Ez azt jelenti, hogy ha a CI rendszered építkezéseket és újbóli építkezéseket végez, akkor minden alkalommal, amikor újraindítod a Docker-in-Docker konténert, kockázatot vállalsz, hogy egy nukleáris bombát dobjál a cache-ébe. Ez biztosan nem menő!
A probléma megoldása
Nézzük egy lépést hátra. Valóban szükséged van Docker-in-Docker-re, vagy csak azt szeretnéd, hogy lehetőséged legyen Docker-t futtatni, nevezetesen konténerek és képek buildelésére és futtatására a CI rendszeredből, miközben maga a CI rendszer egy konténerben van?
Megbeteszem, hogy a legtöbb embernek az utóbbi verzióra van szüksége, ami azt jelenti, hogy szeretnék, ha egy CI rendszer, mint például a Jenkins, képes lenne konténereket futtatni. És a legegyszerűbb módja ennek az, hogy egyszerűen csatlakoztatod a Docker socketet a CI konténeredhez, a -v flaggel.
Egyszerűbben fogalmazva, amikor futtatod a CI konténered (Jenkins vagy más), ahelyett, hogy valami hackelésbe kezdenél a Docker-in-Docker-rel, indítsd el a következő sorral:
docker run -v /var/run/docker.sock:/var/run/docker.sock ...Most ez a konténer hozzáfér a Docker sockethez, és ezáltal képes lesz konténereket futtatni. Csak annyit, hogy a "gyermek" konténerek helyett "rokon" konténereket fog futtatni.
Próbáld ki ezt az hivatalos docker képpel (ami tartalmaz egy Docker bináris fájlt):
docker run -v /var/run/docker.sock:/var/run/docker.sock
-ti dockerEz úgy néz ki és működik, mint a Docker-in-Docker, de nem az: amikor ez a konténer további konténereket épít, azok a felső szintű Dockerben jönnek létre. Nem tapasztalsz majd a beágyazottság mellékhatásait, és a build cache közösen lesz használva több hívás esetén.
Megjegyzés: A cikk korábbi verziói azt tanácsolták, hogy a Docker bináris fájlt a hostból a konténerbe kösd. Ez most már megbízhatatlanná vált, mivel a Docker mechanizmus már nem terjed ki statikus vagy szinte statikus könyvtárakra.
Tehát, ha Docker-t szeretnél használni a Jenkins CI-ből, két lehetőséged van:
Docker CLI telepítése a base image csomagolási rendszerével (azaz, ha az image-d Debian alapú, akkor .deb csomagokat használj), Docker API használata.
Egy kis reklám 🙂
Köszönjük, hogy velünk maradtál. Tetszenek a cikkeink? Szeretnél több érdekes anyagot látni? Támogass minket, és rendelés leadásával vagy ismerősöknek ajánlással segíts nekünk. , Egyedülálló alternatívája az entry-level szervereknek, amelyet Önnek találtunk ki: (elérhetők RAID1 és RAID10 opciók, akár 24 magig és 40GB DDR4-ig).
Dell R730xd kétszer olcsóbban a Tier IV Equinix adatközpontban Amszterdamban? Csak nálunk Hollandiában! Dell R420 — 2x E5-2430 2.2GHz 6C 128GB DDR3 2x960GB SSD 1Gbps 100TB — 99 dollártól! Olvasd el ezt
Forrás: habr.com
