
Docker-in-Docker repræsenterer et virtualiseret Docker-daemon-miljø, der kører inden i selve containeren for at bygge containerbilleder. Hovedformålet med at skabe Docker-in-Docker var at assistere med udviklingen af Docker selv. Mange mennesker bruger det til at køre Jenkins CI. I starten virker det normalt, men der opstår problemer, som kan undgås ved at installere Docker i Jenkins CI-containere. Denne artikel beskriver, hvordan man gør det. Hvis du er interesseret i den endelige løsning uden detaljer, skal du blot læse det sidste afsnit af artiklen, "Løsning på problemet".

Docker-in-Docker: "God"
For mere end to år siden indsatte jeg i Docker –privileged og skrev . Målet var at hjælpe det primære team med hurtigere at udvikle Docker. Inden Docker-in-Docker blev almindeligt, var den typiske udviklingscyklus sådan:
- hackity hack;
- byg (build);
- stop den kørende Docker-daemon;
- start en ny Docker-daemon;
- teste;
- gentag cyklus.
Hvis du derimod ønskede at lave en flot, reproducerbar bygning (altså i en container), blev det mere indviklet:
- hackity hack;
- sørge for, at der kører en fungerende version af Docker;
- bygge en ny Docker med den gamle Docker;
- stoppe Docker-daemonen;
- starte en ny Docker-daemon;
- teste;
- stoppe den nye Docker-daemon;
- gentage.
Med introduktionen af Docker-in-Docker blev processen forenklet:
- hackity hack;
- bygning + opstart i ét trin;
- gentag cyklus.
Er det ikke meget bedre?

Docker-in-Docker: "Slem"
Men mod sat opfattelse består Docker-in-Docker ikke 100% af stjerner, ponyer og enhjørninger. Jeg mener, at der er flere problemer, som udvikleren bør være opmærksom på.
Et af dem angår LSM (Linux sikkerhedsmoduler), såsom AppArmor og SELinux: når containers "intern Docker" bliver startet, kan det forsøge at anvende sikkerhedsprofiler, som vil være i konflikt med eller forvirre "ekstern Docker". Dette er det mest komplekse problem, der skulle løses, når man forsøgte at kombinere den oprindelige implementering af flaget –privileged. Mine ændringer fungerede, og alle tests ville også have bestået på min Debian-maskine og test-virtuelle maskiner med Ubuntu, men de ville falde fra hinanden og brænde på Michael Crosbys maskine (så vidt jeg husker, havde han Fedora). Jeg kan ikke huske den præcise årsag til problemet, men det kan være, fordi Mike er en klog mand, der arbejder med SELINUX=enforce (jeg brugte AppArmor), og mine ændringer tog ikke højde for SELinux-profiler.
Docker-in-Docker: "Den onde"
Det andet problem vedrører Docker-lagringsdrivere. Når du kører Docker-in-Docker, kører den eksterne Docker oven på et normalt filsystem (EXT4, BTRFS eller hvad som helst, du har til rådighed), mens den interne Docker arbejder oven på et copy-on-write system (AUFS, BTRFS, Device Mapper osv., afhængigt af hvad den eksterne Docker er konfigureret til at bruge). Dette skaber mange kombinationer, der ikke vil fungere. For eksempel kan du ikke køre AUFS oven på AUFS.
Hvis du kører BTRFS oven på BTRFS, burde det fungere i starten, men så snart der opstår indlejrede underafsnit, vil du ikke være i stand til at slette det overordnede underafsnit. Device Mapper-modulet har ikke navnerum, så hvis flere Docker-instanser bruger det på én maskine, vil de alle kunne se (og påvirke) billeder hinanden og beholdere til sikkerhedskopiering. Det er skidt.
Der er genveje til at løse mange af disse problemer. For eksempel, hvis du ønsker at bruge AUFS i intern Docker, skal du bare konvertere mappen /var/lib/docker til det, og så vil alt være i orden. Docker har tilføjet nogle grundlæggende navnerum til Device Mapper-mål, så hvis flere Docker-opkald udføres på én maskine, vil de ikke "træde hinanden over tæerne".
Alligevel er en sådan opsætning slet ikke simpel, som man kan se fra disse i dind-repositoriet på GitHub.
Docker-in-Docker: det bliver endnu værre
Hvad med cache af bygningen? Det kan også være ret kompliceret. Folk spørger mig ofte: "hvis jeg kører Docker-in-Docker, hvordan kan jeg så bruge billeder, der er placeret på min vært, i stedet for at hente alt igen i min interne Docker?"
Nogle entreprenante mennesker har forsøgt at binde /var/lib/docker fra værten i Docker-in-Docker-containere. Nogle gange deler de /var/lib/docker med flere containere.

