Tænk dig grundigt om, før du bruger Docker-in-Docker til CI eller testmiljø

Tænk dig grundigt om, før du bruger Docker-in-Docker til CI eller testmiljø

Docker-in-Docker er et virtualiseret Docker-dæmonmiljø, der kører i selve containeren for at bygge containerbilleder. Hovedformålet med at skabe Docker-in-Docker var at hjælpe med at udvikle Docker selv. Mange mennesker bruger det til at køre Jenkins CI. Dette virker normalt i starten, men så opstår der problemer, som kan undgås ved at installere Docker i en Jenkins CI-beholder. Denne artikel fortæller dig, hvordan du gør dette. Hvis du er interesseret i den endelige løsning uden detaljer, skal du blot læse det sidste afsnit af artiklen, "Løsning af problemet."

Tænk dig grundigt om, før du bruger Docker-in-Docker til CI eller testmiljø

Docker-in-Docker: "Godt"

For mere end to år siden satte jeg mig ind i Docker flag –privilegeret og skrev første version af dind. Målet var at hjælpe kerneteamet med at udvikle Docker hurtigere. Før Docker-in-Docker så den typiske udviklingscyklus sådan ud:

  • hackity hack;
  • bygge;
  • stopper en kørende Docker-dæmon;
  • lancering af en ny Docker-dæmon;
  • testning;
  • gentag cyklussen.

Hvis du ville lave en smuk, reproducerbar samling (det vil sige i en beholder), så blev det mere indviklet:

  • hackity hack;
  • sørg for, at en fungerende version af Docker kører;
  • byg ny Docker med gammel Docker;
  • stop Docker-dæmonen;
  • start en ny Docker-dæmon;
  • prøve;
  • stop ny Docker-dæmon;
  • gentage.

Med fremkomsten af ​​Docker-in-Docker er processen blevet enklere:

  • hackity hack;
  • montering + lancering i én fase;
  • gentag cyklussen.

Er det ikke meget bedre på denne måde?

Tænk dig grundigt om, før du bruger Docker-in-Docker til CI eller testmiljø

Docker-in-Docker: "Dårlig"

Men i modsætning til hvad mange tror, ​​er Docker-in-Docker ikke 100 % stjerner, ponyer og enhjørninger. Hvad jeg mener er, at der er flere problemer, som en udvikler skal være opmærksom på.

En af dem vedrører LSM'er (Linux-sikkerhedsmoduler) såsom AppArmor og SELinux: når den kører en container, kan den "interne Docker" forsøge at anvende sikkerhedsprofiler, der vil komme i konflikt med eller forvirre den "eksterne Docker". Dette er det sværeste problem at løse, når man forsøger at fusionere den originale implementering af det –privilegerede flag. Mine ændringer virkede, og alle test ville bestå på min Debian-maskine og Ubuntu-test-VM'er, men de ville gå ned og brænde på Michael Crosbys maskine (han havde Fedora, så vidt jeg husker det). Jeg kan ikke huske den præcise årsag til problemet, men det kan have været fordi Mike er en klog fyr, der arbejder med SELINUX=enforce (jeg brugte AppArmor), og mine ændringer tog ikke højde for SELinux-profiler.

Docker-in-Docker: "Ondskab"

Det andet problem er med Docker-lagerdrivere. Når du kører Docker-in-Docker, kører ekstern Docker oven på et almindeligt filsystem (EXT4, BTRFS, eller hvad du nu har), og intern Docker kører oven på et copy-on-write system (AUFS, BTRFS, Device Mapper) , etc.). , afhængigt af hvad der er konfigureret til at bruge ekstern Docker). Dette skaber mange kombinationer, der ikke vil fungere. For eksempel vil du ikke være i stand til at køre AUFS oven på AUFS.

Hvis du kører BTRFS oven på BTRFS, burde det virke i starten, men når der først er indlejrede undervolumener, vil sletning af den overordnede undervolumen mislykkes. Device Mapper-modulet har ikke noget navneområde, så hvis flere Docker-instanser kører det på den samme maskine, vil de alle kunne se (og påvirke) billederne på hinanden og på container-backup-enhederne. Det her er slemt.

Der er løsninger til at løse mange af disse problemer. For eksempel, hvis du vil bruge AUFS i intern Docker, skal du bare omdanne /var/lib/docker-mappen til en volumen, og du vil være i orden. Docker har tilføjet nogle basisnavneområder til Device Mapper-målnavne, så hvis flere Docker-opkald kører på den samme maskine, vil de ikke træde på hinanden.

En sådan opsætning er dog slet ikke enkel, som det kan ses af disse artikler i dind-lageret på GitHub.

Docker-in-Docker: Det bliver værre

Hvad med build-cachen? Dette kan også være ret svært. Folk spørger mig ofte "hvis jeg kører Docker-in-Docker, hvordan kan jeg så bruge billeder hostet på min vært i stedet for at trække alt tilbage i min interne Docker"?

Nogle driftige mennesker har forsøgt at binde /var/lib/docker fra værten til en Docker-in-Docker-beholder. Nogle gange deler de /var/lib/docker med flere containere.

