O que eu preciso saber para subir um Cluster Docker Swarm

Standard

Introdução

Antes de mais nada, docker swarm é um gerenciador e orquestrador de cluster Docker. É a possibilidade que você tem de ter vários Docker engines atuando juntos para servir os contêineres com alta disponibilidade e escalabilidade.

Um dos objetivos do Docker Swarm é ser simples, como o ecossistema Docker em geral!
Podemos concluir que Swarm é um conjunto de Docker Engines, usados para implantar serviços em larga escala e de forma profissional. Dessa forma é possível fazer balanceamento de carga, descoberta automática de novos serviços, escalar o ambiente em momento de alta demanda e resolver automaticamente caso de falhas em serviços em contêineres.

Quando você executa um Docker no modo “tradicional” você inicia contêineres com o comando docker container run, porém usando Swarm você passará a executar serviços, que na verdade são abstração de contêineres no ambiente de cluster.

Passamos a usar o termo diferente, pois dentro de um service podem conter mais de um contêineres espalhados (ou não) entre os nós desse cluster. A idéia aqui é abstrair a localização e quantidade de contêineres. Se você ficar preocupado demais onde eles estão e quantos são, talvez seja um indício que esteja utilizando a tecnologia de forma errada ou ela não encaixa na sua necessidade.

Como instalar o Docker Swarm?

A grande vantagem do Swarm é que, a partir da versão 1.12, ele já está contido no Docker engine, ou seja, não precisa fazer nada para instalar o Swarm, basta iniciá-lo, algo que faremos posteriormente, ainda neste capítulo.

Em caso de falha no nó, o que acontece com os contêineres?

O Docker Swarm é um cluster bem inteligente e trabalha no modelo de conciliação de estado desejado, ou seja, você precisa solicitar o serviço, informar qual a imagem docker a ser utilizada, especificar quantas réplicas ele deve ter e outras opções adicionais, tal como porta, volumes e afins.

Uma vez informado a imagem e número de réplicas, será registrado no cluster o estado desejado desse serviço, e assim todo o cluster trabalhará conjuntamente para manter o que foi solicitado.

A conciliação do estado desejado se dá iniciando novos contêineres em nós saudáveis, a fim de manter o número esperado de réplicas.

Segue abaixo um exemplo para deixar mais claro esse processo:

Vale salientar que o nó que apresentou problemas não será tratado automaticamente pelo Docker Swarm, pois isso está em outro nível da infraestrutura e o Swarm não se propõe a trabalhar nessa camada.

Como funciona a comunicação entre diferentes nós do cluster?

Você pode criar uma rede do tipo overlay que já está automaticamente disponível no cluster Swarm. Uma vez utilizada essa rede, o contêiner receberá um endereço único que será acessível de qualquer contêiner, independente de qual nó do cluster ele esteja. Explicaremos um pouco mais dessa rede em capítulos posteriores.

Como é gerenciada a consistência do estado do cluster Swarm?

O Docker Swarm utiliza o algoritmo de consenso chamado Raft, que tem como um dos objetivo ser simples, ou seja, segue uma das premissas da Docker. Ele é responsável gerência de pela tolerância e distribuição das tarefas que impacta na performance que o cluster consegue atender.

O que é algoritmo de consenso?

Consenso é um problema fundamental relacionado a tolerância a falha em ambientes distribuídos, como é o caso de um cluster de hosts Docker, por exemplo.

Envolve múltiplos servidores acordando valores. Uma vez que eles decidem os valores, isso deve ser uma decisão final. Tipicamente o algoritmo de consenso viabiliza que o cluster continue funcionando mesmo que parte de seus dispositivos não esteja operacional, e se responsabiliza por replicar os estados das máquinas, uma abordagem comum em ambientes de tolerância a falha. Cada servidor tem seu estado e log. O estado da máquina é um componente que queremos que seja tolerável a falhas, como uma tabela de hash, por exemplo.

A ideia é que, para o cliente desse cluster, pareça que ele está interagindo com apenas uma máquina, que tem um estado consistente, mesmo que nesse cluster alguns de seus nós apresentem problemas de disponibilidade.

