Tenk nøye før du bruker Docker-in-Docker for CI eller testmiljø

Tenk nøye før du bruker Docker-in-Docker for CI eller testmiljø

Docker-in-Docker er et virtualisert Docker-demonmiljø som kjører i selve containeren for å bygge containerbilder. Hovedformålet med å lage Docker-in-Docker var å hjelpe til med å utvikle Docker selv. Mange bruker den til å kjøre Jenkins CI. Dette virker normalt i begynnelsen, men så oppstår det problemer som kan unngås ved å installere Docker i en Jenkins CI-beholder. Denne artikkelen forteller deg hvordan du gjør dette. Hvis du er interessert i den endelige løsningen uten detaljer, les bare den siste delen av artikkelen, "Løse problemet."

Tenk nøye før du bruker Docker-in-Docker for CI eller testmiljø

Docker-in-Docker: "Bra"

For mer enn to år siden satte jeg inn i Docker flagg –privilegert og skrev første versjon av dind. Målet var å hjelpe kjerneteamet med å utvikle Docker raskere. Før Docker-in-Docker så den typiske utviklingssyklusen slik ut:

  • hackity hack;
  • bygge;
  • stoppe en kjørende Docker-demon;
  • lanserer en ny Docker-demon;
  • testing;
  • gjenta syklusen.

Hvis du ønsket å lage en vakker, reproduserbar montering (det vil si i en beholder), ble det mer intrikat:

  • hackity hack;
  • sørg for at en fungerende versjon av Docker kjører;
  • bygge ny Docker med gammel Docker;
  • stopp Docker-demonen;
  • start en ny Docker-demon;
  • test;
  • stopp ny Docker-demon;
  • gjenta.

Med ankomsten av Docker-in-Docker har prosessen blitt enklere:

  • hackity hack;
  • montering + lansering i ett trinn;
  • gjenta syklusen.

Er det ikke mye bedre på denne måten?

Tenk nøye før du bruker Docker-in-Docker for CI eller testmiljø

Docker-in-Docker: "Dårlig"

Imidlertid, i motsetning til hva mange tror, ​​er Docker-in-Docker ikke 100 % stjerner, ponnier og enhjørninger. Det jeg mener er at det er flere problemer som en utvikler må være klar over.

En av dem gjelder LSM-er (Linux-sikkerhetsmoduler) som AppArmor og SELinux: når du kjører en container, kan den "interne Docker" prøve å bruke sikkerhetsprofiler som vil komme i konflikt med eller forvirre den "eksterne Docker". Dette er det vanskeligste problemet å løse når man prøver å slå sammen den opprinnelige implementeringen av –privileged-flagget. Endringene mine fungerte og alle tester ville passere på Debian-maskinen min og Ubuntu-test-VM-ene mine, men de ville krasje og brenne på Michael Crosbys maskin (han hadde Fedora så vidt jeg husker). Jeg husker ikke den eksakte årsaken til problemet, men det kan ha vært fordi Mike er en klok fyr som jobber med SELINUX=enforce (jeg brukte AppArmor) og endringene mine tok ikke hensyn til SELinux-profiler.

Docker-in-Docker: "Ondskap"

Det andre problemet er med Docker-lagringsdrivere. Når du kjører Docker-in-Docker, kjører ekstern Docker på toppen av et vanlig filsystem (EXT4, BTRFS, eller hva du nå har) og intern Docker kjører på toppen av et kopi-på-skriv-system (AUFS, BTRFS, Device Mapper , etc.). , avhengig av hva som er konfigurert til å bruke ekstern docker). Dette skaper mange kombinasjoner som ikke vil fungere. For eksempel vil du ikke kunne kjøre AUFS på toppen av AUFS.

Hvis du kjører BTRFS på toppen av BTRFS, bør det fungere i begynnelsen, men når det er nestede undervolumer, vil sletting av det overordnede undervolumet mislykkes. Device Mapper-modulen har ikke noe navneområde, så hvis flere Docker-forekomster kjører den på samme maskin, vil de alle kunne se (og påvirke) bildene på hverandre og på containerbackup-enhetene. Dette er dårlig.

Det finnes løsninger for å løse mange av disse problemene. For eksempel, hvis du vil bruke AUFS i intern Docker, gjør du bare /var/lib/docker-mappen til et volum, så går det bra. Docker har lagt til noen basisnavneområder til Device Mapper-målnavn, slik at hvis flere Docker-anrop kjører på samme maskin, vil de ikke tråkke på hverandre.

Et slikt oppsett er imidlertid slett ikke enkelt, som man kan se av disse Artikkel i dind-lageret på GitHub.

Docker-in-Docker: Det blir verre

Hva med build-cachen? Dette kan også være ganske vanskelig. Folk spør meg ofte "hvis jeg kjører Docker-in-Docker, hvordan kan jeg bruke bilder som ligger på verten min i stedet for å trekke alt tilbake til min interne Docker"?

Noen driftige mennesker har forsøkt å binde /var/lib/docker fra verten til en Docker-in-Docker-beholder. Noen ganger deler de /var/lib/docker med flere beholdere.