Vil du ødelægge dataene? For det er præcis, hvad der vil skade dine data!
Docker-dæmonen blev tydeligvis designet til at have eksklusiv adgang til /var/lib/docker. Intet andet bør "røre ved, stikke i eller røre" filer i Docker, der er i denne mappe.
Hvorfor er det sådan? Fordi det er resultatet af en af de hårdeste lektioner lært under udviklingen af dotCloud. Container-motoren i dotCloud fungerede ved at have flere processer, der samtidig tilgik /var/lib/dotcloud. Smarte tricks, såsom atomisk erstatning af filer (i stedet for redigering på stedet), "peppere" koden med anbefalende og obligatoriske låse samt andre eksperimenter med sikre systemer som SQLite og BDB fungerede ikke altid. Da vi redesignede vores container-motor, som til sidst blev til Docker, var en af de vigtigste designbeslutninger at samle alle operationer med containere under en enkelt dæmon for at afslutte al denne vrøvl med samtidigt adgang.
Misforstå mig ikke: det er helt muligt at lave noget godt, stabilt og hurtigt, som involverer flere processer og moderne parallel håndtering. Men vi mener, det er nemmere og lettere at skrive og vedligeholde kode ved at bruge Docker som den eneste aktør.
Det betyder, at hvis du deler mappen /var/lib/docker mellem flere Docker-instanser, vil du få problemer. Selvfølgelig kan det fungere, især i de tidlige testfaser. "Hør, mor, jeg kan køre ubuntu med 'docker'!" Men prøv at gøre noget mere komplekst, som at hente det samme billede fra to forskellige instanser, og du vil se verden brænde.
Det betyder, at hvis dit CI-system udfører builds og re-builds, så risikerer du hver gang, du genstarter Docker-in-Docker containeren, at nulstille en kernebombe i dens cache. Det er slet ikke godt!
Løsning på problemet
Lad os tage et skridt tilbage. Har du virkelig brug for Docker-in-Docker, eller vil du bare være i stand til at køre Docker, dvs. at bygge og køre containere og billeder fra dit CI-system, mens selve dette CI-system er i en container?
Jeg ved, at de fleste mennesker ønsker den sidste mulighed, det vil sige, at de ønsker, at et CI-system som Jenkins kan køre containere. Og den nemmeste måde at gøre dette på er simpelthen at montere Docker-socket i din CI-container ved at binde den med flaget -v.
Sagt på en enklere måde, når du kører din CI-container (Jenkins eller en anden), i stedet for at hacke noget sammen med Docker-in-Docker, skal du starte den med følgende linje:
docker run -v /var/run/docker.sock:/var/run/docker.sock ...Nu vil denne container have adgang til Docker-socket og vil derfor kunne køre containere. Undtagen at den i stedet for at køre 'underordnede' containere vil køre 'beslægtede' containere.
Prøv dette ved at bruge det officielle Docker-billede (som indeholder Docker-binærfilen):
docker run -v /var/run/docker.sock:/var/run/docker.sock
-ti dockerDette ser ud til at fungere som Docker-in-Docker, men det er ikke Docker-in-Docker: når denne container opretter yderligere containere, vil de blive oprettet i Docker-niveauet over. Du vil ikke opleve bivirkninger ved indlejring, og build-cachen vil blive delt mellem flere opkald.
Bemærk: Tidligere versioner af denne artikel anbefalede at montere Docker-binærfilen fra værten til containeren. Dette er nu blevet usikkert, da Docker-mekanismen ikke længere gælder for statiske eller næsten statiske biblioteker.
Så hvis du ønsker at bruge Docker fra Jenkins CI, har du 2 muligheder:
installation af Docker CLI ved hjælp af det grundlæggende system til pakkeopbygning (dvs. hvis dit billede er baseret på Debian, skal du bruge .deb-pakker), brug af Docker API.
Lidt reklame 🙂
Tak fordi du bliver hos os. Kan du lide vores artikler? Ønsker du at se flere interessante materialer? Støt os ved at bestille eller anbefale os til dine bekendte, , en unik analog til entry-level servere, som vi har designet til dig: (tilgængelige muligheder med RAID1 og RAID10, op til 24 kerner og op til 40 GB DDR4).
Dell R730xd til halv pris i datacenteret Equinix Tier IV i Amsterdam? Kun hos os i Holland! Dell R420 - 2x E5-2430 2.2GHz 6C 128GB DDR3 2x960GB SSD 1Gbps 100TB - fra 99 $! Læs om hvordan
Kilde: habr.com
