Důkladně přemýšlejte, než začnete používat Docker-in-Docker pro CI nebo testovací prostředí.

Důkladně přemýšlejte, než začnete používat Docker-in-Docker pro CI nebo testovací prostředí.

Docker-in-Docker představuje virtualizované prostředí Docker démonu spuštěného uvnitř samotného kontejneru pro sestavení obrazů kontejnerů. Hlavním cílem vytvoření Docker-in-Docker byla pomoc při vývoji samotného Dockeru. Mnoho lidí jej používá k spuštění Jenkins CI. Zpočátku se to zdá normální, ale pak se objeví problémy, kterým se lze vyhnout, pokud nainstalujete Docker do kontejneru Jenkins CI. V tomto článku se dozvíte, jak to udělat. Pokud vás zajímá konečné řešení bez podrobností, přečtěte si pouze poslední část článku "Řešení problému".

Důkladně přemýšlejte, než začnete používat Docker-in-Docker pro CI nebo testovací prostředí.

Docker-in-Docker: "Dobré"

Před více než dvěma lety jsem vložil do Dockeru příznak --privileged a napsal první verzi dind. Cílem bylo pomoci hlavnímu týmu vyvíjet Docker rychleji. Před vznikem Docker-in-Docker byl typický vývojový cyklus takový:

  • hackity hack;
  • sestavení (build);
  • zastavení spuštěného Docker démonu;
  • spuštění nového Docker démonu;
  • testování;
  • opakování cyklu.

Pokud jste chtěli vytvořit hezké, reprodukovatelné sestavení (tedy v kontejneru), stávalo se to složitější:

  • hackity hack;
  • ujistit se, že je spuštěna funkční verze Docker;
  • sestavit nový Docker se starým Dockerem;
  • zastavit Docker démon;
  • spuštění nového Docker démonu;
  • testování;
  • zastavit nový Docker démon;
  • opakovat.

S příchodem Docker-in-Docker se proces zjednodušil:

  • hackity hack;
  • sestavení + spuštění v jednom kroku;
  • opakování cyklu.

Není to lepší?

Důkladně přemýšlejte, než začnete používat Docker-in-Docker pro CI nebo testovací prostředí.

Docker-in-Docker: "Špatné"

Ale, navzdory běžným názorům, Docker-in-Docker není z 100% samé hvězdičky, poníci a jednorožci. Mám na mysli, že existuje několik problémů, o kterých by vývojář měl vědět.

Jedním z problémů jsou LSM (moduly zabezpečení Linuxu), jako jsou AppArmor a SELinux: při spuštění kontejneru „vnitřní Docker“ se může pokusit aplikovat bezpečnostní profily, které budou konfliktní nebo zmatené s „vnějším Dockerem“. Toto byla nejkomplexnější otázka, kterou bylo třeba řešit při snaze integrovat původní implementaci příznaku –privileged. Mé změny fungovaly a všechny testy by také prošly na mém Debianu a testovací virtuální ploše Ubuntu, ale zhroutily by se na stroji Michaela Crosbieho (pokud si pamatuji, měl Fedora). Nebo si nemohu vzpomenout na přesný důvod, ale možná to bylo proto, že Mike — moudrý člověk, který pracuje s SELINUX=enforce (já jsem použil AppArmor), a mé změny nezohlednily profily SELinux.

Docker-in-Docker: „Zlý“

Druhý problém souvisí s ovladači úložiště Dockeru. Když spustíte Docker-in-Docker, vnější Docker funguje nad běžným souborovým systémem (EXT4, BTRFS nebo jakýmkoliv jiným, který máte k dispozici), zatímco vnitřní Docker funguje nad systémem copy-on-write (AUFS, BTRFS, Device Mapper atd., v závislosti na tom, co je nastaveno pro použití vnějším Dockerem). Tím vznikají různé kombinace, které nebudou fungovat. Například nemůžete spouštět AUFS nad AUFS.

Pokud spustíte BTRFS nad BTRFS, mělo by to ze začátku fungovat, ale jakmile se objeví vnořené podobjemy, nebude možné odstranit nadřazený podobjem. Modul Device Mapper nemá prostory názvů, takže pokud několik instancí Dockeru používá jeden na stejném stroji, všechny budou moci vidět (a ovlivňovat) obrazy vzájemně a zařízení pro zálohování kontejnerů. To je špatné.

Existují obchody k řešení mnoha z těchto problémů. Například pokud chcete používat AUFS ve vnitřním Dockeru, stačí převést složku /var/lib/docker na to a všechno bude v pořádku. Docker přidal některé základní prostory názvů cílovým názvům Device Mapperu, takže pokud bude na jednom stroji probíhat několik volání Dockeru, nebudou si „stoupnout“ do cesty.

Nicméně, taková konfigurace není vůbec jednoduchá, jak je možné vidět z těchto článků v repozitáři dind na GitHubu.

Docker-in-Docker: je to ještě horší

A co cache sestavení? To může být také docela komplikované. Lidé se mě často ptají: „když spouštím Docker-in-Docker, jak mohu použít obrazy umístěné na mém hostitelském systému místo toho, abych je znovu stahoval do mého interního Dockeru?“

Někteří podnikaví lidé se pokusili připojit /var/lib/docker z hostitele do Docker-in-Docker kontejneru. Někdy sdílejí /var/lib/docker mezi několika kontejnery.

Důkladně přemýšlejte, než začnete používat Docker-in-Docker pro CI nebo testovací prostředí.
Chcete poškodit data? Protože to je přesně to, co poškodí vaše data!

