Mag-isip nang mabuti bago gamitin ang Docker-in-Docker para sa CI o kapaligiran ng pagsubok

Mag-isip nang mabuti bago gamitin ang Docker-in-Docker para sa CI o kapaligiran ng pagsubok

Ang Docker-in-Docker ay isang virtualized na Docker daemon na kapaligiran na tumatakbo sa loob mismo ng container upang bumuo ng mga imahe ng container. Ang pangunahing layunin ng paglikha ng Docker-in-Docker ay upang makatulong na bumuo ng Docker mismo. Maraming tao ang gumagamit nito upang patakbuhin ang Jenkins CI. Mukhang normal ito sa una, ngunit pagkatapos ay lumitaw ang mga problema na maiiwasan sa pamamagitan ng pag-install ng Docker sa isang lalagyan ng Jenkins CI. Sinasabi sa iyo ng artikulong ito kung paano ito gagawin. Kung interesado ka sa panghuling solusyon nang walang mga detalye, basahin lamang ang huling seksyon ng artikulo, "Paglutas ng Problema."

Mag-isip nang mabuti bago gamitin ang Docker-in-Docker para sa CI o kapaligiran ng pagsubok

Docker-in-Docker: "Maganda"

Mahigit dalawang taon na ang nakalipas ay inilagay ko sa Docker bandila –pribilehiyo at nagsulat unang bersyon ng dind. Ang layunin ay tulungan ang pangunahing koponan na bumuo ng Docker nang mas mabilis. Bago ang Docker-in-Docker, ang karaniwang ikot ng pag-unlad ay ganito ang hitsura:

  • hackity hack;
  • bumuo;
  • pagpapahinto sa isang tumatakbong Docker daemon;
  • paglulunsad ng bagong Docker daemon;
  • pagsubok;
  • ulitin ang cycle.

Kung nais mong gumawa ng isang maganda, maaaring kopyahin na pagpupulong (iyon ay, sa isang lalagyan), kung gayon ito ay naging mas masalimuot:

  • hackity hack;
  • tiyaking gumagana ang isang gumaganang bersyon ng Docker;
  • bumuo ng bagong Docker gamit ang lumang Docker;
  • itigil ang Docker daemon;
  • magsimula ng bagong Docker daemon;
  • pagsusulit;
  • itigil ang bagong Docker daemon;
  • ulitin.

Sa pagdating ng Docker-in-Docker, ang proseso ay naging mas simple:

  • hackity hack;
  • pagpupulong + paglulunsad sa isang yugto;
  • ulitin ang cycle.

Hindi ba't mas mabuti sa ganitong paraan?

Mag-isip nang mabuti bago gamitin ang Docker-in-Docker para sa CI o kapaligiran ng pagsubok

Docker-in-Docker: "Masama"

Gayunpaman, salungat sa tanyag na paniniwala, ang Docker-in-Docker ay hindi 100% na mga bituin, kabayo at unicorn. Ang ibig kong sabihin ay mayroong ilang mga isyu na kailangang malaman ng isang developer.

Ang isa sa mga ito ay tungkol sa mga LSM (Linux security modules) tulad ng AppArmor at SELinux: kapag nagpapatakbo ng container, maaaring subukan ng "internal Docker" na maglapat ng mga profile ng seguridad na salungat o malito ang "external Docker". Ito ang pinakamahirap na problemang lutasin kapag sinusubukang pagsamahin ang orihinal na pagpapatupad ng –privileged flag. Ang aking mga pagbabago ay gumana at lahat ng mga pagsubok ay ipapasa sa aking Debian machine at Ubuntu test VMs, ngunit sila ay mag-crash at masunog sa makina ni Michael Crosby (siya ay may Fedora bilang naaalala ko). Hindi ko maalala ang eksaktong dahilan ng problema, ngunit maaaring ito ay dahil si Mike ay isang matalinong tao na nagtatrabaho sa SELINUX=enforce (ginamit ko ang AppArmor) at ang aking mga pagbabago ay hindi isinasaalang-alang ang mga profile ng SELinux.

Docker-in-Docker: "Masama"

