Docker machine, Docker swarm, Docker service

O Docker Machine é uma ferramenta que permite instalar o Docker Engine em hosts virtuais, ou seja, com o Docker Machine é possível instalar Docker Hosts no VirtualBox, nos provedores de nuvem, AWS, Azure, Google Cloud, Digital Ocean e etc. Com o docker-machine, é possível iniciar, inspecionar, parar e reiniciar um host, gerenciando e atualizando seu Daemon Docker.

O Docker Swarm é uma ferramenta nativa do Docker que permite a criação de clusters de Docker, ou seja, podemos fazer com que diversos hosts de Docker estejam dentro do mesmo pool de recursos, facilitando assim o deploy de containers. É possível por exemplo criar um container sem necessariamente saber em qual host ele está.

Para usar o Docker Engine no modo swarm, é preciso ter instalado o Docker Engine v1.12.0 ou posterior, com a versão 1.12 o swarm já vem habilitado nativamente para a gerência do cluster de containers. Com essa CLI é possível criar o swarm, fazer deploy de serviços para aplicações e gerenciar o comportamento do swarm. Para uma versão antiga do Docker verifique: https://docs.docker.com/swarm/.

Com o Swarm é possível declarar para a aplicação tanto um serviço de frontend e um serviço backend, (vamos fazer um exemplo dessa aplicação no final do artigo) assim como podemos especificar diversas redes, também é possível escalonar quantas vezes forem necessárias determinados serviços (tarefas) no Docker Swarm o Host manager é responsável pelo gerenciamento de todo o cluster, atribuindo e fazendo o serviço de DNS e balanceamento de carga.

A CLI do Docker Swarm é composta por:

Commands:
  init        Initialize a swarm
  join        Join a swarm as a node and/or manager
  join-token  Manage join tokens
  leave       Leave the swarm
  unlock      Unlock swarm
  unlock-key  Manage the unlock key
  update      Update the swarm

Para esse artigo vou utilizar minha própria máquina como manager e mais duas outras máquinas no VirtualBox utilizando o docker-machine como provider. Para instalar o Docker-machine:

# curl -L https://github.com/docker/machine/releases/download/v0.12.0/docker-machine-`uname -s`-`uname -m` > /tmp/docker-machine && chmod +x /tmp/docker-machine && sudo cp /tmp/docker-machine /usr/local/bin/docker-machine

Vamos ao Docker Swarm, que será o nosso manager:

# docker swarm init
Swarm initialized: current node (hkp74a6gh058gfpt0n6zj4h0r) is now a manager.


To add a worker to this swarm, run the following command:

docker swarm join \
--token SWMTKN-1-3dnwb4neo8nymome1neo565a8akl465vb2ottult04c49nxjhn-0vtrvqg993au02s6tqgvfofi4 \
192.168.100.7:2377

To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.

Em caso de conflito é necessário especificar a interface na qual o Swarm será iniciado. Ex:

# docker swarm init --advertise-addr 192.168.100.7

Agora vamos criar dois workers utilizando o Docker machine:

# for i in 1 2;do docker-machine create --driver virtualbox worker-$i; done
Running pre-create checks...
Creating machine...
...
...
...
Checking connection to Docker...
Docker is up and running!
To see how to connect your Docker Client to the Docker Engine running on this virtual machine, run: docker-machine env worker-2

Após o termino desse procedimento o próprio Docker machine nos informa como gerenciar as máquinas:

# docker-machine env worker-2

O docker machine env mostra quais são as variáveis necessárias para realizar a conexão com o Docker Host que queremos através do Docker Machine:

# docker-machine env worker-1
export DOCKER_TLS_VERIFY="1"
export DOCKER_HOST="tcp://192.168.99.100:2376"
export DOCKER_CERT_PATH="/root/.docker/machine/machines/worker-1"
export DOCKER_MACHINE_NAME="worker-1"
# Run this command to configure your shell:
# eval $(docker-machine env worker-1)

