Docker-in-Docker estas virtualigita Docker-demona medio funkcianta ene de la ujo mem por konstrui ujbildojn. La ĉefa celo de kreado de Docker-in-Docker estis helpi evoluigi Docker mem. Multaj homoj uzas ĝin por ruli Jenkins CI. Ĉi tio ŝajnas normala komence, sed poste aperas problemoj, kiuj povas esti evititaj instalante Docker en Jenkins CI-ujo. Ĉi tiu artikolo diras al vi kiel fari tion. Se vi interesiĝas pri la fina solvo sen detaloj, simple legu la lastan sekcion de la artikolo, "Solvanta la Problemon."
Docker-in-Docker: "Bona"
Antaŭ pli ol du jaroj mi metis en Docker
- hackity hako;
- konstrui;
- haltigi kurantan Docker-demonon;
- lanĉante novan Docker-demonon;
- testado;
- ripetu la ciklon.
Se vi volis fari belan, reprodukteblan asembleon (tio estas, en ujo), tiam ĝi fariĝis pli komplika:
- hackity hako;
- certigu, ke funkcianta versio de Docker funkcias;
- konstrui novan Docker kun malnova Docker;
- haltigu Docker-demonon;
- komenci novan Docker-demonon;
- testo;
- haltigi novan Docker-demonon;
- ripeti.
Kun la apero de Docker-in-Docker, la procezo fariĝis pli simpla:
- hackity hako;
- muntado + lanĉo en unu etapo;
- ripetu la ciklon.
Ĉu ne estas multe pli bone ĉi tiel?
Docker-in-Docker: "Malbona"
Tamen, kontraŭe al populara kredo, Docker-in-Docker ne estas 100% steloj, poneoj kaj unikornoj. Kion mi volas diri estas, ke estas pluraj aferoj, pri kiuj programisto devas esti konscia.
Unu el ili koncernas LSM-ojn (Linukso-sekurecaj moduloj) kiel AppArmor kaj SELinux: dum funkciado de ujo, la "interna Docker" eble provos apliki sekurecajn profilojn, kiuj konfliktos aŭ konfuzos la "eksteran Docker". Ĉi tio estas la plej malfacila problemo solvi kiam oni provas kunfandi la originan efektivigon de la flago –privilegia. Miaj ŝanĝoj funkciis kaj ĉiuj testoj transdonus mian Debianan maŝinon kaj Ubuntu-testajn VM-ojn, sed ili kraŝus kaj brulus sur la maŝino de Michael Crosby (li havis Fedora kiel mi memoras). Mi ne povas memori la precizan kaŭzon de la problemo, sed eble estis ĉar Mike estas saĝa ulo, kiu laboras kun SELINUX=enforce (mi uzis AppArmor) kaj miaj ŝanĝoj ne enkalkulis SELinux-profilojn.
Docker-in-Docker: "Malico"
La dua afero estas kun Docker-stokaj ŝoforoj. Kiam vi rulas Docker-in-Docker, ekstera Docker funkcias aldone al regula dosiersistemo (EXT4, BTRFS, aŭ kion ajn vi havas) kaj interna Docker funkcias aldone al kopi-sur-skriba sistemo (AUFS, BTRFS, Device Mapper). , ktp.). , depende de tio, kio estas agordita por uzi eksteran Docker). Ĉi tio kreas multajn kombinaĵojn, kiuj ne funkcios. Ekzemple, vi ne povos ruli AUFS super AUFS.
Se vi rulas BTRFS sur BTRFS, ĝi devus funkcii komence, sed post kiam estas nestitaj subvolumoj, forigo de la gepatra subvolumo malsukcesos. La Device Mapper-modulo havas neniun nomspacon, do se pluraj Docker-instancoj rulas ĝin sur la sama maŝino, ili ĉiuj povos vidi (kaj influi) la bildojn unu sur la alia kaj sur la uj-rezervaj aparatoj. Ĉi tio estas malbona.
Estas solvoj por solvi multajn el ĉi tiuj problemoj. Ekzemple, se vi volas uzi AUFS en interna Docker, simple turnu la dosierujon /var/lib/docker en volumon kaj vi estos bone. Docker aldonis kelkajn bazajn nomspacojn al Device Mapper celnomoj tiel ke se pluraj Docker-vokoj funkcias sur la sama maŝino, ili ne paŝas unu sur la alian.
Tamen tia aranĝo tute ne estas simpla, kiel oni povas vidi el ĉi tiuj
Docker-in-Docker: Ĝi plimalboniĝas
Kio pri la konstrukaŝmemoro? Ĉi tio ankaŭ povas esti sufiĉe malfacila. Homoj ofte demandas min "se mi rulas Docker-in-Docker, kiel mi povas uzi bildojn gastigitajn ĉe mia gastiganto anstataŭ tiri ĉion reen en mian internan Docker"?
Iuj entreprenemaj homoj provis ligi /var/lib/docker de la gastiganto al Docker-in-Docker-ujo. Kelkfoje ili kunhavas /var/lib/docker kun pluraj ujoj.
Ĉu vi volas korupti viajn datumojn? Ĉar ĝuste ĉi tio damaĝos viajn datumojn!
La Docker-demono estis klare dizajnita por havi ekskluzivan aliron al /var/lib/docker. Nenio alia devus "tuŝi, piki aŭ piki" iujn ajn Docker-dosierojn situantajn en ĉi tiu dosierujo.
Kial ĉi tio estas tiel? Ĉar ĉi tio estas la rezulto de unu el la plej malfacilaj lecionoj lernitaj dum disvolvado de dotCloud. La dotCloud-ujo-motoro funkciis havante plurajn procezojn alirantajn /var/lib/dotcloud samtempe. Ruzaj lertaĵoj kiel ekzemple atomdosieranstataŭaĵo (anstataŭ surloka redaktado), piprikodo kun konsilaj kaj devigaj seruroj, kaj aliaj eksperimentoj kun sekuraj sistemoj kiel ekzemple SQLite kaj BDB ne ĉiam funkciis. Kiam ni restrukturis nian ujran motoron, kiu poste iĝis Docker, unu el la grandaj dezajnaj decidoj estis plifirmigi ĉiujn ujajn operaciojn sub ununura demono por forigi ĉiujn samtempajn sensencaĵojn.
Ne miskomprenu min: estas tute eble fari ion bonan, fidindan kaj rapidan, kiu implikas plurajn procezojn kaj modernan paralelan kontrolon. Sed ni opinias, ke estas pli simpla kaj pli facile skribi kaj konservi kodon uzante Docker kiel la solan ludilon.
Ĉi tio signifas, ke se vi dividas la dosierujon /var/lib/docker inter pluraj Docker-okazoj, vi havos problemojn. Kompreneble, ĉi tio povas funkcii, precipe en la fruaj stadioj de testado. "Aŭskultu, panjo, mi povas funkciigi ubuntu kiel doker!" Sed provu ion pli kompleksan, kiel tiri la saman bildon el du malsamaj okazoj, kaj vi vidos la mondon bruli.
Ĉi tio signifas, ke se via CI-sistemo faras konstruojn kaj rekonstruojn, ĉiufoje kiam vi rekomencas vian Docker-in-Docker-ujon, vi riskas faligi atombombon en ĝian kaŝmemoron. Ĉi tio tute ne estas mojosa!
Problemo
Ni faru paŝon malantaŭen. Ĉu vi vere bezonas Docker-in-Docker aŭ ĉu vi nur volas povi ruli Docker kaj konstrui kaj ruli ujojn kaj bildojn de via CI-sistemo dum tiu CI-sistemo mem estas en ujo?
Mi vetas, ke plej multaj homoj volas ĉi-lastan opcion, tio signifas, ke ili volas CI-sistemon kiel Jenkins povi ruli ujojn. Kaj la plej facila maniero fari tion estas simple enigi Docker-ingon en vian CI-ujon kaj asocii ĝin kun la -v flago.
Simple dirite, kiam vi rulas vian CI-ujon (Jenkins aŭ alia), anstataŭ haki ion kune kun Docker-in-Docker, komencu ĝin per la linio:
docker run -v /var/run/docker.sock:/var/run/docker.sock ...
Ĉi tiu ujo nun havos aliron al la ingo Docker kaj do povos ruli ujojn. Krom ke anstataŭ ruli "infanajn" ujojn, ĝi lanĉos "fratajn" ujojn.
Provu ĉi tion uzante la oficialan docker-bildon (kiu enhavas la Docker-binaron):
docker run -v /var/run/docker.sock:/var/run/docker.sock
-ti docker
Ĝi aspektas kaj funkcias kiel Docker-in-Docker, sed ĝi ne estas Docker-in-Docker: kiam ĉi tiu ujo kreas pliajn ujojn, ili estos kreitaj en la plej alta nivelo Docker. Vi ne spertos la kromefikojn de nestado kaj la asembleokaŝmemoro estos dividita tra pluraj alvokoj.
Noto: Antaŭaj versioj de ĉi tiu artikolo konsilis ligi la binaron Docker de la gastiganto al la ujo. Ĉi tio nun fariĝis nefidinda ĉar la Docker-motoro ne plu kovras senmovajn aŭ preskaŭ senmovajn bibliotekojn.
Do, se vi volas uzi Docker de Jenkins CI, vi havas 2 eblojn:
instalante la Docker CLI uzante la bazan bildan paksistemon (t.e. se via bildo estas bazita sur Debian, uzu .deb-pakaĵojn), uzante la Docker API.
Kelkaj reklamoj 🙂
Dankon pro restado ĉe ni. Ĉu vi ŝatas niajn artikolojn? Ĉu vi volas vidi pli interesan enhavon? Subtenu nin farante mendon aŭ rekomendante al amikoj,
Dell R730xd 2 fojojn pli malmultekosta en Equinix Tier IV datumcentro en Amsterdamo? Nur ĉi tie
fonto: www.habr.com