Ahoj všichni! Ve svém , slíbil jsem, že se podělím o spuštění Dockera v Dockeru a o praktických aspektech aplikace této činnosti. Nastal čas splnit svůj slib. Zkušený DevOps by snad mohl nesouhlasit a říci, že ti, kdo potřebují Docker uvnitř Dockera, jednoduše přesměrují socket Docker démona z hostitele dovnitř kontejneru, což stačí v 99 % případů. Ale nespěchejte na mě házet sušenky, protože se bude jednat o skutečné spuštění Dockera uvnitř Dockera. Toto řešení má mnoho možných oblastí aplikace a o jednom z nich je tento článek, takže se usaďte pohodlně a vyrovnejte si ruce před sebe.

Začátek
Všechno začalo deštivým zářijovým večerem, když jsem čištěl pronajatý stroj za 5 USD na Digital Ocean, který zamrzl, protože Docker zaplnil svými obrazy a kontejnery všech 24 gigabajtů dostupného úložiště. Ironií bylo, že všechny tyto obrazy a kontejnery byly transientní a potřeboval jsem je jen k testování funkčnosti mé aplikace pokaždé, když vyšla nová verze nějaké knihovny či frameworku. Zkoušel jsem psát shell skripty a nastavovat cron pro úklid odpadu, ale to nepomohlo: pokaždé to nevyhnutelně končilo tím, že diskový prostor mého serveru byl zacenžován a server zamrzl (v tom lepším případě). V určitém okamžiku jsem narazil na článek o tom, jak spouštět Jenkins v kontejneru a jak může vytvářet a odstraňovat build pipeline přes přesměrovaný socket docker démona. Nápad se mi zalíbil, ale rozhodl jsem se zajít dál a vyzkoušet experimentovat s přímým spuštěním Dockera uvnitř Dockera. V té době se mi zdálo zcela logickým řešením stahovat docker obrazy a vytvářet kontejnery všech aplikací, které potřebuji pro testování uvnitř jiného kontejneru (nazvěme ho staging kontejner). Nápad spočíval v tom, spouštět staging kontejner s příznakem -rm, což automaticky odstraní celý kontejner se vším jeho obsahem při jeho zastavení. Zkoumal jsem docker obraz od samotného Dockera (), ale zjistil jsem, že je příliš objemný a nepodařilo se mi donutit ho pracovat tak, jak potřebuji, a chtěl jsem si projít celou cestu sám.
Praxe. Případné problémy
Stanovil jsem si za cíl dostat kontejner do provozu tak, jak jsem potřeboval, a pokračoval jsem ve svých experimentech, jejichž výsledkem bylo nespočet vylepšení. Výsledkem mého sebevzdělávání byl následující algoritmus:
Spouštíme Docker kontejner v interaktivním režimu.
docker run --privileged -it docker:18.09.6Všimněte si verze kontejneru, krok vpravo nebo vlevo a váš DinD se mění na dýni. Ve skutečnosti se to často pokazí s vydáním nové verze.
Musíme se okamžitě dostat do shellu.Zkusíme zjistit, které kontejnery jsou spuštěny (Odpověď: žádné), ale pojďme provést příkaz stejně:
docker psBudete trochu překvapeni, ale ukazuje se, že Docker démon 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 hostPojď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 foundInstalujeme balíčky iptables a bash (v bash je příjemnější pracovat než v sh):
apk add --no-cache iptables bashSpouštíme bash. Konečně jsme zpět v obvyklém shellu.
zkusíme spustit Docker znovu:
dockerd &Musíme vidět dlouhý výpis logů končící:
INFO[2019-11-25T19:51:19.448080400Z] Daemon has completed initialization INFO[2019-11-25T19:51:19.474439300Z] API listen on /var/run/docker.sockStiskneme Enter. Jsme znovu v bash.
Od tohoto okamžiku můžeme zkoušet spouštět další kontejnery uvnitř našeho Docker kontejneru, ale co když chceme spustit další Docker kontejner uvnitř našeho Docker kontejneru nebo něco nevyjde a kontejner "vypadne"? Začít znovu.
Vlastní DinD kontejner a nové experimenty.
Abych nemusel znovu a znovu opakovat výše popsané kroky, vytvořil jsem vlastní DinD kontejner:
Fungující DinD řešení mi umožnilo spouštět Docker uvnitř Dockeru rekurzivně a provádět odvážnější experimenty.
Jeden takový (úspěšný) experiment se spuštěním MySQL a Nodejs nyní popíšu.
Nejvíce netrpěliví si mohou prohlédnout, jak to bylo zde.

Tak začněme:
Spouštíme DinD v interaktivním režimu. V této verzi DinD musíme ručně namapovat všechny porty, které mohou používat naše podřízené kontejnery (na tom již pracuji).
docker run --privileged -it -p 80:8080 -p 3306:3306 alekslitvinenk/dindDostáváme se do bash, odkud můžeme okamžitě začít spouštět podřízené kontejnery.
Spouštíme MySQL:
docker run --name mysql -e MYSQL_ROOT_PASSWORD=strongpassword -d -p 3306:3306 mysqlPřipojujeme se k databázi stejně jako bychom se k ní připojovali lokálně. Ujistíme se, že vše funguje.
Spouštíme druhý kontejner:
docker run -d --rm -p 8080:8080 alekslitvinenk/hello-world-nodejs-serverVšimněte si, že mapování portu zde bude právě 8080:8080, protože jsme již namapovali port 80 z hostitele do rodičovského kontejneru na port 8080.
Jdeme na localhost v prohlížeči a ujistíme se, že server odpovídá "Hello World!".
V mém případě experiment s vloženými Docker kontejnery dopadl docela pozitivně a budu pokračovat v rozvoji projektu a jeho používání pro staging. Zdá se mi, že je to mnohem lehčí řešení než Kubernetes a Jenkins X. Ale to je můj subjektivní názor.
Myslím, že pro dnešní článek je to vše. V dalším článku podrobněji popíšu experimenty s rekurzivním spuštěním Dockeru v Dockeru a montování adresářů do hloubky vložených kontejnerů.
P.S. Pokud považujete tento projekt za užitečný, prosím, dejte mu hvězdičku na GitHubu, udělejte fork a řekněte o něm přátelům.
Edit1 Opravil jsem chyby, zaměřil jsem se na 2 videa
Zdroj: habr.com
