A Docker-in-Docker egy virtualizált Docker-démonkörnyezet, amely magában a tárolóban fut a tárolóképek létrehozásához. A Docker-in-Docker létrehozásának fő célja magának a Dockernek a fejlesztése volt. Sokan használják a Jenkins CI futtatására. Ez elsőre normálisnak tűnik, de aztán olyan problémák merülnek fel, amelyek elkerülhetők, ha a Dockert Jenkins CI tárolóba telepítik. Ez a cikk megmondja, hogyan kell ezt megtenni. Ha érdekli a részletek nélküli végső megoldás, csak olvassa el a cikk utolsó részét, „A probléma megoldása”.
Docker-in-Docker: "Jó"
Több mint két éve bekerültem a Dockerbe
- hackity hack;
- épít;
- egy futó Docker démon leállítása;
- új Docker démon elindítása;
- tesztelése;
- ismételje meg a ciklust.
Ha gyönyörű, reprodukálható összeállítást akart készíteni (vagyis konténerben), akkor bonyolultabb lett:
- hackity hack;
- győződjön meg arról, hogy a Docker működő verziója fut;
- építsen új Dockert a régi Dockerrel;
- Docker démon leállítása;
- indítson el egy új Docker démont;
- teszt;
- új Docker démon leállítása;
- ismétlés.
A Docker-in-Docker megjelenésével a folyamat egyszerűbbé vált:
- hackity hack;
- összeszerelés + indítás egy szakaszban;
- ismételje meg a ciklust.
Nem sokkal jobb így?
Docker-in-Docker: "Rossz"
A közhiedelemmel ellentétben azonban a Docker-in-Docker nem 100%-ban sztárok, pónik és unikornisok. Arra gondolok, hogy a fejlesztőnek több problémával tisztában kell lennie.
Az egyik az LSM-ekre (Linux biztonsági modulokra) vonatkozik, mint például az AppArmor és a SELinux: konténer futtatásakor a „belső Docker” megpróbálhat olyan biztonsági profilokat alkalmazni, amelyek ütköznek vagy összezavarják a „külső Dockert”. Ez a legnehezebben megoldható probléma a –privileged flag eredeti megvalósításának egyesítésekor. A módosításaim működtek, és minden teszt átment a Debian gépemen és az Ubuntu teszt virtuális gépeimen, de összeomlottak és kiégtek Michael Crosby gépén (ahogy emlékszem, Fedora volt neki). Nem emlékszem a probléma pontos okára, de lehet, hogy Mike egy bölcs fickó, aki SELINUX=enforce-szal dolgozik (én AppArmort használtam), és a változtatásaim nem vették figyelembe a SELinux profilokat.
Docker-in-Docker: "Gonosz"
A második probléma a Docker tároló-illesztőprogramokkal kapcsolatos. A Docker-in-Docker futtatásakor a külső Docker egy normál fájlrendszeren (EXT4, BTRFS vagy bármi más), a belső Docker pedig egy írásra másolási rendszeren (AUFS, BTRFS, Device Mapper) fut. stb.). , attól függően, hogy mi van konfigurálva külső Docker használatára). Ez sok olyan kombinációt hoz létre, amelyek nem működnek. Például nem tudja futtatni az AUFS-t az AUFS-en felül.
Ha a BTRFS-t a BTRFS-en felül futtatja, akkor először működnie kell, de ha vannak beágyazott alkötetek, a szülő alkötet törlése sikertelen lesz. Az Eszközleképező modulnak nincs névtere, így ha több Docker-példány futtatja ugyanazon a gépen, akkor mindegyik képes lesz látni (és befolyásolni) a képeket egymáson és a tároló biztonsági mentési eszközein. Ez rossz.
Sok ilyen probléma megoldására létezik megoldás. Például, ha AUFS-t szeretne használni a belső Dockerben, egyszerűen alakítsa át a /var/lib/docker mappát kötetté, és minden rendben lesz. A Docker hozzáadott néhány alapnévteret az Eszközleképező célneveihez, így ha több Docker-hívás fut ugyanazon a gépen, akkor nem lépnek egymásra.
Ez a beállítás azonban egyáltalán nem egyszerű, amint az ezekből is látszik
Docker-in-Docker: Egyre rosszabb
Mi a helyzet a build gyorsítótárral? Ez is elég nehéz lehet. Az emberek gyakran kérdezik tőlem, hogy „ha a Docker-in-Dockert futtatom, hogyan használhatom a gazdagépemen tárolt képeket ahelyett, hogy mindent visszahúznék a belső Dockerembe”?
Néhány vállalkozó szellemű ember megpróbálta a /var/lib/docker fájlt a gazdagépről egy Docker-in-Docker tárolóhoz kötni. Néha több tárolóval is megosztják a /var/lib/docker fájlt.
Meg akarja rontani az adatait? Mert pontosan ez fogja károsítani az adatait!
A Docker démont egyértelműen úgy tervezték, hogy kizárólagos hozzáféréssel rendelkezzen a /var/lib/docker fájlhoz. Semmi más nem „érinthet meg, bökhetne vagy produkálhat” az ebben a mappában található Docker-fájlokhoz.
Miért van ez így? Mert ez a dotCloud fejlesztése során levont egyik legnehezebb leckének az eredménye. A dotCloud konténermotor úgy futott, hogy egyszerre több folyamat is elérte a /var/lib/dotcloud fájlt. Az olyan furfangos trükkök, mint például az atomfájl cseréje (helyi szerkesztés helyett), a kódok figyelmeztető és kötelező zárolásokkal történő kiegészítése, valamint a biztonságos rendszerekkel, például az SQLite-tel és a BDB-vel végzett egyéb kísérletek nem mindig működtek. Amikor újraterveztük konténermotorunkat, amelyből végül Docker lett, az egyik nagy tervezési döntés az volt, hogy az összes konténerműveletet egyetlen démon alá vonjuk össze, hogy megszüntessük az összes párhuzamosítási hülyeséget.
Félreértés ne essék: teljesen lehetséges valami jót, megbízhatót és gyorsat készíteni, amely több folyamatot és modern párhuzamos vezérlést foglal magában. De úgy gondoljuk, hogy egyszerűbb és könnyebb kódot írni és karbantartani, ha a Dockert használja egyedüli lejátszóként.
Ez azt jelenti, hogy ha megosztja a /var/lib/docker könyvtárat több Docker-példány között, akkor problémái lesznek. Természetesen ez működhet, különösen a tesztelés korai szakaszában. – Figyelj, anya, én dokkolóként futtathatom az ubuntut! De próbáljon meg valami bonyolultabbat, például húzza ki ugyanazt a képet két különböző példányból, és látni fogja, hogy a világ égni fog.
Ez azt jelenti, hogy ha a CI-rendszere összeállításokat és újraépítéseket hajt végre, minden alkalommal, amikor újraindítja a Docker-in-Docker tárolót, fennáll annak a veszélye, hogy egy atommagot dob a gyorsítótárába. Ez egyáltalán nem menő!
Az oldat
Tegyünk egy lépést hátra. Valóban szüksége van a Docker-in-Dockerre, vagy csak azt szeretné, hogy a Docker futtasson, és konténereket és képeket készítsen és futtasson CI-rendszeréből, miközben maga a CI-rendszer egy tárolóban van?
Fogadok, hogy a legtöbb ember az utóbbi lehetőséget szeretné, vagyis azt akarják, hogy egy olyan CI rendszer, mint a Jenkins, képes legyen konténerek futtatására. Ennek a legegyszerűbb módja, ha egyszerűen behelyez egy Docker-aljzatot a CI-tárolóba, és társítja a -v jelzővel.
Egyszerűen fogalmazva, amikor futtatja a CI-tárolót (Jenkins vagy más), ahelyett, hogy feltörne valamit a Docker-in-Dockerrel, kezdje a következő sorral:
docker run -v /var/run/docker.sock:/var/run/docker.sock ...
Ez a tároló mostantól hozzá fog férni a Docker foglalathoz, és így képes lesz tárolók futtatására. Kivéve, hogy ahelyett, hogy „gyermek” tárolókat futtatna, „testvér” tárolókat indít el.
Próbálja ki ezt a hivatalos docker kép segítségével (amely tartalmazza a Docker bináris fájlt):
docker run -v /var/run/docker.sock:/var/run/docker.sock
-ti docker
Úgy néz ki, és úgy működik, mint a Docker-in-Docker, de nem a Docker-in-Docker: amikor ez a tároló további tárolókat hoz létre, azok a legfelső szintű Dockerben jönnek létre. Nem fogja tapasztalni a beágyazás mellékhatásait, és az összeállítási gyorsítótár több hívás között meg lesz osztva.
Megjegyzés: A cikk korábbi verziói azt javasolták, hogy a Docker-binárist a gazdagépről a tárolóhoz kapcsolják. Ez mára megbízhatatlanná vált, mivel a Docker-motor már nem fedi le a statikus vagy csaknem statikus könyvtárakat.
Tehát, ha a Jenkins CI Docker-jét szeretné használni, két lehetősége van:
a Docker parancssori felület telepítése az alapképcsomag-rendszerrel (azaz ha a kép Debian-on alapul, használjon .deb csomagokat), a Docker API használatával.
Néhány hirdetés 🙂
Köszönjük, hogy velünk tartott. Tetszenek cikkeink? További érdekes tartalmakat szeretne látni? Támogass minket rendeléssel vagy ajánlj ismerőseidnek,
A Dell R730xd kétszer olcsóbb az amszterdami Equinix Tier IV adatközpontban? Csak itt
Forrás: will.com