Docker Swarm: Exemplo de Utilização

Fizemos uma mesa redonda no Opensanca para discutir as soluções de orquestração de containers. Na ocasião levei um exemplo extremamente simples de setup do Docker Swarm, que disponibilizo aqui.

O Swarm é a ferramenta nativa de orquestração do docker. Ela permite que containers executem distribuídos em em um cluster, controlando a quantidade de containers, registro, deploy e update de serviços.

Neste nosso exemplo vamos executar um servidor de aplicação NGINX com uma aplicação PHP. Para isso teremos um serviço do NGINX (feita a partir da imagem base do NGINX com pouquíssima customização), nosso servidor de aplicação, que recebe os requests HTTPs e envia para o serviço do PHP-FPM (construído com base na imagem do PHP-FPM do phpdocker.io), responsável pela execução do código do exemplo.

Antes de tudo, é necessário criar o cluster de máquinas. Neste exemplo, vamos utilizar duas VMs rodando Ubuntu Server 16LTS. Ambas as máquinas devem estar na mesma rede e com acesso à internet — para conseguir baixar as imagens — , o docker deve estar instalado e o usuário deve ter permissão para executar comandos do docker.

Com as máquinas instanciadas configuradas e com o docker instalado prosseguimos pro Swarm. Um cluster Swarm é gerenciado pelos managers e o cluster deve ter pelo menos um manager. Portanto, vamos executar o seguinte comando na máquina de desejamos que seja o manager:

$ docker swarm init

O resultado deve ser algo parecido com:

Basta agora executar o comando de join na segunda máquina para criar o cluster:

$ docker swarm join — token [TOKEN DA MENSAGEM DE INIT] [IP DO MANAGER]:2377

A partir deste comando, nosso cluster foi criado e todos os containers que forem instanciados serão distribuídos entre as nossas máquinas do cluster.

Criação dos serviços

Um serviço é uma abstração dos conjunto de containers que foram instanciados a partir de uma imagem e tem uma função única.

O serviço do NGINX irá expor a porta 9080 que será utilizada para os teste. Essa porta será mapeada para a porta 80 de cada container do serviço. Ao receber requisições, o NGINX irá chamar o serviço do PHP-FPM na porta 9000. Este serviço do PHP-FPM ira executar um código php que mostra o ip do container PHP-FPM que está recebendo a requisição.

O passo a passo para uma requisição é o seguinte:

  1. A máquina host recebe requisição na porta 8090
  2. A requisição é enviada para um container do serviço NGINX na porta 80
  3. O servidor de aplicação, através de sua configuração, requisita ao serviço PHP-FPM, na porta 9000 que execute o código index.php
  4. Um container do serviço PHP-FPM recebe a requisição na porta 9000, executa o arquivo index.php.
  5. O arquivo index obtém o IP do container do serviço PHP-FPM onde está executando e retorna este valor por toda a cadeia até que o resultado seja apresentado na tela.

Comunicação entre serviços

Para garantir a comunicação, criaremos uma rede no docker que será utilizada pelos serviços. Vamos criar uma rede com o nome opensanca:

$ docker network create -d overlay opensanca

Vamos então à criação destes serviços, lembre-se que comandos devem ser executados no manager.

Serviço NGINX

$ docker service create -p 9080:80 — name nginx — network opensanca rafapg/nginx:meetup

Este comando tem a seguinte estrutura:

  1. docker service create: informa ao docker que vamos criar um serviço
  2. -p 9080:80: informa que as requisições recebidas na porta 9080 da máquina serão redirecionadas para a porta 80 dos containers deste serviço
  3. -name nginx: configura o nome do serviço no cluster
  4. -nework opensanca: coloca nosso serviço na rede opensanca, que criamos anteriormente
  5. rafapg/nginx:meetup: é a imagem que vamos utilizar como base no nosso serviço.

PHP-FPM

$ docker service create — name php-fpm — network opensanca rafapg/php-fpm:meetup

Este comando tem a seguinte estrutura:

  1. docker service create: informa ao docker que vamos criar um serviço
  2. -name php-fpm: configura o nome do serviço no cluster — é o “endereço” que o nginx vai usar para acessar o php-fpm
  3. -nework opensanca: coloca nosso serviço na rede opensanca, para comunicação com o serviço do nginx
  4. rafapg/nginx:meetup: é a imagem que vamos utilizar como base neste serviço

Após a criação dos serviços, podemos verificar o status destes pelo comando:

$ docker service ls

O comando deverá retornar os serviços em execução e quantas réplicas de cada serviço está executando no cluster.

Se fizermos uma requisição para o nginx, o retorno será o IP do container do PHP-FPM que está processando a requisição:

$ curl 127.0.0.1:9080

Como só temos uma réplica de cada serviço, mesmo que executemos múltiplas vezes esse comando, o retorno será o mesmo IP.

Escalando um Serviço

Para efeito de teste, vamos escalar o serviço do PHP-FPM

$ docker service scale php-fpm=10

Este comando altera para 10 replicas do container php-fpm distribuídos no cluster. Para ver onde está executando cada uma das réplicas, basta executar o comando docker ps em cada uma das máquinas.

Ao executar novamente o comando abaixo, cada uma das requisições irá retornar o ip de cada uma das 10 réplicas do php-fpm.

$ curl 127.0.0.1:9080

So what?

Com este pequeno overview, é possível imaginar a capacidade do Docker do Swarm de orquestrar de containers em um cluster. Além disso, é uma capacidade nativa do Docker, o que a torna ainda melhor.

O Swarm provê muito mais do que gerenciamento dos serviços e capacidade de escalar containers, como a implantação de update, health check, constraints, gerenciamento de senhas ('secrets'). Por esses e outros motivos é um tópico que vale a pena ser estudado.