Em nosso exemplo da tabela de hash, o log pode incluir comandos do tipo aplique x para 3, e assim o algoritmo de consenso será usado para acordar esse mesmo comando em outros servidores, ou seja, a ideia é que após o acordo entre os nós o resultado desse comando seja único para todos os nós e que o resultado para o cliente do cluster seja consistente.

Por que a Docker escolheu o RAFT?

O objetivo é que o Docker Swarm garanta que todos os nós do tipo manager estejam focados em gerenciar e agendar tarefas no cluster e sempre armazenando o mesmo estado, com consistência.

A Docker preza pela simplicidade e eficácia dos seu ecossistema e como o RAFT tem a premissa de ser também simples, esse casamento foi possível.

No contexto do cluster Docker, como funciona o RAFT?

Manter consistência entre os membros do cluster significa que em caso de falha de um dos nós do tipo manager, um outro possa assumir suas tarefas e restaurar os serviços para um estado estável. Por exemplo, se um manager líder que é responsável por agendar todas as tarefas no cluster deixa de funcionar inesperadamente, qualquer outro manager do cluster poderá assumir a tarefa de agendar e balanceará novamente as tarefas para atender um estado desejado, ou seja, como tem menos um nó no cluster é possível que alguns containeres precisem ser realocados para que a carga não fique pesada para apenas um dos membros do cluster.

Quando falamos de tolerância a falha, qual o limite?

Raft tolera até (N-1)/2 falhas e requer um quorum de (N/2)+1 membros para acordar um valor proposto no cluster. Isso quer dizer que em um cluster com 5 managers rodando Raft, se 3 desses nós ficarem indisponíveis, o sistema não irá processar mais nenhuma requisição de agendamento de tarefas. As tarefas existentes continuaram executando, mas o agendador não estará disponível para novas, nem mesmo se recuperar de falhas com balanceamento de serviços de containers por exemplo.

Criando o cluster

Desde a versão 1.12, cada instalação do docker tem em seu interior a funcionalidade de se transformar em Swarm, ou seja, se o cluster não existir, qualquer instalação convencional do docker pode iniciar um cluster com apenas um comando:

docker swarm init --advertise-addr 192.168.99.121

Obs: O valor de advertise-addr precisa ser o ip da interface usada para comunicação entre os nós do cluster.

A resposta para esse comando será bem explicativo, mas a parte mais importante é a sugestão de comando que ele exibirá para que você possa copiar e colar nos próximos nós de Swarm que você venha a adicionar nesse cluster. Nesse comando já está incluso o token de acesso para o cluster.

Esse token de acesso garante a segurança do auto-registro dos nós no cluster. Segue abaixo um exemplo de comando exibido como saída do inicio do cluster:

docker swarm join \
--token SWMTKN-1-3pu6hszjas19xyp7ghgosyx9k8atbfcr8p2is99znpy26u2lkl-1awxwuwd3z9j1z3puu7rcgdbx \
172.17.0.2:2377

Nesse caso o comando “docker swarm join” e seus parâmetros, devem ser executados em outro nó, que nesse assumiria o papel de worker. Explicaremos mais a frente a diferença entre esses dois papéis.

Se desejar adicionar um novo manager, ao invés de um worker, você deve obter o token de join correspondente utilizando esse comando abaixo em um dos managers do seu cluster:

docker swarm join-token manager

Qual a diferença entre nó worker e manager

Um nó é uma instância de um Docker engine participante de um cluster swarm. Você pode rodar mais de um nó em uma mesma máquina, com ajuda de virtualização de máquina, por exemplo.

Quando você inicia um serviço de container no cluster swarm, você submete uma definição de serviço para um nó manager, esse membro especial dispara unidades de trabalho chamada “tasks” normalmente para os nós do tipo worker. Eu falo normalmente, porque a depender da carga do cluster nós do tipo manager também podem ser responsáveis por executar “tasks” de container.

