O que é o Docker Swarm

O Docker é o mais popular sistema de gerenciamento de containers do mercado. Existem outros, mas com menor relevância. A Docker Inc. possui produtos que auxiliam em todo o ciclo de vida dos contêineres como docker-compose e o Docker Swarm. O Swarm é a ferramenta responsável pela orquestração dos contêineres. Entenda que orquestrar é garantir que, primeiramente, o ciclo de vida dos contêineres seja gerenciado. Isso significa que a criação, atualização, deploy, escalabilidade, configuração e afins dos contêineres ocorram conforme as expectativas.

Além disso a Docker Inc em dezembro de 2014 fez a versão beta do Docker Swarm, porém ele dependia do uso de um service Discovery externo (como etcd, zookeeper, consul e outros). Porém ele passou a incorporar o produto Docker só em julho de 2016. Nesse momento ele recebeu o nome de Swarm mode. A estrutura que já se chamava Swarm passou a se chamar ‘Swarm classic’. Atualmente ele está bem mais sofisticado suportando o conceito de secrets (tokens e senhas podem ser gerenciados pelo Swarm), stacks (agrupamento de contêineres e serviços), configs (configurações compartilhadas) e autolock (exigir senha mesmo para nodos administrativos). Esse artigo explica de maneira geral porque existem orquestradores e como o Docker Swarm tenta lidar com os problemas envolvidos nesse cenário.

Para que utilizar um orquestrador de contêineres?

Desenvolver utilizando contêineres é algo que facilita muito o trabalho além de reduzir a bagunça que é gerada na máquina do dev. Entretanto, quando falamos de ambiente de homologação ou produção a situação é outra. Para fins didáticos estou considerando ambientes sem CI/CD. Imagine que uma aplicação dependa de 3 containers (um de front com Angular 13, um de back-end com NodeJS e um com o MySQL). Imagine também que essa aplicação seja acessada por 30000 usuários por semana em média.

Considerando esse cenário, devemos pensar que a aplicação precisa estar com várias instâncias replicadas para garantir disponibilidade. Então, o front talvez não tenha 1 container, mas sim 10 containers ou 100 containers; a mesma coisa deve ser pensada para o back-end e a mesma coisa para o banco. Mas além disso outras práticas podem ser consideradas como estruturação de cache, uso de CQRS etc. E além de tudo isso, as atualizações do sistema precisam ser feitas aos poucos e de modo que não tenha downtime.

O problema a resolver

Veja que o Docker puro não é suficiente para lidar com questões como essa e nesse cenário entra o orquestrador de contêineres. Os mais conhecidos são o Docker Swarm e o Kubernetes (k8s). Veja um pequeno resumo das questões que os orquestradores visam resolver:

  • Gerenciar o ciclo de vida dos containers
  • Escalar
  • Recriar contêineres que morreram
  • Atualizar o sistema sem downtime
  • Publicar contêineres
  • Comunicação entre os Contêineres
  • Gerenciar secredos

A solução a esperar

Entendido o problema acerca dos contêineres que justifica os orquestradores agora precisamos entender o que deve ser orquestrado. Os elementos mais evidentes são os nodos (podemos ter 1, 10 ou 100 instâncias do próprio Docker); os contêineres; as redes, os volumes e o monitoramento de todo o ambiente. Por fim o que se pretende com tudo isso é, de maneira geral garantir as seguintes premissas:

  • Aplicação sempre rodando (alta disponibilidade)
  • Escalabilidade automática (crescer ou diminuir conforme desejado)
  • Tolerância a falhas (se falhar não refletir para o usuário e se rearranjar sozinho)
  • Otimização do uso dos recursos (consumir quanto for necessário: nem mais nem menos)
  • Redução da intervenção manual (evitar erros humanos tão comuns com todas as commad-lines)

Swarm mode