Agora vamos adicionar os workers ao nosso cluster Swarm utilizando o output do docker swarm.

Mas primeiro vamos carregar as variáveis dos workers:

# eval $(docker-machine env worker-1)

E adicionamos ao cluster:

# docker swarm join \
> --token SWMTKN-1-3dnwb4neo8nymome1neo565a8akl465vb2ottult04c49nxjhn-0vtrvqg993au02s6tqgvfofi4 \
> 192.168.100.7:2377
This node joined a swarm as a worker.

E fazemos isso para o worker-2:

# eval $(docker-machine env worker-2)

Adicionando ao cluster:

# docker swarm join \
> --token SWMTKN-1-3dnwb4neo8nymome1neo565a8akl465vb2ottult04c49nxjhn-0vtrvqg993au02s6tqgvfofi4 \
> 192.168.100.7:2377
This node joined a swarm as a worker.

Em um outro terminal podemos verificar a estrutura do Docker Swarm:

# docker node ls
ID                          HOSTNAME STATUS AVAILABILITY MANAGER STATUS
4jebeo33pa5c5ewh1dotavu1j   worker-2 Ready  Active
hkp74a6gh058gfpt0n6zj4h0r * notebook Ready  Active       Leader
j04624y4zkxrcmtujwkwerure   worker-1 Ready  Active

Verificamos também que após a criação do cluster o Docker criou uma outra rede:

# docker network ls | grep swarm
tj35jsfhc2tyingressoverlayswarm

Agora vamos criar um serviço para o nosso cluster:

# docker service create --name web -p 8080:80 nginx
t8xe237acbtihnqw1fori75hf
Since --detach=false was not specified, tasks will be created in the background.
In a future release, --detach=false will become the default.

Neste exemplo estamos criando um serviço de nome web utilizando a imagem do Nginx fazendo o bind da porta do host 8080 para a porta 80 do container.

# docker service ls
ID            NAME	MODE        REPLICAS  IMAGE
t8xe237acbti  web       replicated  0/1       nginx:latest

Podemos verificar que ele não está replicado, que está rodando apenas no nosso manager:

# docker service ps web
ID           NAME  IMAGE        NODE     DESIRED STATE CURRENT STATE   ERROR PORTS
a8jatd89ngrd web.1 nginx:latest notebook Running       Running 35 seconds ago

Vamos replicar esse containers para o cluster:

# docker service scale web=3
web scaled to 3

Verificando a replicação para os nodes:

# docker service ps web
ID           NAME  IMAGE        NODE     DESIRED STATE CURRENT STATE   ERROR PORTS
a8jatd89ngrd web.1 nginx:latest notebook Running       Running 3 minutes ago
yp27jbmucrre web.2 nginx:latest worker-2 Running       Running 9 seconds ago
932rulsgkuvc web.3 nginx:latest worker-1 Running       Running 11 seconds ago

Replicação bem sucedida:

# docker service ls
ID           NAME MODE       REPLICAS IMAGE 
t8xe237acbti web  replicated 3/3      nginx:latest 

Neste momento temos um container de Nginx rodando em cada worker:

# docker node ls
ID                          HOSTNAME STATUS   AVAILABILITY MANAGER STATUS
4jebeo33pa5c5ewh1dotavu1j   worker-2 Running  Active
hkp74a6gh058gfpt0n6zj4h0r * notebook Running  Active       Leader
j04624y4zkxrcmtujwkwerure   worker-1 Running  Active

Para logar nos nodes:

# docker-machine ssh worker-1
## .
## ## ## ==
## ## ## ## ## ===
/"""""""""""""""""\___/ ===
~~~ {~~ ~~~~ ~~~ ~~~~ ~~~ ~ / ===- ~~~
\______ o __/
\ \ __/
\____\_______/
_ _ ____ _ _
| |__ ___ ___ | |_|___ \ __| | ___ ___| | _____ _ __
| '_ \ / _ \ / _ \| __| __) / _` |/ _ \ / __| |/ / _ \ '__|
| |_) | (_) | (_) | |_ / __/ (_| | (_) | (__| < __/ |
|_.__/ \___/ \___/ \__|_____\__,_|\___/ \___|_|\_\___|_|
Boot2Docker version 17.06.0-ce, build HEAD : 0672754 - Thu Jun 29 00:06:31 UTC 2017
Docker version 17.06.0-ce, build 02c1d87
docker@worker-1:~$

E verificamos nosso container:

docker@worker-1:~$ docker ps
CONTAINER ID    IMAGE   COMMAND     CREATED         STATUS          PORTS   NAMES
69a2944abbcb    nginx   "bash"      10 minutes ago  Up 10 minutes   80/tcp -> 0.0.0.0:8080  

Verficamos no nosso worker-2 também:

# docker-machine ssh worker-2
## .
## ## ## ==
## ## ## ## ## ===
/"""""""""""""""""\___/ ===
~~~ {~~ ~~~~ ~~~ ~~~~ ~~~ ~ / ===- ~~~
\______ o __/
\ \ __/
\____\_______/
_ _ ____ _ _
| |__ ___ ___ | |_|___ \ __| | ___ ___| | _____ _ __
| '_ \ / _ \ / _ \| __| __) / _` |/ _ \ / __| |/ / _ \ '__|
| |_) | (_) | (_) | |_ / __/ (_| | (_) | (__| < __/ |
|_.__/ \___/ \___/ \__|_____\__,_|\___/ \___|_|\_\___|_|
Boot2Docker version 17.06.0-ce, build HEAD : 0672754 - Thu Jun 29 00:06:31 UTC 2017
Docker version 17.06.0-ce, build 02c1d87

No outro node:

docker@worker-2:~$ docker ps
CONTAINER IDIMAGE   COMMAND    CREATED  STATUSPORTS  NAMES
4b8592400d8bnginx:latest   "nginx -g 'daemon ..."  11 minutes ago  Up 11 minutes80/tcp web.2.yp27jbmucrre1ls859q2t0plf 

Coisa lindaaa!! – Estamos com nosso cluster ativo e com os containers distribuídos em cada um dos nodes. Para retirar um node do cluster:

docker@worker-2:~$ docker swarm leave
Node left the swarm.

Verificamos:

 # docker node ls 
ID 			    HOSTNAME STATUS AVAILABILITY MANAGER STATUS
4jebeo33pa5c5ewh1dotavu1j   worker-2 Down   Active
hkp74a6gh058gfpt0n6zj4h0r * notebook Ready  Active       Leader
j04624y4zkxrcmtujwkwerure   worker-1 Ready  Active

Verificamos que seu status é Down, agora é só removermos:

# docker node rm worker-2
worker-2

Podemos verificar após a retirada do nó do cluster que o próprio Swarm já se encarregou da alta-disponibilidade, no passo anterior possuíamos um container em cada host, agora possuímos dois no manager e um no worker1:

# docker service ps web
ID               NAME   IMAGE           NODE       DESIRED STATE CURRENT STATE   ERROR PORTS
a8jatd89ngrd	 web.17	nginx:latest	notebook   Running       Running 17 minutes ago
mxuuslaluhyx	 web.2	nginx:latest	notebook   Running       Running about a minute ago
932rulsgkuvc	 web.3	nginx:latest	worker-1   Running       Running 14 minutes ago   

Referências:
http://www.mundodocker.com.br/docker-swarm/
http://tutoriaisgnulinux.com/2016/10/14/_docker-engine-v1-12-swarm/
https://www.youtube.com/watch?v=IYfSWOrSWRE&t=423s
https://docs.docker.com/engine/reference/commandline/service_create/#options
https://churropsondevops.tech/2017/07/02/docker-desvendando-docker-machine-swarm-com-virtualbox/

Docker machine, Docker swarm, Docker service
  • Amauri Antonio

    Ótimo artigo!