Pense coidadosamente antes de usar Docker-in-Docker para CI ou ambiente de proba

Pense coidadosamente antes de usar Docker-in-Docker para CI ou ambiente de proba

Docker-in-Docker é un entorno de daemon Docker virtualizado que se executa no propio contenedor para crear imaxes do contenedor. O propósito principal de crear Docker-in-Docker era axudar a desenvolver o propio Docker. Moitas persoas úsano para executar Jenkins CI. Isto parece normal ao principio, pero despois xorden problemas que se poden evitar instalando Docker nun contenedor Jenkins CI. Este artigo indícase como facelo. Se estás interesado na solución final sen detalles, só tes que ler a última sección do artigo, "Resolver o problema".

Pense coidadosamente antes de usar Docker-in-Docker para CI ou ambiente de proba

Docker-in-Docker: "Bo"

Hai máis de dous anos que puxen en Docker bandeira –privilexiado e escrito primeira versión de dind. O obxectivo era axudar ao equipo principal a desenvolver Docker máis rápido. Antes de Docker-in-Docker, o ciclo de desenvolvemento típico era o seguinte:

  • hackity hack;
  • construír;
  • deter un daemon Docker en execución;
  • lanzando un novo daemon Docker;
  • probas;
  • repetir o ciclo.

Se querías facer un conxunto fermoso e reproducible (é dicir, nun recipiente), volveuse máis complicado:

  • hackity hack;
  • asegúrese de que se está a executar unha versión de Docker que funcione;
  • construír un novo Docker co antigo Docker;
  • parar o demo Docker;
  • iniciar un novo daemon Docker;
  • proba;
  • deter o novo daemon Docker;
  • repetir.

Coa chegada de Docker-in-Docker, o proceso fíxose máis sinxelo:

  • hackity hack;
  • montaxe + lanzamento nunha etapa;
  • repetir o ciclo.

Non é moito mellor deste xeito?

Pense coidadosamente antes de usar Docker-in-Docker para CI ou ambiente de proba

Docker-in-Docker: "Malo"

Non obstante, ao contrario da crenza popular, Docker-in-Docker non é 100% estrelas, pôneis e unicornios. O que quero dicir é que hai varios problemas dos que un desenvolvedor debe ter en conta.

Un deles refírese aos LSM (módulos de seguridade de Linux) como AppArmor e SELinux: ao executar un contedor, o "Docker interno" pode tentar aplicar perfís de seguridade que entrarán en conflito ou confundirán ao "Docker externo". Este é o problema máis difícil de resolver cando se intenta combinar a implementación orixinal da bandeira –privileged. Os meus cambios funcionaron e todas as probas pasarían á miña máquina Debian e ás máquinas virtuales de proba de Ubuntu, pero fallaban e arderían na máquina de Michael Crosby (que recordo que tiña Fedora). Non lembro a causa exacta do problema, pero puido ser porque Mike é un tipo sabio que traballa con SELINUX=enforce (eu usei AppArmor) e os meus cambios non tiveron en conta os perfís de SELinux.

Docker-in-Docker: "Malvado"

O segundo problema é cos controladores de almacenamento Docker. Cando executa Docker-in-Docker, o Docker externo execútase enriba dun sistema de ficheiros normal (EXT4, BTRFS ou o que teña) e o Docker interno execútase nun sistema de copia en escritura (AUFS, BTRFS, Device Mapper). , etc.). , dependendo do que estea configurado para usar Docker externo). Isto crea moitas combinacións que non funcionarán. Por exemplo, non poderá executar AUFS enriba de AUFS.

Se executas BTRFS enriba de BTRFS, debería funcionar ao principio, pero unha vez que haxa subvolumes aniñados, fallará ao eliminar o subvolume pai. O módulo Device Mapper non ten espazo de nomes, polo que se o executan varias instancias de Docker na mesma máquina, todas poderán ver (e influír) as imaxes entre si e nos dispositivos de copia de seguridade do contedor. Isto é malo.

Hai solucións para resolver moitos destes problemas. Por exemplo, se queres usar AUFS no Docker interno, só tes que converter o cartafol /var/lib/docker nun volume e estarás ben. Docker engadiu algúns espazos de nomes base aos nomes de destino do Device Mapper para que se se executan varias chamadas de Docker na mesma máquina, non se pisarán entre si.

Non obstante, tal configuración non é nada sinxela, como se pode ver nestes artigos no repositorio dind en GitHub.

Docker-in-Docker: empeora

Que pasa coa caché de compilación? Isto tamén pode ser bastante difícil. Moitas veces, a xente pregúntame "se estou a executar Docker-in-Docker, como podo usar imaxes aloxadas no meu servidor en lugar de devolver todo ao meu Docker interno"?

Algunhas persoas emprendedoras intentaron vincular /var/lib/docker desde o host a un contedor Docker-in-Docker. Ás veces comparten /var/lib/docker con varios contedores.

