Penseu bé abans d'utilitzar Docker-in-Docker per a CI o entorn de prova

Penseu bé abans d'utilitzar Docker-in-Docker per a CI o entorn de prova

Docker-in-Docker és un entorn de dimoni Docker virtualitzat que s'executa dins del propi contenidor per crear imatges de contenidor. L'objectiu principal de crear Docker-in-Docker era ajudar a desenvolupar Docker. Molta gent l'utilitza per executar Jenkins CI. Això sembla normal al principi, però després sorgeixen problemes que es poden evitar instal·lant Docker en un contenidor Jenkins CI. Aquest article us explica com fer-ho. Si esteu interessats en la solució final sense detalls, només heu de llegir l'última secció de l'article, "Resolució del problema".

Penseu bé abans d'utilitzar Docker-in-Docker per a CI o entorn de prova

Docker-in-Docker: "Bé"

Fa més de dos anys vaig posar en Docker bandera – privilegiat i escrit primera versió de dind. L'objectiu era ajudar l'equip principal a desenvolupar Docker més ràpidament. Abans de Docker-in-Docker, el cicle de desenvolupament típic tenia aquest aspecte:

  • hackity hack;
  • construir;
  • aturar un dimoni Docker en execució;
  • llançant un nou dimoni Docker;
  • proves;
  • repetir el cicle.

Si volies fer un conjunt bonic i reproduïble (és a dir, en un contenidor), es va fer més complicat:

  • hackity hack;
  • assegureu-vos que s'està executant una versió de Docker que funcioni;
  • crear un nou Docker amb l'antic Docker;
  • aturar el dimoni Docker;
  • iniciar un nou dimoni Docker;
  • prova;
  • aturar el nou dimoni Docker;
  • repetir.

Amb l'arribada de Docker-in-Docker, el procés s'ha tornat més senzill:

  • hackity hack;
  • muntatge + llançament en una sola etapa;
  • repetir el cicle.

No és molt millor així?

Penseu bé abans d'utilitzar Docker-in-Docker per a CI o entorn de prova

Docker-in-Docker: "Dolent"

Tanmateix, contràriament a la creença popular, Docker-in-Docker no és 100% estrelles, ponis i unicorns. El que vull dir és que hi ha diversos problemes que un desenvolupador ha de tenir en compte.

Un d'ells es refereix als LSM (mòduls de seguretat de Linux) com AppArmor i SELinux: quan s'executa un contenidor, el "Docker intern" pot intentar aplicar perfils de seguretat que entren en conflicte o confonen el "Docker extern". Aquest és el problema més difícil de resoldre quan s'intenta combinar la implementació original de la bandera –privileged. Els meus canvis van funcionar i totes les proves passarien a la meva màquina Debian i a les màquines virtuals de prova d'Ubuntu, però s'estavellaven i es cremarien a la màquina de Michael Crosby (que recordo que tenia Fedora). No recordo la causa exacta del problema, però pot ser que en Mike és un tipus savi que treballa amb SELINUX=enforce (he fet servir AppArmor) i els meus canvis no van tenir en compte els perfils SELinux.

Docker-in-Docker: "Malvat"

El segon problema és amb els controladors d'emmagatzematge Docker. Quan executeu Docker-in-Docker, Docker extern s'executa sobre un sistema de fitxers normal (EXT4, BTRFS o el que tingueu) i Docker intern s'executa sobre un sistema de còpia en escriptura (AUFS, BTRFS, Device Mapper). , etc.), depenent del que estigui configurat per utilitzar Docker extern). Això crea moltes combinacions que no funcionaran. Per exemple, no podreu executar AUFS a sobre d'AUFS.

Si executeu BTRFS a sobre de BTRFS, al principi hauria de funcionar, però un cop hi hagi subvolums imbricats, la supressió del subvolum principal fallarà. El mòdul Device Mapper no té espai de noms, de manera que si diverses instàncies de Docker l'executen a la mateixa màquina, totes podran veure (i influir) les imatges entre elles i en els dispositius de còpia de seguretat del contenidor. Això és dolent.

Hi ha solucions per resoldre molts d'aquests problemes. Per exemple, si voleu utilitzar AUFS al Docker intern, només heu de convertir la carpeta /var/lib/docker en un volum i anirà bé. Docker ha afegit alguns espais de noms bàsics als noms de destinació de Device Mapper de manera que si s'executen diverses trucades de Docker a la mateixa màquina, no es trepitgin.

Tanmateix, aquesta configuració no és gens senzilla, com es pot veure a partir d'aquests articles al repositori dind de GitHub.

Docker-in-Docker: empitjora

Què passa amb la memòria cau de compilació? Això també pot ser bastant difícil. La gent sovint em pregunta "si estic executant Docker-in-Docker, com puc utilitzar les imatges allotjades al meu amfitrió en lloc de tornar-ho a treure tot al meu Docker intern"?

Algunes persones emprenedores han intentat lligar /var/lib/docker des de l'amfitrió a un contenidor Docker-in-Docker. De vegades comparteixen /var/lib/docker amb diversos contenidors.

