Como executei o Docker dentro do Docker e o que resultou dele

Olá a todos! No dele artigo anterior, prometi falar sobre como executar o Docker no Docker e os aspectos práticos do uso desta lição. É hora de cumprir sua promessa. Um devopser experiente provavelmente objetará que aqueles que precisam do Docker dentro do Docker simplesmente encaminharão o soquete do daemon do Docker do host para o contêiner e isso será suficiente em 99% dos casos. Mas não se apresse em jogar biscoitos em mim, porque falaremos sobre como realmente executar o Docker dentro do Docker. Esta solução tem muitas aplicações possíveis e este artigo é sobre uma delas, então sente-se e estique os braços à sua frente.

Como executei o Docker dentro do Docker e o que resultou dele

começo

Tudo começou em uma noite chuvosa de setembro, quando eu estava limpando a máquina que aluguei por US$ 5 na Digital Ocean, que estava congelada porque o Docker havia preenchido todos os 24 gigabytes de espaço disponível em disco com suas imagens e contêineres. A ironia é que todas essas imagens e contêineres eram transitórios e necessários apenas para testar o desempenho do meu aplicativo sempre que uma nova versão de uma biblioteca ou estrutura era lançada. Tentei escrever scripts de shell e configurar um cronograma cron para limpar o lixo, mas não ajudou: toda vez que terminava inevitavelmente com o espaço em disco do meu servidor sendo consumido e o servidor travando (na melhor das hipóteses). Em algum momento, me deparei com um artigo sobre como executar o Jenkins em um contêiner e como ele pode criar e excluir pipelines de construção por meio de um soquete docker daemon encaminhado para ele. Gostei da ideia, mas decidi ir mais longe e tentar executar o Docker diretamente dentro do Docker. Naquela época, parecia-me uma solução completamente lógica baixar imagens do Docker e criar contêineres para todos os aplicativos que eu precisava para testar dentro de outro contêiner (vamos chamá-lo de contêiner de teste). A ideia era iniciar um contêiner de teste com o sinalizador -rm, que exclui automaticamente todo o contêiner e todo o seu conteúdo quando ele é interrompido. Eu mexi na imagem do Docker do próprio Docker (https://hub.docker.com/_/docker), mas acabou sendo muito complicado e nunca consegui fazê-lo funcionar do jeito que precisava e queria ir até o fim sozinho.

Prática. Cones

Decidi fazer o recipiente funcionar da maneira que eu precisava e continuei meus experimentos, que resultaram em uma infinidade de botões. O resultado da minha autotortura foi o seguinte algoritmo:

  1. Lançamos o contêiner Docker em modo interativo.

    docker run --privileged -it docker:18.09.6

    Preste atenção na versão do container, dê um passo para a direita ou para a esquerda e seu DinD vira uma abóbora. Na verdade, as coisas quebram com frequência quando uma nova versão é lançada.
    Devemos entrar imediatamente na casca.

  2. Estamos tentando descobrir quais contêineres estão em execução (Resposta: nenhum), mas vamos executar o comando mesmo assim:

    docker ps

    Você ficará um pouco surpreso, mas acontece que o daemon do Docker nem está rodando:

    error during connect: Get http://docker:2375/v1.40/containers/json: dial tcp: lookup docker on 
    192.168.65.1:53: no such host

  3. Vamos executá-lo nós mesmos:

    dockerd &

    Outra surpresa desagradável:

    failed to start daemon: Error initializing network controller: error obtaining controller instance: failed 
    to create NAT chain DOCKER: Iptables not found

  4. Instale os pacotes iptables e bash (tudo é mais agradável de trabalhar no bash do que no sh):

    apk add --no-cache iptables bash

  5. Vamos lançar o bash. Finalmente estamos de volta ao shell habitual

  6. Vamos tentar executar o Docker novamente:

    dockerd &

    Devemos ver uma longa folha de registros terminando com:

    INFO[2019-11-25T19:51:19.448080400Z] Daemon has completed initialization          
    INFO[2019-11-25T19:51:19.474439300Z] API listen on /var/run/docker.sock

  7. Pressione Enter. Estamos de volta à festa.

De agora em diante, podemos tentar lançar outros contêineres dentro de nosso contêiner Docker, mas e se quisermos lançar outro contêiner Docker dentro de nosso contêiner Docker ou algo der errado e o contêiner travar? Começar tudo de novo.

Próprio contêiner DinD e novos experimentos

Como executei o Docker dentro do Docker e o que resultou dele
Para evitar repetir as etapas acima repetidamente, criei meu próprio contêiner DinD:

https://github.com/alekslitvinenk/dind

A solução DinD funcional me deu a capacidade de executar o Docker dentro do Docker recursivamente e fazer experimentos mais aventureiros.
Vou descrever um desses experimentos (bem-sucedidos) com a execução de MySQL e Nodejs agora.
Os mais impacientes podem ver como foi aqui

Então vamos começar:

  1. Lançamos o DinD em modo interativo. Nesta versão do DinD, precisamos mapear manualmente todas as portas que nossos contêineres filhos podem usar (já estou trabalhando nisso)

    docker run --privileged -it 
    -p 80:8080 
    -p 3306:3306 
    alekslitvinenk/dind

    Entramos no bash, de onde podemos começar imediatamente a lançar contêineres filhos.

  2. Inicie o MySQL:

    docker run --name mysql -e MYSQL_ROOT_PASSWORD=strongpassword -d -p 3306:3306 mysql

  3. Nós nos conectamos ao banco de dados da mesma forma que nos conectaríamos localmente. Vamos garantir que tudo funcione.

  4. Inicie o segundo contêiner:

    docker run -d --rm -p 8080:8080 alekslitvinenk/hello-world-nodejs-server

    Observe que o mapeamento da porta será exatamente 8080:8080, uma vez que já mapeamos a porta 80 do host para o contêiner pai até a porta 8080.

  5. Vamos para localhost no navegador, certifique-se de que o servidor responda “Hello World!”

No meu caso, o experimento com contêineres Docker aninhados acabou sendo bastante positivo e continuarei desenvolvendo o projeto e utilizando-o para teste. Parece-me que esta é uma solução muito mais leve que Kubernetes e Jenkins X. Mas esta é minha opinião subjetiva.

Acho que isso é tudo para o artigo de hoje. No próximo artigo, descreverei com mais detalhes experimentos com a execução recursiva do Docker no Docker e a montagem de diretórios profundamente em contêineres aninhados.

PS Se você achar este projeto útil, dê uma estrela no GitHub, faça um fork e conte para seus amigos.

Edit1 Erros corrigidos, focado em 2 vídeos

Fonte: habr.com

Adicionar um comentário