Docker-in-Docker je virtuelizirani Docker demon koji radi na samom kontejneru za izgradnju slika kontejnera. Glavna svrha kreiranja Docker-in-Docker-a bila je pomoć u razvoju samog Docker-a. Mnogi ljudi ga koriste za pokretanje Jenkins CI. Ovo se u početku čini normalnim, ali onda nastaju problemi koji se mogu izbjeći instaliranjem Dockera u Jenkins CI kontejner. Ovaj članak objašnjava kako to učiniti. Ako vas zanima konačno rješenje bez detalja, samo pročitajte posljednji odjeljak članka Rješavanje problema.
Docker-in-Docker: Dobro
Prije više od dvije godine stavio sam Docker
- hackity hack;
- montaža (gradnja);
- zaustaviti pokretanje Docker demona;
- pokretanje novog Docker demona;
- testiranje;
- ciklus ponoviti.
Ako ste htjeli napraviti lijepu, ponovljivu montažu (odnosno u kontejneru), onda je postalo složenije:
- hackity hack;
- provjerite da li radi funkcionalna verzija Dockera;
- izgraditi novi Docker sa starim Dockerom;
- zaustaviti docker demon;
- pokrenuti novi Docker demon;
- test;
- zaustaviti novi Docker demon;
- ponovi.
Pojavom Docker-in-Docker-a, proces je pojednostavljen:
- hackity hack;
- montaža + pokretanje u jednom koraku;
- ciklus ponoviti.
Nije li to mnogo bolje?
Docker-in-Docker: "Loše"
Međutim, suprotno popularnom vjerovanju, Docker-in-Docker nije 100% zvijezda, poniji i jednorozi. Mislim, postoji nekoliko problema kojih programer mora biti svjestan.
Jedan se tiče LSM-ova (Linux sigurnosnih modula) kao što su AppArmor i SELinux: kada se pokreće kontejner, "interni Docker" može pokušati primijeniti sigurnosne profile koji će biti u sukobu ili zamagljivati "spoljni Docker". Ovo je najteži problem za rješavanje kada se pokušava kombinirati originalna implementacija --privileged zastavice. Moje promjene su funkcionirale i svi testovi bi također prošli na mojoj Debian mašini i testirali Ubuntu VM, ali bi se srušili i spalili na mašini Michaela Crosbyja (imao je Fedoru koliko se sjećam). Ne mogu se sjetiti tačnog uzroka problema, ali možda je to zato što je Mike mudar čovjek koji radi sa SELINUX=enforce (koristio sam AppArmor) i moje promjene nisu poštovale SELinux profile.
Docker-in-Docker: "Zlo"
Drugi problem se odnosi na Docker drajvere za skladištenje. Kada pokrenete Docker-in-Docker, eksterni Docker radi na vrhu običnog sistema datoteka (EXT4, BTRFS, ili šta god imate), dok se interni Docker pokreće na sistemu kopiranja na upisivanje (AUFS, BTRFS , Device Mapper, itd.). , u zavisnosti od toga šta je konfigurisano da koristi eksterni Docker). U ovom slučaju postoji mnogo kombinacija koje neće raditi. Na primjer, nećete moći pokrenuti AUFS na vrhu AUFS-a.
Ako koristite BTRFS na vrhu BTRFS-a, ovo bi u početku trebalo funkcionirati, ali kada postoje ugniježđeni podvolumen, roditeljski podvolumen se ne može izbrisati. Modul Device Mapper je bez imenskog prostora, tako da ako ga više Docker instanci koristi na istoj mašini, svi će moći da vide (i utiču) na slike jedni drugih i uređaja za rezervnu kopiju kontejnera. Ovo je loše.
Postoje rješenja za rješavanje mnogih od ovih problema. Na primjer, ako želite da koristite AUFS u internom Docker-u, samo pretvorite /var/lib/docker folder u volumen i sve će biti u redu. Docker je dodao neke osnovne prostore imena imenima cilja uređaja Device Mapper tako da ako se više Docker poziva izvrši na istoj mašini, oni neće "nagaziti" jedan na drugog.
Međutim, ovo podešavanje nije nimalo jednostavno, kao što možete vidjeti iz ovih
Docker-in-Docker: Sve gore
Šta je sa keš memorijom za izgradnju? Ovo također može biti prilično nezgodno. Ljudi me često pitaju “ako koristim Docker-in-Docker, kako mogu koristiti slike koje se nalaze na mom hostu umjesto da ponovo povlačim sve u svom internom Docker-u”?
Neki preduzimljivi ljudi pokušali su povezati /var/lib/docker sa hosta na Docker-in-Docker kontejner. Ponekad dijele /var/lib/docker s više kontejnera.
Želite oštetiti podatke? Jer upravo to će oštetiti vaše podatke!
Docker daemon je jasno dizajniran da ima ekskluzivni pristup /var/lib/docker. Ništa drugo ne bi trebalo "dodirnuti, bockati ili opipati" bilo koje Docker datoteke koje se nalaze u ovoj fascikli.
Zašto je tako? Zato što je to rezultat jedne od najtežih lekcija naučenih u razvoju dotCloud-a. DotCloud kontejnerski mehanizam je radio tako što je imao više procesa koji istovremeno pristupaju /var/lib/dotcloudu. Lukavi trikovi kao što su atomska zamjena fajlova (umjesto uređivanja na mjestu), začinjavanje koda savjetodavnim i obaveznim bravama i drugi eksperimenti sa sigurnim sistemima kao što su SQLite i BDB nisu uvijek radili. Kada smo redizajnirali naš motor kontejnera, koji je na kraju postao Docker, jedna od glavnih dizajnerskih odluka bila je da prikupimo sve operacije kontejnera pod jednim demonom kako bismo uklonili sve ove gluposti o konkurentnosti.
Nemojte me pogrešno shvatiti: potpuno je moguće napraviti nešto lijepo, pouzdano i brzo što uključuje više procesa i modernu paralelnu kontrolu. Ali mislimo da je lakše i lakše pisati i održavati kod uz Docker kao jedinog igrača.
To znači da ako dijelite /var/lib/docker direktorij na više Docker instanci, bit ćete u nevolji. Naravno, ovo može funkcionirati, posebno u ranim fazama testiranja. “Slušaj, mama, mogu pokrenuti ubuntu s docker-om!” Ali pokušajte nešto složenije, poput izvlačenja iste slike iz dvije različite instance, i vidjet ćete kako svijet gori.
To znači da ako vaš CI sistem gradi i rekonstruiše, onda svaki put kada ponovo pokrenete svoj Docker-in-Docker kontejner, rizikujete da bacite nuklearnu bombu u njegovu keš memoriju. Uopšte nije kul!
Rešavanje problema
Hajdemo korak unazad. Da li vam je zaista potreban Docker-in-Docker, ili samo želite da možete da pokrenete Docker, odnosno da pravite i pokrećete kontejnere i slike iz vašeg CI sistema, dok je sam taj CI sistem u kontejneru?
Kladim se da većina ljudi želi potonju opciju, tj. žele da CI sistem poput Jenkinsa može pokretati kontejnere. A najlakši način da to učinite je da jednostavno umetnete Docker utičnicu u svoj CI kontejner povezujući ga sa -v zastavicom.
Jednostavno rečeno, kada pokrenete svoj CI kontejner (Jenkins ili na neki drugi način), umjesto da hakujete zajedno sa Docker-in-Docker-om, započnite ga sa linijom:
docker run -v /var/run/docker.sock:/var/run/docker.sock ...
Ovaj kontejner će sada imati pristup Docker socketu i stoga će moći pokretati kontejnere. Osim što će umjesto pokretanja "podređenih" kontejnera pokrenuti kontejnere "sestra".
Isprobajte ovo koristeći zvaničnu docker sliku (koja sadrži docker binarnu datoteku):
docker run -v /var/run/docker.sock:/var/run/docker.sock
-ti docker
Izgleda i radi kao Docker-in-Docker, ali nije Docker-in-Docker: kada ovaj kontejner kreira dodatne kontejnere, oni će biti kreirani u Docker-u najvišeg nivoa. Nećete iskusiti nuspojave ugniježđenja, a keš sklopa će se dijeliti na više poziva.
Napomena: Prethodne verzije ovog članka savjetovale su povezivanje Docker binarne datoteke od hosta do kontejnera. Ovo je sada postalo nepouzdano jer se Docker engine više ne proširuje na statične ili skoro statične biblioteke.
Dakle, ako želite koristiti Docker iz Jenkins CI, imate 2 opcije:
instaliranje Docker CLI koristeći osnovni sustav pakiranja slika (tj. ako je vaša slika bazirana na Debianu, koristite .deb pakete), koristeći Docker API.
Neke reklame 🙂
Hvala vam što ste ostali s nama. Da li vam se sviđaju naši članci? Želite li vidjeti još zanimljivih sadržaja? Podržite nas naručivanjem ili preporukom prijateljima,
Dell R730xd 2 puta jeftiniji u Equinix Tier IV data centru u Amsterdamu? Samo ovdje
izvor: www.habr.com