Penseu bé abans d'utilitzar Docker-in-Docker per a CI o entorn de prova
Vols corrompre les teves dades? Perquè això és exactament el que farà malbé les vostres dades!

El dimoni Docker es va dissenyar clarament per tenir accés exclusiu a /var/lib/docker. No hi ha res més que "tocar, picar o treure" cap fitxer Docker situat en aquesta carpeta.

Per què és així? Perquè aquest és el resultat d'una de les lliçons més difícils apreses durant el desenvolupament de dotCloud. El motor de contenidors dotCloud es va executar tenint diversos processos que accedeixen a /var/lib/dotcloud simultàniament. Trucs astuts com la substitució de fitxers atòmics (en lloc de l'edició in situ), el codi de pepper amb bloquejos d'assessorament i obligatori i altres experiments amb sistemes segurs com SQLite i BDB no sempre van funcionar. Quan estàvem redissenyant el nostre motor de contenidors, que finalment es va convertir en Docker, una de les grans decisions de disseny va ser consolidar totes les operacions de contenidors sota un únic dimoni per eliminar totes les tonterias de concurrència.

No em malinterpreteu: és totalment possible fer alguna cosa bona, fiable i ràpida que impliqui múltiples processos i un control paral·lel modern. Però creiem que és més senzill i més fàcil escriure i mantenir codi utilitzant Docker com a únic reproductor.

Això vol dir que si compartiu el directori /var/lib/docker entre diverses instàncies de Docker, tindreu problemes. Per descomptat, això pot funcionar, especialment en les primeres etapes de les proves. "Escolta, mare, puc executar l'ubuntu com a docker!" Però proveu alguna cosa més complexa, com treure la mateixa imatge de dos casos diferents, i veureu com el món crema.

Això vol dir que si el vostre sistema CI realitza compilacions i reconstruccions, cada vegada que reinicieu el contenidor Docker-in-Docker, correu el risc de deixar caure una bomba nuclear a la memòria cau. Això no és gens genial!

La solució

Fem un pas enrere. Realment necessiteu Docker-in-Docker o només voleu poder executar Docker i crear i executar contenidors i imatges des del vostre sistema CI mentre aquest mateix sistema CI es troba en un contenidor?

Aposto que la majoria de la gent vol aquesta darrera opció, és a dir, volen que un sistema CI com Jenkins pugui executar contenidors. I la manera més senzilla de fer-ho és simplement inserir un sòcol Docker al contenidor CI i associar-lo amb la bandera -v.

En poques paraules, quan executeu el vostre contenidor CI (Jenkins o un altre), en lloc de piratejar alguna cosa juntament amb Docker-in-Docker, inicieu-lo amb la línia:

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

Aquest contenidor ara tindrà accés al sòcol Docker i, per tant, podrà executar contenidors. Excepte que en comptes d'executar contenidors "fills", llançarà contenidors "germans".

Proveu-ho amb la imatge oficial de Docker (que conté el binari de Docker):

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

Sembla i funciona com Docker-in-Docker, però no és Docker-in-Docker: quan aquest contenidor crea contenidors addicionals, es crearan al Docker de nivell superior. No experimentareu els efectes secundaris de la nidificació i la memòria cau de muntatge es compartirà en diverses trucades.

Nota: les versions anteriors d'aquest article recomanaven enllaçar el binari Docker de l'amfitrió al contenidor. Això s'ha tornat poc fiable, ja que el motor Docker ja no cobreix biblioteques estàtiques o gairebé estàtiques.

Per tant, si voleu utilitzar Docker de Jenkins CI, teniu 2 opcions:
instal·lant la CLI de Docker mitjançant el sistema bàsic d'empaquetament d'imatges (és a dir, si la vostra imatge es basa en Debian, utilitzeu paquets .deb), mitjançant l'API de Docker.

Alguns anuncis 🙂

Gràcies per quedar-te amb nosaltres. T'agraden els nostres articles? Vols veure més contingut interessant? Doneu-nos suport fent una comanda o recomanant als amics, Cloud VPS per a desenvolupadors des de 4.99 dòlars, un anàleg únic dels servidors d'entrada, que vam inventar per a vosaltres: Tota la veritat sobre VPS (KVM) E5-2697 v3 (6 nuclis) 10 GB DDR4 480 GB SSD 1 Gbps des de 19 dòlars o com compartir un servidor? (disponible amb RAID1 i RAID10, fins a 24 nuclis i fins a 40 GB DDR4).

Dell R730xd 2 vegades més barat al centre de dades Equinix Tier IV a Amsterdam? Només aquí 2 x Intel TetraDeca-Core Xeon 2x E5-2697v3 2.6 GHz 14C 64 GB DDR4 4 x 960 GB SSD 1 Gbps 100 TV des de 199 $ als Països Baixos! Dell R420 - 2x E5-2430 2.2 Ghz 6C 128 GB DDR3 2 x 960 GB SSD 1 Gbps 100 TB - a partir de 99 $! Llegeix sobre Com construir infrastructure corp. classe amb l'ús de servidors Dell R730xd E5-2650 v4 per valor de 9000 euros per un cèntim?

Font: www.habr.com

Afegeix comentari