Quando se trata de DevOps, orquestrar contêineres é um ponto vital. Isso se deve ao fato de que, em um ambiente DevOps, a entrega da infra ocorre como código.
Mas não se assuste (ainda), estamos apenas começando e, para entender direitinho como tudo isso funciona, vamos falar de Docker, Swarm e Portainer.
Não vamos entrar em debate sobre qual ferramenta é melhor, mas sim, ensinar na prática como orquestrar contêineres utilizando essas três ferramentas e o sistema operacional Linux.
É importante frisar que nosso foco principal é na ferramenta Docker, fornecedora de contêineres.
Vamos lá?
Não vamos pular etapas: deixe o kubernetes pra depois
É claro que a ferramenta mais indicada para orquestração de contêineres Docker é o Kubernetes.
Mas não se engane: precisamos aprender a dirigir o 1.0 turbo antes de pegarmos o V8. Por isso o Docker Swarm simplificará nossos primeiros passos.
Apesar de muitas opiniões contrárias, o Swarm se sai muito bem em produção, sim. Se você o utilizar direito, a migração pro Kubernetes vai ser simples um dia.
>>Leitura Recomendada:
Usando o MediatR com ASP.NET Core
O Swarm na prática
O Swarm é um modo nativo do docker, que, quando habilitado, clusteriza um conjunto de computadores.
Após o devido ingresso no cluster, o modo swarm passa a atuar como hospedeiro para qualquer contêiner que precise dos recursos disponíveis no cluster.
Neste modo, você cria “Services”, em vez de contêineres. Agora imagine o ‘Service’ como se fosse um projeto arquitetônico de uma casa.
A partir desse projeto arquitetônico, você diz pro swarm quantas casas (contêineres) você quer construir, e pronto: os contêineres são criados e distribuídos no cluster.
>>Leitura Recomendada:
Os principais serviços da arquitetura AWS!
Services e contêineres
Sim. No mundo DevOps você projeta e a linha de produção faz acontecer.
Considere o Docker como uma de nossas linhas de produção. Ele pode atuar de forma harmoniosa com várias linhas de produção simultâneas, que dividem seus recursos para otimizar a entrega. Isso é swarm, linhas de produção integradas.
Quando você cria um cluster Swarm, considere que é necessário no mínimo três computadores e eles são classificados em managers e workers.
Os managers têm alguns ‘privilégios’ e podem ditar como o cluster trabalha.
Agora, guarde isso: é necessário no mínimo três masters para um cluster saudável.
Para iniciar um cluster swarm, instale o docker no seu linux preferido. Considerando o IP da sua maquina como “192.168.0.6”, dê o comando:
$ docker swarm init
A resposta será:
Swarm initialized:
To add a worker to this swarm, run the following command:
$docker swarm join –token AEOIHEAOE-1-aefuihfea342342i3u42iuh24g54g2h4 no23nih4i2u3ni424oi23n42u4gn2o3i 192.168.0.6:2377
Ele, além de inicializar o cluster, ainda te passa o comando que você deve rodar nos outros ‘nós’ para que eles ingressem como “WORKERS” no ecossistema.
Para obter o comando de ingresso de novos “MASTERS” (precisamos de três para um cluster saudável), digite “docker swarm join-token manager”.
Um cluster em dois comandos. Nem parece possível.
Portainer – Enterprise ready
Estamos aqui para entender o que acontece em um orquestrador de contêineres, então vamos utilizar um gestor gráfico chamado Portainer.
Eu sei que uma tecnologia muito falado atualmente é o Kubernetes, está em alta. Mas, para começar a orquestrar, o Portainer pode ser a solução ideal. Se te interessar mais tarde, aqui está uma comparação: Portainer vs Kubernetes.
O Portainer é uma interface web que interage com o socket do docker para criar novos contêineres e monitorá-los.
O Portainer também pode ser utilizado para visualizar o cluster, gerenciar a autenticação de usuários e permissões de acesso ao cluster.
O portainer é, de forma resumida, uma aplicação para gerenciar seus containers, estejam eles em cluster ou não.
Eles tem objetivo de agilizar a movimentação desses contêineres no momento de carga e descarga.
Outro detalhe legal: você pode administrar vários clusters Swarm em um único portainer.
Utilizando o “Portainer Agent” você se conecta em outros clusters, acessa a Shell de qualquer contêiner, migra suas Stacks — já vamos falar disso — para outros clusters e muito mais.
Poderíamos fazer isso expondo a API do Docker?
Sim, mas o processo varia de acordo com a distribuição Linux que você utiliza, então vamos facilitar as coisas.
Por enquanto o agente do Portainer é o suficiente.
O Portainer como serviço
Esta solução na verdade é composta de dois serviços, o Portainer em si e o agente.
O agente é responsável pela comunicação da interface web de administração e os nós do cluster. Assim você poderá acessar qualquer container ou volume, ver logs, etc.
Para subir o agente use o comando:
$ docker service create \
--name portainer_agent \
--network apps \
-e AGENT_CLUSTER_ADDR=tasks.portainer.agent \
--mode global \
--constraint 'node.platform.os == linux' \
--mount type=bind,src=/var/run/docker.sock,dst=/var/run/docker.sock \
--mount type=bind,src=/var/lib/docker/volumes,dst=/var/lib/docker/volumes \
portainer/agent
Parece complicado, mas vamos entender as novidades em relação ao comando de criação do serviço do traefik.
Por meio do “-e”, passamos uma variável de ambiente com um endereço pro nosso agente. Em seguida determinamos o modo global, ou seja, todos os nós do cluster devem rodar esse contêiner.
Como essa imagem é para nós Linux, usamos a constraint para garantir que ele não vai rodar em nós com outro sistema operacional.
Pra fechar montamos o socket do docker e o diretório de volumes do docker, assim o Portainer pode administrar os volumes e containers em qualquer nó em que o agente estiver.
Finalmente, suba o Portainer com o comando:
$ docker service create -t \ --name portainer \ --network apps \ --replicas=1 \ --constraint 'node.role == managem' \ --mount type=bind,src=/var/run/docker.sock,dst=/var/run/docker.sock \ --mount type=bind,src=/mnt/portainer,dst=/data \ -l “traefik.docker.network=app” \ -l “traefik.frontend.rule=Host:portainer.lab.local” \ -l “trafik.port=9000” \ portainer/portainer -H “tcp://tasks.portainer.agent:9001” --tlsskipverify
O que muda aqui, é que só teremos uma réplica. este serviço deve rodar apenas em nós que sejam “managers” do swarm.
Também persistimos o diretório do container “/data” no diretório local do host “/mnt/portainer”.
Em seguida passamos os labels pro nosso front-end encaminhar requisições para o endereço “portainer.lab.local” diretamente para o contêiner do Portainer na porta 9000.
Pra fechar, apontamos para o endereço dos agentes ignorando a verificação ssl e PUM! Tá no ar!
Como eu faço a orquestração de contêineres na prática?
A introdução foi longa, mas necessária. Revise tudo acima até imergir no contexto.
Remova quaisquer resquícios de outras versões do docker:
$ sudo apt-get remove docker docker-engine docker.io containerd runc
Instale os pré requisitos:
$ sudo apt-get install apt-transport-https ca-certificates curl gnupg-agent software-properties-common
Configure o repositório oficial do Docker
Adicionando Chaves do repositório
$ curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo apt-key add -
$ sudo apt-key fingerprint 0EBFCD88
Adicionando repositório oficial do Docker-ce
$ sudo add-apt-repository \
"deb [arch=amd64] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) \
stable
Instalando docker
$ sudo apt-get update
$ sudo apt-get install docker-ce docker-ce-cli containerd.io
IMPORTANTE: repita esses passos em todas as Vm’s. Em seguida vamos criar nosso cluster.
Inicializando cluster SWARM
Para inicializar o cluster, acesse a vm 1, acesse como root e dê o comando:
$ docker swarm init
A saída desse comando vai te dar a instrução de adicionar workers ao cluster, mas queremos managers. Afinal, precisamos de 3 managers para um cluster saudável, lembra?
Para obter o comando de inclusão de managers, digite o comando:
$ docker swarm join-token manager
A saída desse comando nada mais é que o que você precisa executar em todos as demais VM’s para que elas entrem no cluster como Managers.
A cereja do bolo
Apesar de não ser nosso escopo, não é nada prático acessarmos nossos serviços por meio de um endereço de IP.
Então vamos utilizar um Front-end para encaminhar nossas requisições “HTTP” para os contêineres que rodam aplicações web.
Para isso, vamos usar o Traefik, que é um front-end super performático e otimizado para nosso ambiente cloud.
Com ele, em vez de criarmos “virtual Hosts” em um Front-end Apache por exemplo, basta que informemos algumas “labels” na hora de subir nossos contêineres.
Para subir (já como um service dentro do swarm) o Trafik, primeiramente crie a rede que ele vai utilizar para fazer a ponte de frontend com os demais containers:
$ docker network create --driver overlay -- attachable --subnet=192.162.250.0/24 apps
Este comando cria uma rede usando o driver overlay, que vai interagir com todo o cluster e pode ser anexada aos contêineres que forem criados. É importante escolher uma faixa de rede incomum para evitar problemas de roteamento.
Em seguida crie o contêiner do traefik:
$ docker service create --name Frontend -- network apps --mount type=bind,src=/var/run/docker.sock,dst=/var/run/docker.sock -p 80:80 -p 8080:8080 traefik:latest --docker --docker.watch --api
Que beleza!
Um front-end em duas linhas de comando. Vamos entender o que cada parte do comando significa:
“docker service create” = Estamos informando pro Docker que vamos criar um serviço do swarm.
“–name Frontend” = Estamos atribuindo um nome a este serviço. Nesse caso o serviço vai se chamar “Frontend”.
“–mount type=bind,src=/var/run/docker.sock,dst=/var/run/docker.sock” = Monte um volume do tipo “diretório local” no caminho “/var/run/docker.sock” dentro do contêiner pro mesmo caminho. é através desse socket do docker que o traefik detecta novos contêineres.
“-p 80:80 -p 8080:8080” = Exponha essas portas apontando para o contêiner. Seria um “nat” da porta externa do host docker, para interna do contêiner.
“traefik:latest” = Imagem docker que vamos usar para esse serviço. Nesse caso a do traefik na última versão.
“–docker –docker.watch –api” = Comandos passados para o contêiner do nosso frontend, de acordo com a documentação do traefik.
Na prática, informamos ao traefik que ele vai monitorar o ambiente docker por meio do socket montado e que vai disponibilizar uma interface web para consultas de API e monitoramento visual.
>>Leitura Recomendada:
Arquitetura de microsserviços x Arquitetura Monolítica
Algumas coisas ainda não fazem sentido
O mundo Docker é imenso e eu acabei de te mostrar apenas uma das milhares de formas de se subir um cluster e uma interface de gerenciamento.
Explore este ambiente e veja que, por meio do portainer, boa parte acontece em background no docker.
Lembra dos yamls e Stacks? Falamos sobre isso no artigo sobre os Pilares DevOps?
O portainer é perfeito para que você veja isso funcionando. Quer uma dica para sua primeira stack?
Faça uma com o serviço “Visualizer”. Com ele você visualiza seus contêineres em tempo real. Em que nós os containers estão rodando, veja-os saltando de nó em nó, etc etc..
Qual a conclusão sobre orquestração de ambientes?
Espero ter ajudado com um “norte” na sua caminhada Docker. Muita coisa é novidade e, naturalmente, você precisa de um tempo de adaptação. Agora é questão de persistir e testar. O resto vem naturalmente.
Grande abraço!