Olá a todos! No 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 (
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:
-
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. -
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
-
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
-
Instale os pacotes iptables e bash (tudo é mais agradável de trabalhar no bash do que no sh):
apk add --no-cache iptables bash
-
Vamos lançar o bash. Finalmente estamos de volta ao shell habitual
-
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
-
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
Para evitar repetir as etapas acima repetidamente, criei meu próprio contêiner 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:
-
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.
-
Inicie o MySQL:
docker run --name mysql -e MYSQL_ROOT_PASSWORD=strongpassword -d -p 3306:3306 mysql
-
Nós nos conectamos ao banco de dados da mesma forma que nos conectaríamos localmente. Vamos garantir que tudo funcione.
-
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.
-
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