Docker démon byl zjevně navržen tak, aby měl výhradní přístup k /var/lib/docker. Nic jiného by nemělo "dotýkat se, ťukat nebo zkoumat" jakékoli soubory Dockeru, nacházející se v této složce.

Proč je to tak? Protože to je výsledek jedné z nejtvrdších lekcí, které jsme se naučili při vývoji dotCloud. Kontejnerový engine dotCloud fungoval s několika procesy, které současně přistupovaly k /var/lib/dotcloud. Chytré triky, jako je atomová výměna souborů (namísto úprav na místě), "pálkování" kódu doporučujícími a povinnými zámky a další experimenty se zabezpečenými systémy, jako je SQLite a BDB, ne vždy fungovaly. Když jsme přepracovávali náš kontejnerový engine, který se nakonec stal Dockerem, jedním z hlavních designových rozhodnutí bylo seskupit všechny operace s kontejnery pod jeden démon, aby jsme skoncovali s veškerou tou hloupostí současného přístupu.

Nepochopte mě špatně: je zcela možné udělat něco dobrého, spolehlivého a rychlého, co zahrnuje několik procesů a moderní paralelní řízení. Ale myslíme si, že je jednodušší a snazší psát a udržovat kód, když používáme Docker jako jediného hráče.

To znamená, že pokud sdílíte adresář /var/lib/docker mezi několika instancemi Dockeru, budete mít problémy. Samozřejmě, že to může fungovat, zejména na počátku testování. "Poslouchej, mámo, mohu spustit ubuntu přes Docker!" Ale zkuste udělat něco složitějšího, například vytáhnout stejný obraz z dvou různých instancí, a uvidíte, jak svět hoří.

To znamená, že pokud váš CI systém provádí sestavení a přestavby, při každém restartu kontejnmentu Docker-in-Docker riskujete vyresetování jeho cache s bombou. To rozhodně není cool!

Řešení problému

Pojďme se vrátit krok zpět. Opravdu potřebujete Docker-in-Docker, nebo jen chcete mít možnost spouštět Docker, tedy sestavovat a spouštět kontejnery a obrázky ze svého CI systému, zatímco tento CI systém je v kontejneru?

Vsadím se, že většině lidí potřebují tu poslední variantu, to znamená, že chtějí, aby CI systém, jako Jenkins, mohl spouštět kontejnery. A nejjednodušší způsob, jak toho dosáhnout, je jednoduše připojit Docker socket k vašemu CI kontejneru s pomocí příznaku -v.

Jinými slovy, když spouštíte svůj CI kontejner (Jenkins nebo jiný), místo hackování něco s Docker-in-Docker, začněte ho tímto způsobem:

docker run -v /var/run/docker.sock:/var/run/docker.sock ...

Nyní tento kontejner bude mít přístup k Docker socketu a tudíž bude moci spouštět kontejnery. Akorát, že místo spouštění "potomních" kontejnerů bude spouštět "příbuzné" kontejnery.

Zkuste to s oficiálním obrazem docker (který obsahuje binární soubor Docker):

docker run -v /var/run/docker.sock:/var/run/docker.sock 
           -ti docker

Vypadá to a funguje to jako Docker-in-Docker, ale to není Docker-in-Docker: když tento kontejner vytvoří další kontejnery, budou vytvořeny v nadřazeném Dockeru. Nebudete mít zkušenosti s vedlejšími efekty vnoření a cache sestavení bude sdíleno pro více volání.

Poznámka: Předchozí verze tohoto článku doporučovaly připojit binární soubor Docker z hostitele k kontejneru. To se nyní stalo nespolehlivým, protože mechanismus Dockeru již není rozšířen na statické nebo téměř statické knihovny.

Takže pokud chcete používat Docker z Jenkins CI, máte 2 možnosti:
instalace Docker CLI pomocí základního systému balíčků (t.j. pokud je váš obraz založen na Debianu, použijte balíčky .deb), použití Docker API.

Malá reklama 🙂

Děkujeme, že s námi zůstáváte. Líbí se vám naše články? Chcete vidět více zajímavých materiálů? Podpořte nás objednávkou nebo doporučením známým, cloudové VPS pro vývojáře od 4,99 $, unikátní alternativa entry-level serverů, kterou jsme pro vás vymysleli: Všechny pravdy o VPS (KVM) E5-2697 v3 (6 jader) 10GB DDR4 480GB SSD 1Gbps od 19 $ nebo jak správně rozdělit server? (k dispozici varianty s RAID1 a RAID10, až 24 jader a až 40GB DDR4).

Dell R730xd je dvakrát levnější v datovém centru Equinix Tier IV v Amsterdamu? Jen u nás 2 x Intel TetraDeca-Core Xeon 2x E5-2697v3 2.6GHz 14C 64GB DDR4 4x960GB SSD 1Gbps 100 TB od 199 $ v Nizozemsku! Dell R420 — 2x E5-2430 2.2GHz 6C 128GB DDR3 2x960GB SSD 1Gbps 100TB — od 99 $! Čtěte o tom Jak postavit infrastrukturu podnikové třídy s použitím serverů Dell R730xd E5-2650 v4 v hodnotě 9000 eur za pakatel?

Zdroj: habr.com

Koupit spolehlivý hosting pro webové stránky s ochranou proti DDoS, VPS VDS servery 🔥 Koupit spolehlivý hosting pro webové stránky s ochranou proti DDoS, VPS VDS servery | ProHoster