Os managers são responsáveis também pela orquestração e gerenciamento do cluster, que tem como objetivo manter o estado desejado do swarm, como já foi explicado anteriormente. Caso exista mais do que um, eles elegem o líder manager que conduzirá as orquestração das tarefas.

Quantos managers eu devo iniciar?

Tudo depende do tamanho da sua infraestrutura e do grau de alta-disponibilidade você deseja atender, pois vale lembrar que a conta de tolerância a falha é simples “(N-1)/2 managers” ou seja:

Três managers toleram no máximo a perda de um dos managers e cinco managers toleram a perda de no máximo dois nós do tipo managers.

Vale salientar que a adição de mais nós do tipo manager não aumentam a escalabilidade e performance do cluster, na verdade isso pode ser oposto. Sendo assim a Docker sugere que você não ultrapasse o número de sete nós do tipo manager no mesmo cluster swarm.

Iniciar contêiner ou serviço?

Como estamos falando de um ambiente de cluster, ao efetuar um deploy de uma aplicação não necessariamente será apenas um contêiner a ser iniciado, sendo assim o swarm apresenta o seu conceito de service.

Um service é uma definição de tarefas a serem executadas pelos nós do tipo workers. Essa é forma como o swarm organiza as aplicações implantadas no seu cluster. A interação dos usuários se dá dessa forma.

Quando você cria um serviço, você deve especificar a imagem a ser usada e quais outras opções o seu service precisa para iniciar normalmente (portas expostas, redes, réplicas e afins).

Em um modelo de serviço replicado, o swarm gerencia números específicos de réplicas ao longo dos nós, baseado no número de réplicas informada no início do service.

É possível especificar que o serviço em questão é do tipo “global” e assim o swarm inicia um contêiner desse serviço em cada nós disponível no cluster. Ele é muito usado para contêineres operacionais de gerência, como monitoramento e ferramenta de logs, por exemplo.
Como funciona a comunicação em containers de nós diferentes do cluster?

Swarm nativamente suporta redes do tipo overlay, resumidamente podemos dizer que essa é a rede que possibilita a comunicação de contêineres em nós diferentes no cluster.

Você não precisará de nenhuma configuração adicional para criar redes do tipo overlay, ou seja, nada de dependência de instalar serviço de chave-valor ou afins, pois o swarm já inclui nativamente esse serviço.

As funcionalidades de uma rede overlay no swarm são:

Você pode anexar vários serviços de contêineres na mesma rede
Por padrão, o serviço de descoberta interno do swarm entrega um endereço IP (VIP) e uma entrada DNS (também por um serviço interno) para cada contêiner na mesma rede.
Você pode configurar que o serviço use DNS round-robin ao invés de VIP.
Para utilizar redes overlay no seu cluster, garanta que os nós do swarm podem se comunicar nas seguintes portas:

Port 7946 TCP/UDP para descoberta de rede de contêiner.
Port 4789 UDP para rede overlay de contêiner.

Criando uma rede overlay no Swarm:

A partir de um manager execute os seguintes comandos para criar uma rede overlay com o nome minha-rede:

docker network create \
 --driver overlay \
 --subnet 10.0.9.0/24 \
 --opt encrypted \
 minha-rede

No comando acima podemos ver que será criada uma rede, com o driver overlay, que a sub-rede a ser entregue nessa rede overlay será 10.0.9.0/24. Vale salientar que o que o docker swarm chama de rede é uma abstração da rede convencional, que opera nas camadas TCP/IP e trafega dados em meios como cabo de rede, fibra e ondas eletromagnéticas (WiFI).

Toda vez que falarmos de redes docker swarm, seja overlay ou qualquer outro tipo, ela tem o mesmo objetivo que é interligar serviços, mas nesse caso estamos em um nível superior na hierarquia de abstração.

Por padrão toda comunicação entre nós do swarm é criptografada, mas a opção “–opt” desse exemplo especifica que uma nova camada de criptografia seja aplicada nessa conexão dessa rede.

Você pode checar se a rede foi criada com sucesso com o comando abaixo:

docker network ls