Ang pangalawang isyu ay sa mga driver ng imbakan ng Docker. Kapag nagpatakbo ka ng Docker-in-Docker, ang panlabas na Docker ay tumatakbo sa ibabaw ng isang regular na file system (EXT4, BTRFS, o anumang mayroon ka) at ang panloob na Docker ay tumatakbo sa ibabaw ng isang copy-on-write system (AUFS, BTRFS, Device Mapper , atbp.). , depende sa kung ano ang naka-configure upang magamit ang panlabas na Docker). Lumilikha ito ng maraming kumbinasyon na hindi gagana. Halimbawa, hindi mo magagawang patakbuhin ang AUFS sa ibabaw ng AUFS.

Kung magpapatakbo ka ng BTRFS sa itaas ng BTRFS, dapat itong gumana sa una, ngunit kapag may mga nested na subvolume, mabibigo ang pagtanggal sa parent subvolume. Ang module ng Device Mapper ay walang namespace, kaya kung maraming Docker instance ang nagpapatakbo nito sa parehong makina, makikita (at maimpluwensyahan) nilang lahat ang mga imahe sa isa't isa at sa mga backup na device ng container. Masama ito.

Mayroong mga solusyon upang malutas ang marami sa mga problemang ito. Halimbawa, kung gusto mong gumamit ng AUFS sa panloob na Docker, gawing volume lang ang /var/lib/docker folder at magiging maayos ka. Nagdagdag si Docker ng ilang mga base namespace sa mga target na pangalan ng Device Mapper upang kung maraming tawag sa Docker ay tumatakbo sa parehong makina, hindi sila magtatapak sa isa't isa.

Gayunpaman, ang gayong pag-setup ay hindi lahat simple, tulad ng makikita mula sa mga ito Artikulo sa dind repository sa GitHub.

Docker-in-Docker: Lumalala ito

Paano naman ang build cache? Ito ay maaari ding medyo mahirap. Madalas itanong sa akin ng mga tao "kung nagpapatakbo ako ng Docker-in-Docker, paano ko magagamit ang mga larawang naka-host sa aking host sa halip na ibalik ang lahat sa aking panloob na Docker"?

Sinubukan ng ilang masigasig na tao na itali ang /var/lib/docker mula sa host patungo sa isang container ng Docker-in-Docker. Minsan nagbabahagi sila ng /var/lib/docker sa maraming container.

Mag-isip nang mabuti bago gamitin ang Docker-in-Docker para sa CI o kapaligiran ng pagsubok
Gusto mo bang sirain ang iyong data? Dahil ito mismo ang makakasira sa iyong data!

Ang Docker daemon ay malinaw na idinisenyo upang magkaroon ng eksklusibong pag-access sa /var/lib/docker. Wala nang iba pang dapat "hawakan, sundutin, o itulak" ang anumang mga file ng Docker na matatagpuan sa folder na ito.

Bakit ganito? Dahil ito ang resulta ng isa sa pinakamahirap na aral na natutunan habang binubuo ang dotCloud. Ang dotCloud container engine ay tumakbo sa pamamagitan ng pagkakaroon ng maraming proseso sa pag-access sa /var/lib/dotcloud nang sabay-sabay. Ang mga tusong trick gaya ng pagpapalit ng atomic file (sa halip na in-place na pag-edit), peppering code na may advisory at mandatory lock, at iba pang mga eksperimento na may mga secure na system gaya ng SQLite at BDB ay hindi palaging gumagana. Noong nire-redesign namin ang aming container engine, na kalaunan ay naging Docker, isa sa mga malalaking desisyon sa disenyo ay pagsama-samahin ang lahat ng mga operasyon ng container sa ilalim ng isang daemon para mawala ang lahat ng concurrency na kalokohan.

Huwag kang magkamali: ganap na posible na gumawa ng isang bagay na mabuti, maaasahan at mabilis na nagsasangkot ng maraming proseso at modernong parallel na kontrol. Ngunit sa tingin namin ay mas simple at mas madaling magsulat at magpanatili ng code gamit ang Docker bilang ang tanging manlalaro.

Nangangahulugan ito na kung ibabahagi mo ang direktoryo ng /var/lib/docker sa pagitan ng maraming instance ng Docker, magkakaroon ka ng mga problema. Siyempre, maaari itong gumana, lalo na sa mga unang yugto ng pagsubok. "Makinig, Ma, maaari kong patakbuhin ang ubuntu bilang isang docker!" Ngunit subukan ang isang bagay na mas kumplikado, tulad ng paghila sa parehong imahe mula sa dalawang magkaibang mga pagkakataon, at makikita mo ang mundo na nasusunog.