Pense coidadosamente antes de usar Docker-in-Docker para CI ou ambiente de proba
Queres corromper os teus datos? Porque isto é exactamente o que danará os teus datos.

O daemon Docker foi deseñado claramente para ter acceso exclusivo a /var/lib/docker. Nada máis debería "tocar, pinchar ou tocar" ningún ficheiro Docker situado neste cartafol.

Por que é así? Porque este é o resultado dunha das leccións máis difíciles aprendidas ao desenvolver dotCloud. O motor de contedores dotCloud funcionou ao ter varios procesos que acceden a /var/lib/dotcloud simultaneamente. Trucos astutos como a substitución de ficheiros atómicos (en lugar da edición no lugar), o código peppering con bloqueos consultivos e obrigatorios e outros experimentos con sistemas seguros como SQLite e BDB non sempre funcionaron. Cando estabamos a redeseñar o noso motor de contedores, que finalmente se converteu en Docker, unha das grandes decisións de deseño foi consolidar todas as operacións de contedores baixo un único daemon para eliminar todas as tonterías de concorrencia.

Non me malinterpretes: é totalmente posible facer algo bo, fiable e rápido que implique múltiples procesos e control paralelo moderno. Pero pensamos que é máis sinxelo escribir e manter código usando Docker como único reprodutor.

Isto significa que se compartes o directorio /var/lib/docker entre varias instancias de Docker, terás problemas. Por suposto, isto pode funcionar, especialmente nas primeiras fases das probas. "Escoita, mamá, podo executar ubuntu como un docker!" Pero proba algo máis complexo, como tirar a mesma imaxe de dúas instancias diferentes, e verás que o mundo arde.

Isto significa que se o teu sistema de CI realiza compilacións e reconstrucións, cada vez que reinicias o teu contedor Docker-in-Docker, corres o risco de soltar unha bomba nuclear na súa caché. Isto non é xenial!

A solución

Imos dar un paso atrás. Necesitas realmente Docker-in-Docker ou só queres poder executar Docker e construír e executar contedores e imaxes desde o teu sistema CI mentres ese propio sistema CI está nun contedor?

Aposto que a maioría da xente quere esta última opción, o que significa que queren que un sistema de CI como Jenkins poida executar contedores. E a forma máis sinxela de facelo é simplemente inserir un socket Docker no seu contenedor CI e asocialo coa bandeira -v.

Simplemente, cando executes o teu contenedor CI (Jenkins ou outro), en lugar de piratear algo xunto con Docker-in-Docker, iníciao coa liña:

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

Este contedor agora terá acceso ao socket Docker e, polo tanto, poderá executar contedores. Excepto que en lugar de executar contedores "nenos", lanzará contedores "irmáns".

Proba isto usando a imaxe oficial de Docker (que contén o binario de Docker):

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

Parece e funciona como Docker-in-Docker, pero non é Docker-in-Docker: cando este contedor cree contedores adicionais, crearanse no Docker de nivel superior. Non experimentarás os efectos secundarios do aniñamento e a caché de montaxe compartirase en varias chamadas.

Nota: As versións anteriores deste artigo recomendaban ligar o binario de Docker do host ao contedor. Agora non é fiable xa que o motor Docker xa non abarca bibliotecas estáticas ou case estáticas.

Entón, se queres usar Docker de Jenkins CI, tes dúas opcións:
instalando a CLI de Docker usando o sistema básico de empaquetado de imaxes (é dicir, se a súa imaxe está baseada en Debian, use paquetes .deb), usando a API de Docker.

Algúns anuncios 🙂

Grazas por estar connosco. Gústanche os nosos artigos? Queres ver máis contido interesante? Apóyanos facendo un pedido ou recomendando a amigos, Cloud VPS para desenvolvedores desde 4.99 $, un análogo único de servidores de nivel de entrada, que inventamos nós para ti: Toda a verdade sobre VPS (KVM) E5-2697 v3 (6 núcleos) 10 GB DDR4 480 GB SSD 1 Gbps desde 19 dólares ou como compartir un servidor? (dispoñible con RAID1 e RAID10, ata 24 núcleos e ata 40 GB DDR4).

Dell R730xd 2 veces máis barato no centro de datos Equinix Tier IV en Amsterdam? Só aquí 2 x Intel TetraDeca-Core Xeon 2x E5-2697v3 2.6GHz 14C 64GB DDR4 4x960GB SSD 1Gbps 100 TV desde $199 nos Países Baixos! Dell R420 - 2x E5-2430 2.2Ghz 6C 128GB DDR3 2x960GB SSD 1Gbps 100TB - desde $ 99! Ler sobre Como construír a infraestrutura corp. clase co uso de servidores Dell R730xd E5-2650 v4 por valor de 9000 euros por un centavo?

Fonte: www.habr.com

Engadir un comentario