Verifique no resultado se a rede solicitada foi criada no escopo “swarm”, pois ele indica que a rede está disponível para ser usada nos serviços de contêiner iniciados no cluster swarm. Depois de criar o serviço de contêiner anexado à rede, o swarm apenas adiciona a rede em questão para nós do tipo workers que tiverem serviços de contêineres relacionados a essa rede, ou seja, workers que não tenha contêineres com essa rede anexa, o comando “docker network ls” não mostrará em sua lista a rede recém criada.

Iniciando um serviço de contêiner com rede overlay

Para iniciar um serviço anexado a uma rede overlay é bastante simples, basta passar o parâmetro “network” quando criar o serviço. Por exemplo, para criar um serviço nginx anexado a rede chamada “minha-rede” execute o seguinte comando:

docker service create \
--replicas 3 \
--name minha-web \
--network minha-rede \
nginx

Obs: Lembre-se que a rede “minha-rede” precisa estar criada nesse cluster e que o comando informado acima deve ser executado a partir de um manager.

Vale lembrar que os serviços podem ser anexados em qualquer rede criada em qualquer nó do tipo manager, pois como já foi dito antes, essas redes são propagadas pelo cluster.

A partir do manager execute o comando abaixo verificar qual nó está executando o serviço em questão “minha-web”:

docker service ps minha-web

Segue abaixo um desenho de como ficaria esse ambiente funcionando com 3 réplicas do serviço de nginx:

Como eu configuro um serviço para se comunicar com outro dentro da minha aplicação?

Como falamos anteriormente, cada serviço recebe um nome próprio e cada contêiner das réplicas recebe um endereço IP específico, ou seja, no exemplo acima quando eu já estiver com um serviço chamado “minha-web” rodando no cluster e iniciar um novo chamado “minha-api” e a partir desse serviço eu precisar conectar no primeiro, basta eu usar o hostname “minha-web”, dessa forma o balanceador se encarregará de responder com o endereço IP de uma das réplicas do serviço “minha-web”.

É importante salientar que não precisa expor nenhuma porta para o serviço em específico para possibilitar a comunicação dentro da mesma rede overlay.

Para saber todos os endereços IPs do hostname do service, basta dentro do contêiner requisitar a tradução do nome “tasks.<nome do serviço>”. No exemplo da comunicação entre “minha-api” e “minha-web” o comando poderia ser:

nslookup tasks.minha-web

Fontes

https://docs.docker.com/engine/swarm/
https://raft.github.io/
https://docs.docker.com/engine/swarm/networkingy

  • Aloisio Bilck

    Boa tarde,
    Parabéns!!! Muito legal o artigo, me ajudou a esclarecer alguns duvidas. Fica uma dica/sugestão, o material abranger de como funcionaria o swarm com ambiente externo, de como disponibilizar acesso externo das suas aplicações.
    Em diversos tutoriais, documentações e videos no youtube, nenhum explica ou descreve como funciona o swarm na parte externa. De como funciona a “entrega” do “serviço” para a Internet.

    Grato.

    • Rafael Gomes

      Obrigado pelo retorno! Vou adicionar esse texto também! Estou trabalhando nele já!

      • Aloisio Bilck

        Obrigado.

  • Parabéns, ótimo conteúdo, ficou bem mais claro o funcionamento do Swarm para mim.

  • Jonas Fernandes

    Vi varios materiais, em inglês e em portugues.
    Preciso migrar um ambiente de Docker engine comum para um ambiente clusterizado com o Swarm, e vi me deu a segurança necessária de que dará certo.
    Seu artigo foi o mais completo, simples de entender e técnico que vi até agora.
    Tenho muito o que agradecer;

  • Luiz Henrique Priotto

    Excelente artigo!
    Estou utilizando o plugin vSphere Docker Volume Service, devido a isso gostaria de saber se há como, por exemplo, manter um conteiner de mysql ativo e somente se este apresentar problema ele subir uma replica?

    Estou tentando fazer isso via compose mas estou com uma puta dificuldade. Obrigado!