Como eu executei o Docker dentro do Docker e o que resultou disso

Olá a todos! Em minha artigo anterior, eu prometi falar sobre a execução do Docker dentro do Docker e os aspectos práticos dessa atividade. Chegou a hora de cumprir minha promessa. Um DevOps experiente pode argumentar que para quem precisa do Docker dentro do Docker, a solução é simplesmente passar o socket do daemon do Docker do host para dentro do container, e isso é suficiente em 99% dos casos. Mas não se apresse em me jogar cookies, pois aqui falaremos sobre a execução real do Docker dentro do Docker. Essa solução tem muitas áreas de aplicação possíveis e este artigo aborda uma delas, então, acomode-se e estique as mãos à sua frente.

Como eu executei o Docker dentro do Docker e o que resultou disso

Início

Tudo começou numa chuvosa noite de setembro, quando eu estava limpando uma máquina alugada por $5 na Digital Ocean, que congelou completamente porque o Docker ocupou todos os 24 gigabytes de espaço em disco disponível com suas imagens e containers. A ironia era que todas essas imagens e containers eram transitórios e precisavam apenas para testar a funcionalidade do meu aplicativo toda vez que uma nova versão de alguma biblioteca ou framework era lançada. Eu tentei escrever scripts shell e configurar agendamentos cron para limpar a bagunça, mas isso não funcionou: sempre acabava resultando que o espaço em disco do meu servidor estava consumido e o servidor estava travado (na melhor das hipóteses). Em algum momento, me deparei com um artigo sobre como executar o Jenkins em um container e como ele pode criar e remover pipelines de build através de um socket do daemon Docker passado para ele. A ideia me agradou, mas decidi ir além e experimentar a execução direta do Docker dentro do Docker. Naquele momento, parecia uma solução bem lógica baixar imagens do Docker e criar containers de todos os aplicativos que eu precisava para testes dentro de outro container (vamos chamá-lo de container de staging). A ideia era iniciar o container de staging com a flag -rm, que remove automaticamente todo o container com todo o seu conteúdo ao ser parado. Eu brinquei com a imagem do Docker do próprio Docker (https://hub.docker.com/_/docker), mas era muito complexo e eu não consegui fazê-lo funcionar da maneira que eu precisava, e eu queria seguir todo o caminho sozinho.

Prática. Aprendizados.

Eu tinha o objetivo de fazer o contêiner funcionar como eu precisava e continuei meus experimentos, resultado dos quais foram incontáveis obstáculos. O resultado da minha autocrítica foi o seguinte algoritmo:

  1. Iniciamos o contêiner Docker em modo interativo.

    docker run --privileged -it docker:18.09.6

    Preste atenção na versão do contêiner; um pequeno erro e seu DinD se transforma em abóbora. Na verdade, tudo quebra com bastante frequência quando uma nova versão é lançada.
    Devemos entrar diretamente no shell.

  2. Tentamos descobrir quais contêineres estão em execução (Resposta: nenhum), mas vamos executar o comando de qualquer forma:

    docker ps

    Você ficará um pouco surpreso, mas parece que o daemon Docker nem está em execução:

    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 iniciá-lo manualmente:

    dockerd &

    Mais uma desagradável surpresa:

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

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

    apk add --no-cache iptables bash

  5. Iniciamos o bash. Finalmente estamos de volta ao shell familiar.

  6. vamos tentar iniciar o Docker mais uma vez:

    dockerd &

    Devemos ver uma longa lista de logs 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 ao bash.

A partir deste momento, podemos tentar iniciar outros contêineres dentro do nosso contêiner Docker, mas e se quisermos levantar mais um contêiner Docker dentro do nosso contêiner Docker ou se algo der errado e o contêiner "sair"? Começar tudo de novo.

Contêiner DinD próprio e novas experiências

Como eu executei o Docker dentro do Docker e o que resultou disso
Para não repetir os passos descritos acima vez após vez, criei meu próprio contêiner DinD:

https://github.com/alekslitvinenk/dind

A solução DinD funcional me permitiu executar o Docker dentro do Docker recursivamente e realizar experiências mais ousadas.
Um experimento (bem-sucedido) com a execução do MySQL e Nodejs que vou descrever agora.
Os mais impacientes podem ver como isso foi feito aqui.

Por que no hosting comum a administração do PrestaShop é lenta, e no seu não é?

Então, vamos começar:

  1. Iniciamos 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 a iniciar contêineres filhos imediatamente.

  2. Iniciando o MySQL:

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

  3. Conectamo-nos ao banco de dados da mesma forma que nos conectaríamos localmente. Garantimos que tudo está funcionando.

  4. Iniciando o segundo contêiner:

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

    Observe que o mapeamento de porta aqui será exatamente 8080:8080, pois já mapeamos a porta 80 do host para o contêiner pai na porta 8080.

  5. Vamos para localhost no navegador e certificamo-nos de que o servidor responde "Hello World!".

No meu caso, a experiência com contêineres Docker aninhados foi bastante positiva e continuarei a desenvolver o projeto e usá-lo para staging. Parece-me uma solução muito mais leve do que o Kubernetes e Jenkins X. Mas essa é a minha opinião subjetiva.

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

P.S. Se você achar este projeto útil, por favor, dê uma estrela no GitHub, faça um fork e conte aos amigos.

Edit1 Corrigi os erros, foquei em 2 vídeos

Fonte: habr.com

Compre hospedagem confiável para sites com proteção contra DDoS, servidores VPS VDS 🔥 Compre hospedagem confiável para sites com proteção contra DDoS, servidores VPS VDS | ProHoster