Nangangahulugan ito na kung ang iyong CI system ay nagsasagawa ng mga build at muling pagtatayo, sa tuwing i-restart mo ang iyong Docker-in-Docker container, nanganganib kang maghulog ng nuke sa cache nito. Ito ay hindi cool sa lahat!

Ang solusyon

Umatras tayo ng isang hakbang. Kailangan mo ba talaga ng Docker-in-Docker o gusto mo lang na mapatakbo ang Docker at bumuo at magpatakbo ng mga lalagyan at mga imahe mula sa iyong CI system habang ang CI system mismo ay nasa isang lalagyan?

Pustahan ako na gusto ng karamihan sa mga tao ang huli na opsyon, ibig sabihin gusto nila ang isang CI system tulad ng Jenkins na makapagpatakbo ng mga lalagyan. At ang pinakamadaling paraan para gawin ito ay ang simpleng pagpasok ng Docker socket sa iyong CI container at iugnay ito sa -v flag.

Sa madaling salita, kapag pinatakbo mo ang iyong CI container (Jenkins o iba pa), sa halip na mag-hack ng isang bagay kasama ng Docker-in-Docker, simulan ito sa linya:

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

Magkakaroon na ngayon ng access ang container na ito sa Docker socket at samakatuwid ay makakapagpatakbo ng mga container. Maliban na sa halip na magpatakbo ng mga lalagyan ng "bata", maglulunsad ito ng mga lalagyan ng "kapatid".

Subukan ito gamit ang opisyal na docker image (na naglalaman ng Docker binary):

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

Mukhang at gumagana ito tulad ng Docker-in-Docker, ngunit hindi ito Docker-in-Docker: kapag lumikha ang container na ito ng mga karagdagang container, gagawin ang mga ito sa top-level na Docker. Hindi mo mararanasan ang mga side effect ng nesting at ibabahagi ang assembly cache sa maraming tawag.

Tandaan: Pinayuhan ng mga nakaraang bersyon ng artikulong ito na i-link ang Docker binary mula sa host patungo sa container. Ito ay naging hindi maaasahan dahil ang Docker engine ay hindi na sumasaklaw sa mga static o malapit-static na mga aklatan.

Kaya, kung gusto mong gumamit ng Docker mula sa Jenkins CI, mayroon kang 2 pagpipilian:
pag-install ng Docker CLI gamit ang basic image packaging system (ibig sabihin, kung ang iyong larawan ay batay sa Debian, gumamit ng .deb packages), gamit ang Docker API.

Ilang ad 🙂

Salamat sa pananatili sa amin. Gusto mo ba ang aming mga artikulo? Gustong makakita ng mas kawili-wiling nilalaman? Suportahan kami sa pamamagitan ng pag-order o pagrekomenda sa mga kaibigan, cloud VPS para sa mga developer mula sa $4.99, isang natatanging analogue ng mga entry-level na server, na inimbento namin para sa iyo: Ang buong katotohanan tungkol sa VPS (KVM) E5-2697 v3 (6 Cores) 10GB DDR4 480GB SSD 1Gbps mula sa $19 o kung paano magbahagi ng server? (magagamit sa RAID1 at RAID10, hanggang 24 na core at hanggang 40GB DDR4).

Dell R730xd 2x na mas mura sa Equinix Tier IV data center sa Amsterdam? Dito lang 2 x Intel TetraDeca-Core Xeon 2x E5-2697v3 2.6GHz 14C 64GB DDR4 4x960GB SSD 1Gbps 100 TV mula $199 sa Netherlands! Dell R420 - 2x E5-2430 2.2Ghz 6C 128GB DDR3 2x960GB SSD 1Gbps 100TB - mula $99! Basahin ang tungkol sa Paano bumuo ng infrastructure corp. klase sa paggamit ng mga server ng Dell R730xd E5-2650 v4 na nagkakahalaga ng 9000 euro para sa isang sentimos?

Pinagmulan: www.habr.com

Magdagdag ng komento