Tænk dig grundigt om, før du bruger Docker-in-Docker til CI eller testmiljø
Vil du ødelægge dine data? For det er netop det, der vil skade dine data!

Docker-dæmonen var tydeligt designet til at have eksklusiv adgang til /var/lib/docker. Intet andet bør "røre, stikke eller prod" nogen Docker-filer placeret i denne mappe.

Hvorfor er det sådan? Fordi dette er resultatet af en af ​​de sværeste lektioner, man har lært under udviklingen af ​​dotCloud. DotCloud-beholdermotoren kørte ved at have flere processer, der fik adgang til /var/lib/dotcloud samtidigt. Udspekulerede tricks såsom udskiftning af atomfiler (i stedet for redigering på stedet), krydret kode med rådgivende og obligatoriske låse og andre eksperimenter med sikre systemer som SQLite og BDB virkede ikke altid. Da vi redesignede vores containermotor, som til sidst blev Docker, var en af ​​de store designbeslutninger at konsolidere alle containeroperationer under en enkelt dæmon for at gøre op med alt det samtidige nonsens.

Misforstå mig ikke: Det er fuldt ud muligt at lave noget godt, pålideligt og hurtigt, der involverer flere processer og moderne parallel styring. Men vi synes, det er enklere og nemmere at skrive og vedligeholde kode ved at bruge Docker som den eneste spiller.

Dette betyder, at hvis du deler mappen /var/lib/docker mellem flere Docker-instanser, vil du få problemer. Selvfølgelig kan dette fungere, især i de tidlige stadier af test. "Hør, mor, jeg kan køre ubuntu som havnearbejder!" Men prøv noget mere komplekst, som at trække det samme billede fra to forskellige tilfælde, og du vil se verden brænde.

Dette betyder, at hvis dit CI-system udfører opbygninger og genopbygninger, risikerer du, hver gang du genstarter din Docker-in-Docker-beholder, at tabe et atomvåben i dens cache. Det her er slet ikke fedt!

Løsning

Lad os tage et skridt tilbage. Har du virkelig brug for Docker-in-Docker, eller vil du bare kunne køre Docker og bygge og køre containere og billeder fra dit CI-system, mens selve CI-systemet er i en container?

Jeg vil vædde på, at de fleste mennesker vil have den sidste mulighed, hvilket betyder, at de vil have et CI-system som Jenkins for at kunne køre containere. Og den nemmeste måde at gøre dette på er blot at indsætte en Docker-socket i din CI-beholder og knytte den til -v-flaget.

Kort sagt, når du kører din CI-container (Jenkins eller andet), i stedet for at hacke noget sammen med Docker-in-Docker, start den med linjen:

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

Denne container vil nu have adgang til Docker-socket og kan derfor køre containere. Bortset fra, at i stedet for at køre "underordnede" containere, vil den lancere "søskende" containere.

Prøv dette ved at bruge det officielle docker-billede (som indeholder Docker-binæren):

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

Det ser ud og fungerer som Docker-in-Docker, men det er ikke Docker-in-Docker: Når denne container opretter yderligere containere, bliver de oprettet i Docker på øverste niveau. Du vil ikke opleve bivirkningerne ved nesting, og assembly-cachen deles på tværs af flere opkald.

Bemærk: Tidligere versioner af denne artikel anbefalede at linke Docker-binæren fra værten til containeren. Dette er nu blevet upålideligt, da Docker-motoren ikke længere dækker statiske eller næsten statiske biblioteker.

Så hvis du vil bruge Docker fra Jenkins CI, har du 2 muligheder:
installation af Docker CLI ved hjælp af det grundlæggende billedpakkesystem (dvs. hvis dit billede er baseret på Debian, brug .deb-pakker), ved hjælp af Docker API.

Nogle annoncer 🙂

Tak fordi du blev hos os. Kan du lide vores artikler? Vil du se mere interessant indhold? Støt os ved at afgive en ordre eller anbefale til venner, cloud VPS for udviklere fra $4.99, en unik analog af entry-level servere, som blev opfundet af os til dig: Hele sandheden om VPS (KVM) E5-2697 v3 (6 Cores) 10GB DDR4 480GB SSD 1Gbps fra $19 eller hvordan deler man en server? (tilgængelig med RAID1 og RAID10, op til 24 kerner og op til 40 GB DDR4).

Dell R730xd 2 gange billigere i Equinix Tier IV datacenter i Amsterdam? Kun her 2 x Intel TetraDeca-Core Xeon 2x E5-2697v3 2.6GHz 14C 64GB DDR4 4x960GB SSD 1Gbps 100 TV fra $199 i Holland! Dell R420 - 2x E5-2430 2.2Ghz 6C 128GB DDR3 2x960GB SSD 1Gbps 100TB - fra $99! Læse om Hvordan man bygger infrastruktur corp. klasse med brug af Dell R730xd E5-2650 v4-servere til en værdi af 9000 euro for en krone?

Kilde: www.habr.com

Tilføj en kommentar