Tenk nøye før du bruker Docker-in-Docker for CI eller testmiljø
Vil du ødelegge dataene dine? For det er nettopp dette som vil skade dataene dine!

Docker-demonen var tydelig designet for å ha eksklusiv tilgang til /var/lib/docker. Ingenting annet skal "røre, pirke eller prod" noen Docker-filer som ligger i denne mappen.

Hvorfor er det slik? Fordi dette er resultatet av en av de vanskeligste leksjonene man har lært under utviklingen av dotCloud. DotCloud-beholdermotoren kjørte ved at flere prosesser fikk tilgang til /var/lib/dotcloud samtidig. Utspekulerte triks som atomfilerstatning (i stedet for redigering på stedet), pepre kode med rådgivende og obligatoriske låser og andre eksperimenter med sikre systemer som SQLite og BDB fungerte ikke alltid. Da vi redesignet containermotoren vår, som til slutt ble Docker, var en av de store designbeslutningene å konsolidere alle containeroperasjoner under en enkelt demon for å gjøre unna alt det samtidige tullet.

Misforstå meg rett: det er fullt mulig å lage noe godt, pålitelig og raskt som involverer flere prosesser og moderne parallellkontroll. Men vi tror det er enklere og enklere å skrive og vedlikeholde kode ved å bruke Docker som eneste spiller.

Dette betyr at hvis du deler /var/lib/docker-katalogen mellom flere Docker-forekomster, vil du få problemer. Selvfølgelig kan dette fungere, spesielt i de tidlige stadiene av testingen. "Hør, mamma, jeg kan kjøre ubuntu som en docker!" Men prøv noe mer komplekst, som å trekke det samme bildet fra to forskjellige forekomster, og du vil se verden brenne.

Dette betyr at hvis CI-systemet ditt utfører bygg og ombygginger, hver gang du starter Docker-in-Docker-beholderen på nytt, risikerer du å slippe en atombombe i hurtigbufferen. Dette er ikke kult i det hele tatt!

Løsningen

La oss ta et skritt tilbake. Trenger du virkelig Docker-in-Docker eller vil du bare kunne kjøre Docker og bygge og kjøre containere og bilder fra CI-systemet ditt mens selve CI-systemet er i en container?

Jeg vedder på at de fleste vil ha det siste alternativet, noe som betyr at de vil ha et CI-system som Jenkins for å kunne kjøre containere. Og den enkleste måten å gjøre dette på er ganske enkelt å sette inn en Docker-socket i CI-beholderen og knytte den til -v-flagget.

Enkelt sagt, når du kjører CI-beholderen din (Jenkins eller annet), i stedet for å hacke noe sammen med Docker-in-Docker, start den med linjen:

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

Denne containeren vil nå ha tilgang til Docker-kontakten og kan derfor kjøre containere. Bortsett fra at i stedet for å kjøre "barne"-containere, vil den starte "søsken"-containere.

Prøv dette ved å bruke det offisielle docker-bildet (som inneholder Docker-binæren):

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

Det ser ut og fungerer som Docker-in-Docker, men det er ikke Docker-in-Docker: når denne containeren oppretter flere containere, vil de bli opprettet i toppnivå Docker. Du vil ikke oppleve bivirkningene av nesting, og sammenstillingsbufferen vil bli delt på tvers av flere samtaler.

Merk: Tidligere versjoner av denne artikkelen anbefalte å koble Docker-binæren fra verten til beholderen. Dette har nå blitt upålitelig ettersom Docker-motoren ikke lenger dekker statiske eller nesten statiske biblioteker.

Så hvis du vil bruke Docker fra Jenkins CI, har du 2 alternativer:
installere Docker CLI ved å bruke det grunnleggende bildepakkesystemet (dvs. hvis bildet ditt er basert på Debian, bruk .deb-pakker), ved å bruke Docker API.

Noen annonser 🙂

Takk for at du bor hos oss. Liker du artiklene våre? Vil du se mer interessant innhold? Støtt oss ved å legge inn en bestilling eller anbefale til venner, cloud VPS for utviklere fra $4.99, en unik analog av entry-level servere, som ble oppfunnet av oss for deg: Hele sannheten om VPS (KVM) E5-2697 v3 (6 kjerner) 10GB DDR4 480GB SSD 1Gbps fra $19 eller hvordan dele en server? (tilgjengelig med RAID1 og RAID10, opptil 24 kjerner og opptil 40 GB DDR4).

Dell R730xd 2x billigere i Equinix Tier IV datasenter i Amsterdam? Bare her 2 x Intel TetraDeca-Core Xeon 2x E5-2697v3 2.6GHz 14C 64GB DDR4 4x960GB SSD 1Gbps 100 TV fra $199 i Nederland! Dell R420 - 2x E5-2430 2.2Ghz 6C 128GB DDR3 2x960GB SSD 1Gbps 100TB - fra $99! Lese om Hvordan bygge infrastruktur corp. klasse med bruk av Dell R730xd E5-2650 v4-servere verdt 9000 euro for en krone?

Kilde: www.habr.com

Legg til en kommentar