Quando o Docker está em Swarm mode um conjunto de estruturas passa a estar disponível na infraestrutura. Eles têm por objetivo suportar os objetivos de orquestração de contêineres explicados acima:

  • Cluster (agrupamento de máquinas Docker que de modo coordenado garante o funcionamento dos containers)
  • Node (cada host do cluster é um node)
  • Stacks (aglomerado de serviços que se comunicam entre si)
  • Services (são os serviços isolados)
  • Tasks (são as tarefas mínimas para a execução e controle do container)

Tipos de nodos

Para o funcionamento do Docker no modo Swarm as máquinas assumem dois tipos de papéis distintos: manager e worker. Manager são os nodos que decidem onde os contêineres serão executados, suportam comandos administrativos, gerenciam todo o cluster e visam garantir o que chamamos de ‘desired states’ (por exemplo, se um container foi feito para ter 3 réplicas, o manager vai fazer o possível para garantir isso); Workers são as instancias que efetivamente rodam os containers (os managers também podem rodar containers) e reportam o estado deles para os managers.

A comunicação entre os novos para o melhor funcionamento do cluster é feita utilizando TLS. Do ponto de vista de algoritmos a comunicação dos workers é realizada através do glossip protocol (protocolo de fofocas ou protocolo de epidemias, https://academy.bit2me.com/pt/que-es-gossip-protocol/). Já os líderes possuem objetivos diferentes e uso o algoritmo de manutenção de consenso Raft.

Alta disponibilidade

Dentre os managers um sempre é o líder, ou seja, aquele que de fato centraliza a recepção de informações de todo o cluster. Caso haja uma queda do nodo líder um nodo líder deverá ser eleito. A liderança é suportada por um algoritmo específico de manutenção de consenso, o Raft (https://docs.docker.com/engine/Swarm/raft/). Ele funciona assim, resumidamente:

  • Se o líder está online, nada ocorre
  • Todos os managers possuem um tempo de expiração interno. Quando esse tempo é alcançado ele verifica se o líder está online. Se não estiver, ele solicita votos dos demais nodos. Se eleito ele se torna o novo líder.
    • Ele é eleito por maioria de votos (managers / 2 + 1)
    • Se ocorrer a coincidência de 2 nodos solicitarem a liderança ao mesmo tempo, eles não terão maioria de votos e ficarão esperando até que um novo nodo expire e solicite votos. Esse será eleito.

Existe uma quantidade ideal de managers para que ocorra um consenso adequado na rede. O quadro abaixo exemplifica. Note que redes com mais de 7 managers podem gerar muito overhead, sendo algo não recomendado. Normalmente se utiliza entre 3 e 5. O ideal é sempre manter número ímpar de managers.

Como funciona a criação e um serviço

No Docker Swarm não se cria um contêiner, mas sim um service, que agrupa outras estruturas, além de suportar a escala da imagem associada. Vamos analisar a seguinte linha de comando

docker service create nginx
  1. Cria-se a requisição para criação do serviço
  2. API do docker recebe a request
  3. Orchestrator se organiza para garantir o estado ideal (desired state)
  4. Allocator atribui um endereço IP a task que está sendo criada
  5. Dispacher define o nó que receberá a task,
  6. Scheduler agenda o momento para que a task seja executada pelo worker

O worker fica todo o momento buscando tasks e avisando de seu próprio estado.

Alta disponibilidade geográfica

Uma vantagem interessante é a possibilidade de associar labels ao node. É possível desse modo orientar ao provedor de nuvem que prefira colocar algumas imagens em um az ou em outro. Com isso caso haja uma indisponibilidade de uma AZ a chance de sua aplicação continuar disponível é bastante alta.

docker node update --label-add "az=sa-east-1" nginx
docker node update --placement-pref "spread=node.label.az" nginx

Criptografia interna

O Docker Swarm possui uma estrutura robusta de criptografia interna baseada em TLS e possui um padrão de expiração das chaves de 3 meses, mas é possível reduzir esse valor para 1 hora. Para mais detalhes use a linha de comando

docker Swarm ca --help

Autolock

No docker os nós administrativos são os únicos que suportam alguns comandos específicos do cluster, tais como docker nodes ls, docker Swarm join-token, etc. É importante entender que a comunicação entre os nodos administrativos é feita através do Raft que possuem seus logs no docker e que podem ser criptografados através da técnica do autolock.

O comando a seguir pode ser utilizado para ligar o autolock. Após isso é necessário reiniciar o serviço do docker e passar a token de acesso (recebido quando foi dado o comando de bloqueio). Essa melhoria veio por conta de um recurso chamado secrets, adicionado ao Swarm, que será explicado a seguir.

docker Swarm init --autolock
docker Swarm update --autolock

Secrets

Um problema comum em relação a orquestração dos contêineres é como lidar com senhas, logins, tokens etc. que devemos passar por parâmetro. O docker Swarm resolve essa questão com uma feature chamada secrets. Basicamente os secrets ficam associadas ao servisse e são criptografados, acessíveis apenas por dentro do próprio container através de um arquivinho num TempFS, desse modo, a responsabilidade real da segurança do segredo é da aplicação.

echo "minha-senha-complicada" | docker secret create arquivodesenha -d
docker service create --secret-add= arquivodesenha nginx
docker service create --secret-rm= arquivodesenha nginx

Para encontrar o arquivo da senha dentro do container basta rodar o comando:

cat /run/secrets/arquivodesenha

Config

A gestão das configurações do container possui um problema bastante semelhante à gestão das senhas e a solução dada pelo docker Swarm também é muito parecida.

echo "config" | docker config create minhaconfiguracao
docker service create --config-add=minhaconfiguracao nginx
docker service update --config-rm=minhaconfiguracao nginx

para encontrar a configuração dentro do container, basta acessar:

cat /minhaconfiguracao

Healthcheck

No momento da criação de um serviço docker é possível indicar características a cerca das expectativas de saúde dele. Por exemplo, é possível indicar um comando para verificação (por exemplo um curl esperando HTTP 200 de retorno), um intervalo de tempo para testar novamente etc. Veja a seguir algumas das possibilidades de parâmetros que podem ser associados.

docker service create
--health-cmd (comando a ser executado
--health-interval (intervalo)
--health-retries (tentativas)
--health-start-period (quando começa)
--health-timeout (tempo de timeout)
--no-healthcheck (se não haverá healthcheck)

Deployment

Ao fazer a atualização de um serviço há de se levar em consideração qual será a estratégia utilizada. Vamos a uns pontos:

  • matar todos os containers atuais e depois levantar os novos ou o contrário?
  • Implantar em série ou em paralelo?
  • Um por vez ou em blocos de 3, 5, …?
  • Como monitorar o sucesso da implantação?
  • O docker deve descansar (dar um sleeptime) entre um bloco de implantação e outro?
  • Dado um percentual de falha: deverá ter ação de contorno?
  • Qual? Pausar, rollback ou continuar (sem ação de contorno)

Veja a seguir o comando e os parâmetros normalmente utilizados nesse cenário

docker service update
--update-parallelism
--update-order
--update-monitor
--update-delay
--update-max-failure-ratio
--update-failure-action

Logs

Algo interessante no docker Swarm é a consolidação dos logs. É possível ver todos os logs de um serviço através do comando a seguir. Porém, considere que os logs podem ainda não ter sido sincronizado com o manager: eles não atualizam em tempo real.

docker service logs --tail 20 nginx | sort -k3 -4

Thiago Anselme
Thiago Anselme - Gerente de TI - Arquiteto de Soluções

Ele atua/atuou como Dev Full Stack C# .NET / Angular / Kubernetes e afins. Ele possui certificações Microsoft MCTS (6x), MCPD em Web, ITIL v3 e CKAD (Kubernetes) . Thiago é apaixonado por tecnologia, entusiasta de TI desde a infância bem como amante de aprendizado contínuo.

Deixe um comentário