Docker: Orquestração de containers com o Docker Swarm
Visão geral da orquestração de contêiner
Quando executamos contêineres em produção temos que nos preocupar como:
- schedular os serviços em nós distribuídos,
- alta disponibilidade,
- implementar a reconciliação,
- o dimensionamento do ambiente
- o registro em log.
Neste artigo, vou a ferramenta de orquestração que vem incorporada ao Docker Engine, o Docker Swarm, para resolver alguns desses problemas.
Pontos importantes:
- manager = gerencia os nodes e containers
- workers = onde os containers são executados
Este exemplo consiste em um node manager e dois nodes workers. Os managers manipulam comandos e gerenciam o estado do swarm. Os workers não podem manipular comandos e são simplesmente usados para executar contêineres em escala. Por padrão, os managers também são usados para executar contêineres.
Passos
Crie seu primeiro swarm
Para facilitar o entendimento vou usar o https://labs.play-with-docker.com, faça o Login/Sign.
Vou criar 1 node de manager e 2 de workers.
Clique 3 vezes no botão +Add Instance, para criar 3 nodes.
Criando o Manager no Node1
docker swarm init --advertise-addr eth0
Resultado:
Swarm initialized: current node (zn2ljc47iah166z7mbjmx4o1h) is now a manager. To add a worker to this swarm, run the following command: docker swarm join --token SWMTKN-1-60gbmmu7ec4h1...ia451aepqz 192.168.0.38:2377 To add a manager to this swarm, run 'docker swarm join-token manager' and follow the instructions.
Criando o Worker no Node2
docker swarm join --token SWMTKN-1-60gbmmu7ec4h1...ia451aepqz 192.168.0.38:2377
Resultado:
This node joined a swarm as a worker.
Criando o Worker no Node3
docker swarm join --token SWMTKN-1-60gbmmu7ec4h1...ia451aepqz 192.168.0.38:2377
Listando os Nodes
Executar no node1
docker node ls
Resultado:
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION zn2ljc47iah166z7mbjmx4o1h * node1 Ready Active Leader 18.03.1-ce lchy7h37gybh01uaoifcf2tk1 node2 Ready Active 18.03.1-ce6dfxgdw04f t40kelfin697kdjf96lh4n0f2 node3 Ready Active 18.03.1-ceeoektffd94
Implante seu primeiro serviço
Criando o primeiro serviço
Executar no node1
docker service create -d true --name nginx1 --p 80:80 --mount source=/etc/hostname,target=/usr/share/nginx/html/index.html,type=bind,ro nginx:1.12
Este comando é declarativo. o Docker Swarm tentará manter o estado declarado neste comando, a menos que seja explicitamente alterado por outro comando de service do docker. Esse comportamento é útil quando os nodes ficam inativos, por exemplo, e os contêineres são reprogramados automaticamente em outros nodes.
Listando os serviços
docker service ls
Resultado:
ID NAME MODE REPLICAS IMAGE PORTS c87phpl7nerz competent_mccarthy replicated 0/1 true:latest 5s2z3gq9107b nginx1 replicated 1/1 nginx:1.12 *:80->80/tcp jua95ifymrdz trusting_morse replicated 0/1 true:latest
Este comando lista os 3 nodes do swarm. O asterisco (*) ao lado do ID do node representa o node que manipulou esse comando específico (docker node é neste caso).
docker service ps nginx1
Resultado:
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS g4ozhxmyokf5 nginx1.1 nginx:1.12 node1 Running Running 5 minutes ago 8if9h0qg4sew \_ nginx1.1 nginx:1.12 node1 Shutdown Complete 5 minutes ago
Testando o nginx rodando no container
Execute o comando:
curl localhost:80
o resultado será o hostname do node onde o container está sendo executado:
node1
Escale seu serviço
Executar no node1
docker service update --replicas=5 --detach=true nginx1
docker service ls
Resultado:
ID NAME MODE REPLICAS IMAGE PORTS c87phpl7nerz competent_mccarthy replicated 0/1 true:latest 5s2z3gq9107b nginx1 replicated 5/5 nginx:1.12 *:80->80/tcp jua95ifymrdz trusting_morse replicated 0/1 true:latest
docker service ps nginx1
Resultado:
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS g4ozhxmyokf5 nginx1.1 nginx:1.12 node1 Running Running 8 minutes ago 8if9h0qg4sew \_ nginx1.1 nginx:1.12 node1 Shutdown Complete 8 minutes ago z5e1fa63xrpn nginx1.2 nginx:1.12 node3 Running Running 46 seconds ago zfhy7ba46s5s nginx1.3 nginx:1.12 node2 Running Running 46 seconds ago 13woxf1kdyre nginx1.4 nginx:1.12 node2 Running Running 46 seconds ago pn4r3txv1xyk nginx1.5 nginx:1.12 node1 Running Running 51 seconds ago
Testando o nginx rodando no container
$ curl localhost:80 node3 $ curl localhost:80 node2 $ curl localhost:80 node2 $ curl localhost:80 node1
Verificando os logs
docker service logs nginx1
Resultado:
nginx1.5.pn4r3txv1xyk@node1 | 10.255.0.2 - - [26/Sep/2018:13:37:10 +0000] "GET / HTTP/1.1" 200 6 "-" "curl/7.60.0" "-" nginx1.1.g4ozhxmyokf5@node1 | 10.255.0.2 - - [26/Sep/2018:13:33:39 +0000] "GET / HTTP/1.1" 200 6 "-" "curl/7.60.0" "-" nginx1.2.z5e1fa63xrpn@node3 | 10.255.0.2 - - [26/Sep/2018:13:36:17 +0000] "GET / HTTP/1.1" 200 6 "-" "curl/7.60.0" "-" nginx1.2.z5e1fa63xrpn@node3 | 10.255.0.3 - - [26/Sep/2018:13:36:23 +0000] "GET / HTTP/1.1" 200 6 "-" "curl/7.60.0" "-" nginx1.4.13woxf1kdyre@node2 | 10.255.0.4 - - [26/Sep/2018:13:36:27 +0000] "GET / HTTP/1.1" 200 6 "-" "curl/7.60.0" "-" nginx1.3.zfhy7ba46s5s@node2 | 10.255.0.2 - - [26/Sep/2018:13:37:07 +0000] "GET / HTTP/1.1" 200 6 "-" "curl/7.60.0" "-" nginx1.4.13woxf1kdyre@node2 | 10.255.0.2 - - [26/Sep/2018:13:37:06 +0000] "GET / HTTP/1.1" 200 6 "-" "curl/7.60.0" "-"
Aplicar atualizações contínuas
Atualizando a imagem
Execute o comando docker service update para atualizar:
docker service update --image nginx:1.15 --detach=true nginx1
Conferindo a nova versão
docker service ls
Resultado
ID NAME MODE REPLICAS IMAGE PORTS c87phpl7nerz competent_mccarthy replicated 0/1 true:latest 5s2z3gq9107b nginx1 replicated 5/5 nginx:1.15 *:80->80/tcp jua95ifymrdz trusting_morse replicated 0/1 true:latest
Conferindo o CI/CD
docker service ps nginx1
Resultado
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS y25kvki5ezwc nginx1.1 nginx:1.15 node1 Running Running 26 seconds ago g4ozhxmyokf5 \_ nginx1.1 nginx:1.12 node1 Shutdown Shutdown 27 seconds ago 8if9h0qg4sew \_ nginx1.1 nginx:1.12 node1 Shutdown Complete 14 minutes ago 4pkmx4lgb38g nginx1.2 nginx:1.15 node3 Running Running 43 seconds ago z5e1fa63xrpn \_ nginx1.2 nginx:1.12 node3 Shutdown Shutdown 44 seconds ago iql3yqt48d1t nginx1.3 nginx:1.15 node2 Running Running 37 seconds ago zfhy7ba46s5s \_ nginx1.3 nginx:1.12 node2 Shutdown Shutdown 38 seconds ago evvv399ctrwe nginx1.4 nginx:1.15 node2 Running Running 32 seconds ago 13woxf1kdyre \_ nginx1.4 nginx:1.12 node2 Shutdown Shutdown 33 seconds ago lo83blt7nwzi nginx1.5 nginx:1.15 node1 Running Running 48 seconds ago pn4r3txv1xyk \_ nginx1.5 nginx:1.12 node1 Shutdown Shutdown 50 seconds ago
Reconciliar problemas com contêineres
Criando um novo serviço
docker service create -d true --name nginx2 --replicas=5 -p 81:80 --mount source=/etc/hostname,target=/usr/share/ngin/html/index.html,type=bind,ro nginx:1.15
Parando o node 3
Execute no node 3
docker swarm leave
O modelo inspect-and-then-adapt do Docker Swarm permite que ele realize a reconciliação quando algo dá errado. Por exemplo, quando um node no swarm fica inativo, ele pode derrubar contêineres em execução com ele. O swarn reconhecerá essa perda de contêineres e tentará reagendar contêineres em nodes disponíveis para atingir o estado desejado para esse serviço.
Conferindo
docker service ps nginx2 2018-09-26 13:50:03
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS u35jqe96mk70 nginx2.1 nginx:1.15 node1 Running Running about a minute ago uy7f7jith900 nginx2.2 nginx:1.15 node1 Running Running 51 seconds ago p159o9shlcka \_ nginx2.2 nginx:1.15 node3 Shutdown Running about a minute ago o7mqlv07bxu0 nginx2.3 nginx:1.15 node2 Running Running about a minute ago 6bn2i25sjkml nginx2.4 nginx:1.15 node1 Running Running 51 seconds ago xp69u9362xtl \_ nginx2.4 nginx:1.15 node3 Shutdown Running about a minute ago axm3bt4f1fd0 nginx2.5 nginx:1.15 node2 Running Running about a minute ago
Dica: Acompanhe usando o comando watch do linux
watch -n 1 docker service ps nginx2
Determine quantos nós você precisa
Nosso cluster Docker Swarm consiste em 1 manager e 2 workers. Esta configuração não tem altamente disponibilidade. O node manager contém as informações necessárias para gerenciar o cluster, mas se esse node ficar inativo, o cluster deixará de funcionar. Para um aplicativo de produção, você deve provisionar um cluster com vários nodes manager para permitir falhas nestes.
Você deve ter entre 3 e 7 managers. Os managers implementam o algoritmo raft consensus algorithm, que requer que mais de 50% dos nodes concordem com o estado que está sendo armazenado para o cluster. Se você não conseguir mais de 50% de concordância, o swarm deixará de funcionar corretamente.
Siga a seguinte orientação para suportar failover de nodes:
- 3 manager toleram 1 falha de node manager.
- 5 manager toleram 2 falhas de node manager.
- 7 manager toleram 3 falhas de node manager.
Lembrando que quanto mais managers você tiver, mais é oneroso alcançar um consenso sobre o estado de um cluster.
Os workers podem escalar para os milhares de nodes. Os workers se comunicam através do protocolo gossip, que é otimizado para ter bom desempenho sob um monte de tráfego e um grande número de nós.
O Play-with-Docker possui templates que implementam vários nodes por clusters . Clique no ícone no canto superior esquerdo para ver os templates disponíveis.