Jak jsem spustil Docker uvnitř Dockeru a co z toho vzešlo

Ahoj všichni! V jeho předchozí článek, slíbil jsem, že budu mluvit o spuštění Dockeru v Dockeru a praktických aspektech používání této lekce. Je čas dodržet svůj slib. Zkušený devopser pravděpodobně namítne, že ti, kteří potřebují Docker uvnitř Dockeru, jednoduše přeposílají do kontejneru soket démona Docker z hostitele a to bude v 99 % případů stačit. Ale nespěchejte s házením cookies na mě, protože budeme mluvit o skutečném spuštění Dockeru uvnitř Dockeru. Toto řešení má mnoho možných aplikací a tento článek je o jedné z nich, takže se pohodlně posaďte a narovnejte ruce před sebou.

Jak jsem spustil Docker uvnitř Dockeru a co z toho vzešlo

začátek

Všechno to začalo jednoho deštivého zářijového večera, když jsem čistil stroj, který jsem si pronajal za 5 dolarů na Digital Ocean, který byl zamrzlý kvůli skutečnosti, že Docker svými obrázky a kontejnery zaplnil všech 24 gigabajtů dostupného místa na disku. Ironií bylo, že všechny tyto obrázky a kontejnery byly přechodné a byly potřeba pouze k testování výkonu mé aplikace pokaždé, když byla vydána nová verze knihovny nebo frameworku. Zkoušel jsem psát skripty shellu a nastavit plán cron na čištění odpadků, ale nepomohlo to: pokaždé to nevyhnutelně skončilo tím, že se mi zabralo místo na disku a server se zastavil (v nejlepším případě). V určitém okamžiku jsem narazil na článek o tom, jak spustit Jenkins v kontejneru a jak může vytvářet a odstraňovat sestavení potrubí přes docker daemon socket předaný do něj. Nápad se mi líbil, ale rozhodl jsem se jít dále a zkusit experimentovat s přímým spuštěním Dockeru uvnitř Dockeru. V té době se mi zdálo zcela logické řešení stáhnout si obrazy Dockeru a vytvořit kontejnery pro všechny aplikace, které jsem potřeboval pro testování uvnitř jiného kontejneru (říkejme tomu staging kontejner). Záměrem bylo spustit pracovní kontejner s parametrem -rm, který po zastavení automaticky odstraní celý kontejner a veškerý jeho obsah. Pohrál jsem si s obrázkem Dockeru ze samotného Dockeru (https://hub.docker.com/_/docker), ale ukázalo se, že je to příliš těžkopádné a nikdy se mi nepodařilo zprovoznit to tak, jak jsem potřeboval a chtěl jsem do toho jít sám.

Praxe. Šišky

Rozhodl jsem se, že nádoba bude fungovat tak, jak jsem potřeboval, a pokračoval ve svých experimentech, které vyústily v nesčetné množství pupenů. Výsledkem mého sebetrýznění byl následující algoritmus:

  1. Spustíme kontejner Docker v interaktivním režimu.

    docker run --privileged -it docker:18.09.6

    Věnujte pozornost verzi nádoby, krok vpravo nebo vlevo a váš DinD se promění v dýni. Ve skutečnosti se věci pokazí poměrně často, když je vydána nová verze.
    Musíme se okamžitě dostat do skořápky.

  2. Snažíme se zjistit, které kontejnery běží (odpověď: žádné), ale přesto spusťte příkaz:

    docker ps

    Budete trochu překvapeni, ale ukáže se, že démon Docker ani neběží:

    error during connect: Get http://docker:2375/v1.40/containers/json: dial tcp: lookup docker on 
    192.168.65.1:53: no such host

  3. Pojďme to spustit sami:

    dockerd &

    Další nepříjemné překvapení:

    failed to start daemon: Error initializing network controller: error obtaining controller instance: failed 
    to create NAT chain DOCKER: Iptables not found

  4. Nainstalujte balíčky iptables a bash (všechno je příjemnější pracovat v bash než v sh):

    apk add --no-cache iptables bash

  5. Spustíme bash. Konečně jsme zpět v obvyklé skořápce

  6. Zkusme znovu spustit Docker:

    dockerd &

    Měli bychom vidět dlouhý list protokolů končící na:

    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

  7. Stiskněte Enter. Jsme zpět v bash.

Od této chvíle se můžeme pokusit spustit další kontejnery v našem kontejneru Docker, ale co když chceme spustit další kontejner Docker v našem kontejneru Docker nebo se něco pokazí a kontejner se zhroutí? Začněte znovu.

Vlastní kontejner DinD a nové experimenty

Jak jsem spustil Docker uvnitř Dockeru a co z toho vzešlo
Abych se vyhnul opakování výše uvedených kroků znovu a znovu, vytvořil jsem svůj vlastní kontejner DinD:

https://github.com/alekslitvinenk/dind

Funkční řešení DinD mi dalo možnost spouštět Docker uvnitř Dockeru rekurzivně a dělat dobrodružnější experimenty.
Jeden takový (úspěšný) experiment se spuštěním MySQL a Nodejs teď popíšu.
Ti největší nedočkavci se mohou podívat, jak to tady bylo

Začněme tedy:

  1. Spouštíme DinD v interaktivním režimu. V této verzi DinD musíme ručně namapovat všechny porty, které mohou naše podřízené kontejnery používat (už na tom pracuji)

    docker run --privileged -it 
    -p 80:8080 
    -p 3306:3306 
    alekslitvinenk/dind

    Dostáváme se do bash, odkud můžeme okamžitě začít spouštět dětské kontejnery.

  2. Spusťte MySQL:

    docker run --name mysql -e MYSQL_ROOT_PASSWORD=strongpassword -d -p 3306:3306 mysql

  3. K databázi se připojujeme stejným způsobem, jako bychom se k ní připojovali lokálně. Ujistíme se, že vše funguje.

  4. Spusťte druhý kontejner:

    docker run -d --rm -p 8080:8080 alekslitvinenk/hello-world-nodejs-server

    Upozorňujeme, že mapování portů bude přesné 8080:8080, protože jsme již namapovali port 80 z hostitele do nadřazeného kontejneru na port 8080.

  5. V prohlížeči přejdeme na localhost a ujistěte se, že server odpovídá "Hello World!"

V mém případě dopadl experiment s vnořenými kontejnery Docker vcelku pozitivně a projekt budu dále rozvíjet a používat pro staging. Zdá se mi, že je to mnohem odlehčenější řešení než Kubernetes a Jenkins X. Ale to je můj subjektivní názor.

Myslím, že to je pro dnešní článek vše. V příštím článku popíšu podrobněji experimenty s rekurzivním spouštěním Dockeru v Dockeru a připojováním adresářů hluboko do vnořených kontejnerů.

PS Pokud považujete tento projekt za užitečný, dejte mu hvězdičku na GitHubu, rozklikněte jej a řekněte to svým přátelům.

Edit1 Opraveny chyby, zaměřeno na 2 videa

Zdroj: www.habr.com

Přidat komentář