Configurando nosso Cluster
Na máquina chamada manager
, vamos executar o comando abaixo para inicializar o cluster do Docker Swarm. Ele define o IP exclusivo da interface de rede desta máquina como o endereço para comunicação no cluster. Embora o comando possa ser executado em qualquer Node Manager, é necessário inicializá-lo em apenas um deles.
docker swarm init --advertise-addr 192.168.145.10
Substitua
192.168.145.10
pelo IP da interface de rede da máquinamanager
. Esse endereço deve ser acessível pelas outras máquinas no cluster.
Para adicionar os Workers Nodes ao cluster, execute o seguinte comando em cada máquina Worker:
docker swarm join --token TOKEN 192.168.145.10:2377
Substitua
TOKEN
pelo token gerado no comandodocker swarm init
. Ele será exibido no terminal da máquinamanager
após a inicialização do Swarm.
Se você perder o token para adicionar novos Nodes ao cluster do Docker Swarm, não se preocupe, pois é possível recuperá-lo diretamente de qualquer máquina Manager já existente no cluster. Execute o comando a seguir em uma das máquinas Manager, ele exibirá o comando completo com o token necessário para adicionar Nodes Workers, como:
$ docker swarm join-token worker
To add a worker to this swarm, run the following command:
docker swarm join --token SWMTKN-1-4lq6mo3b5u04fu477d7p1iss5zues5gf01mdwv9r6ra8pntzce-5r5zjwqecf9vexjai13kzg3d1 192.168.145.10:2377
Para listar os nodes faça:
$ docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION
b6rexijhb5xqv4pbll90n52o9 * manager Ready Active Leader 27.4.1
u6r6ylph4ix0ymqarqqe2bf60 node1 Ready Active 27.4.1
8rbrwxobsyz4uwg7bffupmz26 node2 Ready Active 27.4.1
Adicinando mais Node Managers
Existem duas formas de adicionar mais um Manager ao cluster. O primeiro método é atraves do comando docker swarm join
contendo o token de Node Manager. Já o segundo método é adicionar o manager como um Worker Node e então promovê-lo manualmente para Node Manager usando o comando docker node promote
.
# Para obter o token de Manager faça:
vagrant@manager1:~$ docker swarm join-token manager
To add a manager to this swarm, run the following command:
docker swarm join --token SWMTKN-1-4acz5l1pkd5x184uski75dhdrcv7s9npmv1jpb5pauq2937jq5-64c6sw26muqswr29wnfxdzaz9 192.168.145.10:2377
Depois é só executar esse comando no novo Node Manager.
Agora vamos ver como fazer adicionando primeiro como um Worker Node e depois promovendo para Node Manager.
# Adicione o novo Manager como Worker:
vagrant@manager1:~$ docker swarm join --token SWMTKN-1-4acz5l1pkd5x184uski75dhdrcv7s9npmv1jpb5pauq2937jq5-47l2lwt3az64nq3txopxdb8km 192.168.145.10:2377
This node joined a swarm as a worker.
# Agora em qualquer Node Manager liste os nodes:
vagrant@manager1:~$ docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION
umggf1y1qg1d5eou7bu60cv22 * manager1 Ready Active Leader 27.4.1
rectb9t0b7xb2ggj2t0m0ea0p manager2 Ready Active 27.4.1
tfkcrj1y935pefg2vjhu70smv node1 Ready Active 27.4.1
mvv4ma3mxsgly7yqyqhx2jrlg node2 Ready Active 27.4.1
# Agora vamos promover o manager2 para ser um Node Manager:
vagrant@manager1:~$ docker node promote manager2
Node manager2 promoted to a manager in the swarm.
# Agora liste novamente os nodes:
vagrant@manager1:~$ docker node ls
ID HOSTNAME STATUS AVAILABILITY MANAGER STATUS ENGINE VERSION
umggf1y1qg1d5eou7bu60cv22 * manager1 Ready Active Leader 27.4.1
rectb9t0b7xb2ggj2t0m0ea0p manager2 Ready Active Reachable 27.4.1
tfkcrj1y935pefg2vjhu70smv node1 Ready Active 27.4.1
mvv4ma3mxsgly7yqyqhx2jrlg node2 Ready Active 27.4.1
Principais comandos para trabalhar com swarm
Abaixo segue uma tabela com os principais comandos.
Comando | Descrição |
---|---|
docker swarm init | Inicializa o Swarm no Node atual e o define como Manager. |
docker swarm join --token <token> <ip>:2377 | Adiciona um Node ao cluster (Worker ou Manager, dependendo do token usado). |
docker swarm join-token worker | Exibe o token necessário para adicionar Nodes como Workers no Swarm. |
docker swarm join-token manager | Exibe o token necessário para adicionar Nodes como Managers no Swarm. |
docker swarm leave | Remove o Node atual do Swarm. Se for um Manager, o quórum será ajustado automaticamente. É necessário executar o docker node rm <node-name> em algum Manager para remover completamente. |
docker node ls | Lista todos os Nodes do cluster, mostrando o status e função de cada um (Worker ou Manager). |
docker node promote <node-name> | Promove um Node Worker a Manager. |
docker node demote <node-name> | Rebaixa um Node Manager para Worker. |
docker node ps <node-name> | Mostra as terefas que estão em execução no node em questão. |
docker node update <node-name> | Modifica as propriedades de um Node. |
docker node rm <node-name> | Remove um Node do cluster (se ele já tiver saído (leave) ou estiver inativo). |
docker service create --name <name> <image> | Cria um novo serviço no cluster baseado na imagem especificada. |
docker service ls | Lista todos os serviços rodando no cluster. |
docker service ps <service-name> | Mostra as tarefas (tasks) de um serviço específico, incluindo onde estão sendo executadas. |
docker service scale <name>=<replicas> | Escala um serviço para o número especificado de réplicas. |
docker service update | Atualiza configurações de um serviço existente (imagem, réplicas, etc.). |
docker service rm <service-name> | Remove um serviço do cluster. |
docker stack deploy -c <file> <name> | Implanta uma pilha (stack) de serviços usando um arquivo YAML (Compose). |
docker stack ls | Lista todas as pilhas (stacks) gerenciadas no cluster. |
docker stack ps <stack-name> | Mostra as tarefas de uma pilha específica. |
docker stack rm <stack-name> | Remove uma pilha e todos os seus serviços associados. |
docker node update
Com esse comando nós podemos alterar a disponibilidade de um Node com o parâmetro --availability
, ele possui as seguintes opções:
active
: O Node está disponível para executar tarefas.drain
: O Node será esvaziado de tarefas ativas e não receberá novas.pause
: O Node não receberá novas tarefas, mas mantém as existentes.
# Mover um Node para manutenção:
docker node update --availability drain worker1
# Após a manutenção, reativá-lo:
docker node update --availability active worker1
Também podemos atualizar rótulos (Labels) de um Node. Os rótulos são úteis para atribuir metadados aos Nodes, permitindo que você crie regras de agendamento de tarefas com base em características específicas do Node. Vejamos um exemplo de como adicionar um rótulo role=db
ao Node worker1:
# Adicionar o rótulo:
docker node update --label-add role=db worker1
# Remover o rótulo:
docker node update --label-rm role worker1
Se o cluster possui Nodes com diferentes capacidades, você pode usar os rótulos para criar restrições ou ajustar manualmente como as tarefas são alocadas. Embora isso não configure diretamente os recursos, pode ser parte da estratégia para gerenciar workloads.
Criando serviços manualmente
No Docker Swarm, um service
é a unidade lógica que define como os contêineres devem ser executados dentro do cluster. O service
no Docker Swarm e no Docker Compose compartilha o mesmo conceito fundamental; ele define como um contêiner (ou conjunto de contêineres) deve ser configurado e executado. O que muda é o contexto de aplicação e algumas funcionalidades adicionais disponíveis no Docker Swarm. Como já comentamos um serviço deve especificar:
Imagem
Qual imagem Docker será utilizada para criar os contêineres.Replicas
Quantas instâncias do contêiner serão executadas (modo replicado) ou como serão distribuídas (modo global).Modo
É o modo de replicação dos containers, podemos definir de duas formas:- Replicado: Permite definir um número específico de réplicas para o serviço.
- Global: Garante que cada nó do cluster execute uma instância do serviço.
Configuração
Parâmetros como variáveis de ambiente, volumes, portas expostas, limites de recursos (CPU e memória) e redes.
Um exemplo básico de criação de um serviço seria:
# Crie os service:
$ docker service create -d --name web-server --replicas 3 -p 80:80 nginx:latest
mrvjd6p49b6t4fo5tel1bkw9j
# Liste os services:
$ docker service ls
ID NAME MODE REPLICAS IMAGE PORTS
mrvjd6p49b6t web-server replicated 3/3 nginx:latest *:80->80/tcp
# Veja quais nodes estão executando o serviço:
$ docker service ps web-server
ID NAME IMAGE NODE DESIRED STATE CURRENT STATE ERROR PORTS
d5ww6suxpmwz web-server.1 nginx:latest node1 Running Running 3 minutes ago
l26gl68iei4p web-server.2 nginx:latest node2 Running Running 3 minutes ago
3y2gig1odsfj web-server.3 nginx:latest manager1 Running Running 3 minutes ago
# Executando uma verificação de logs podemos ver o load balance:
$ docker service logs -f web-server
web-server.1.d5ww6suxpmwz@node1 | 10.0.0.2 - - [26/Dec/2024:13:17:18 +0000] "GET / HTTP/1.1" 200 615 "-" "curl/7.81.0" "-"
web-server.2.l26gl68iei4p@node2 | 10.0.0.2 - - [26/Dec/2024:13:17:18 +0000] "GET / HTTP/1.1" 200 615 "-" "curl/7.81.0" "-"
web-server.3.3y2gig1odsfj@manager1 | 10.0.0.2 - - [26/Dec/2024:13:17:19 +0000] "GET / HTTP/1.1" 200 615 "-" "curl/7.81.0" "-"
# Atualizar o número de réplicas com serviços em execução:
$ docker service update --replicas 2 web-server
Para acessar o serviço você pode usar o endereço IP de qualquer um dos Node Managers.
Alta Disponibilidade
Existem algumas formas da gente sempre acessar os serviços que estão sendo executados nos Managers, abaixo vou descrever algumas delas.
Load Balancer Externo (HAProxy ou NGINX)
Podemos configurar a alta disponibilidade usando um load balancer externo que distribui o tráfego para os Managers ativos. Para softwares Open Source podemos usar ferramentas como HAProxy ou NGINX, elas podem realizar o balanceamento e o failover automaticamente.
Essa abordagem é fácil de configurar e permite health checks para redirecionar tráfego apenas para Managers saudáveis. Você deve ficar ciente que essa abordagem introduz um ponto único de falha se o load balancer não for replicado.
Virtual IP (VIP) com Keepalived
O IP Virtual (VIP), é um endereço IP lógico que não está diretamente associado a uma interface de rede física. Em vez disso, ele é "flutuante" entre vários servidores, proporcionando alta disponibilidade e redundância. Já o Keepalived é um software que gerencia esses IPs virtuais, utilizando o protocolo VRRP (Virtual Router Redundancy Protocol). Ele permite que múltiplos servidores compartilhem um único endereço IP, garantindo que um serviço continue acessível mesmo que um dos servidores falhe.
A vantagem dessa abordagem é que ela não depende de roteamento dinâmico e possui alta disponibilidade automática com failover rápido. Já a desvantagens é na parte da configuração adicional do Keepalived e de não realizar balanceamento de carga, apenas failover.
DNS Round Robin
É possível fazer balanceamento de carga com DNS, para isso precisamos configurar um registro DNS que aponta para todos os IPs dos Managers. O cliente vai sempre usar o mesmo nome na resolução DNS e será o DNS quem vai resolver o nome para diferentes IPs, alternando entre eles.
A desvantagem dessa abordagem é que ela não lida bem com falhas, se um dos managers ficar inacessivel, o cliente pode ser direcionado para ele e não vai obter uma resposta.
Routing Mesh
O Routing Mesh (configuração padrão) é um recurso do Docker Swarm que permite que serviços em um cluster sejam acessados por qualquer node, independentemente de onde o container que executa o serviço esteja realmente rodando. Isso é possível porque o Swarm cria um plano de rede virtual, distribuindo o tráfego de entrada para o node correto. O Routing Mesh está diretamente ligado ao modo de operação VIP (Virtual IP) no Docker Swarm.
Quando você publica um serviço em um cluster Swarm com o modo de rede ingress
, o Routing Mesh intercepta as conexões no node de entrada e as redireciona para os containers que executam o serviço, mesmo que esses containers estejam em outros nodes. Ele utiliza um proxy de software em cada node, que faz esse redirecionamento.
Isso garante alta disponibilidade e simplifica o acesso ao serviço, já que qualquer node pode atuar como ponto de entrada. Internamente, ele usa a rede de sobreposição (overlay network) para rotear os pacotes entre os nodes. Porém, esse comportamento pode adicionar latência e, em alguns casos, não é ideal para cargas que exigem baixa latência ou roteamento direto.
DNSRR
O DNSRR (DNS Round Robin) é um modo de resolução de DNS nativo no Docker Swarm que fornece uma abordagem mais direta para a comunicação entre serviços, eliminando a necessidade do uso do Routing Mesh. Nesse modo, cada container de um serviço no Swarm é registrado no DNS com seu próprio IP, e as resoluções de DNS para o nome do serviço retornam uma lista de todos os IPs dos containers associados.
Quando um serviço no Swarm é configurado com --endpoint-mode dnsrr
, a resolução de DNS retorna os IPs reais dos containers, em vez de um VIP. Isso permite que as aplicações clientes se conectem diretamente aos containers. Diferente do modo VIP, onde o Swarm roteia o tráfego para os containers, no DNSRR o balanceamento é feito pelo cliente. O cliente escolhe qual IP usar para estabelecer a conexão, baseado na lista retornada pelo DNS.
O problema descrito na seção de Alta disponibilidade ainda acontece aqui, como o DNSRR não mantém uma conexão resiliente entre os nodes, se um container falhar, cabe ao cliente resolver novamente o nome do serviço para obter uma nova lista de IPs. Para usar o DNSRR em um serviço no Docker Swarm, você deve especificar o --endpoint-mode
durante a criação do serviço:
docker service create \
--name my-service \
--replicas 3 \
--endpoint-mode dnsrr \
--network my-network \
my-image
Subindo Cluster com Alta disponibilidade
Para demonstrar o uso do Docker Swarm, vamos criar um cluster integrado com HAProxy para garantir alta disponibilidade, abrangendo tanto os nodes managers quanto os workers. O Swarm será configurado para distribuir serviços em uma rede overlay, enquanto o HAProxy atuará como balanceador de carga, roteando o tráfego de forma eficiente para os nodes do cluster, assegurando a resiliência e a continuidade dos serviços. Essa abordagem combina a orquestração do Swarm com a robustez do HAProxy, otimizando a distribuição e o acesso às aplicações.
Criando nossa rede
Para começar, criaremos a rede manualmente, passo a passo, para entender seu funcionamento antes de automatizar o processo com o Docker Compose.
docker network create -d overlay --attachable ctos
Criando nosso serviço
Com nossa rede criada, vamos então criar nosso serviço usando DNSRR para que o HAProxy possa fazer o balanceamento de carga entre os containers. Para criar o serviço, use o comando abaixo:
docker service create \
--name nginx-ha \
--replicas 2 \
--endpoint-mode dnsrr \
--network ctos \
nginx:latest
HAProxy
Vamos configurar o HAProxy, e essa configuração precisa ser aplicada em todos os nodes do cluster. Isso é necessário porque o HAProxy atua como um ponto de entrada distribuído para o tráfego. Em um cluster Docker Swarm, qualquer node pode receber solicitações externas, e ter o HAProxy configurado em todos os nodes garante que o balanceamento de carga funcione independentemente de onde o tráfego entre no cluster. Essa abordagem aumenta a resiliência e previne pontos únicos de falha.
Abaixo deixo o arquivo de configuração do HAProxy.
# Crie o diretório abaixo:
$ sudo mkdir /etc/haproxy
Agora veja o conteúdo do arquivo:
global
log fd@2 local2 # Configura o log para ser enviado ao descritor de arquivo 2 (stderr), usando a facility local2.
chroot /var/lib/haproxy # Define o diretório raiz para execução do processo, melhorando a segurança.
pidfile /var/run/haproxy.pid # Especifica onde será salvo o arquivo PID do processo.
maxconn 4000 # Define o limite máximo de conexões simultâneas.
user haproxy # Especifica o usuário que executará o processo HAProxy.
group haproxy # Especifica o grupo que executará o processo HAProxy.
stats socket /var/lib/haproxy/stats expose-fd listeners # Cria um socket UNIX para coletar estatísticas e permite que listeners acessem.
master-worker # Ativa o modo master-worker, útil para reiniciar workers sem parar o processo master.
resolvers dns-docker
nameserver dns1 127.0.0.11:53 # Define o resolvedor DNS para usar o servidor DNS interno do Docker.
resolve_retries 3 # Número de tentativas de resolução de DNS em caso de falha.
timeout resolve 1s # Tempo limite para resolver um endereço DNS.
timeout retry 1s # Tempo de espera antes de tentar novamente uma resolução.
hold other 10s # Tempo para armazenar estados "outros" (indefinidos).
hold refused 10s # Tempo para armazenar estados "recusado".
hold nx 10s # Tempo para armazenar estados "não encontrado" (NXDOMAIN).
hold timeout 10s # Tempo para armazenar estados "timeout".
hold valid 10s # Tempo para armazenar resoluções válidas no cache.
hold obsolete 10s # Tempo para armazenar resoluções obsoletas no cache.
defaults
timeout connect 10s # Tempo limite para estabelecer uma conexão com o servidor.
timeout client 30s # Tempo limite para comunicação com o cliente.
timeout server 30s # Tempo limite para comunicação com o servidor backend.
log global # Usa a configuração de log definida na seção global.
mode http # Define o modo HTTP para os backends e frontends.
option httplog # Ativa o registro detalhado no formato HTTP.
frontend fe_web
bind *:80 # Faz o frontend escutar em todas as interfaces na porta 80.
use_backend stat if { path -i /stats } # Encaminha para o backend `stat` se o caminho for "/stats".
default_backend nginx-ha_service # Encaminha para o backend padrão `nginx-ha_service` em qualquer outro caso.
backend nginx-ha_service
balance roundrobin # Usa o algoritmo de balanceamento de carga round-robin.
server-template nginx- 20 nginx-ha:80 check resolvers dns-docker init-addr libc,none
backend stat
stats enable # Ativa as estatísticas para este backend.
stats uri /stats # Define o caminho "/stats" para acessar as estatísticas.
stats refresh 15s # Atualiza as estatísticas a cada 15 segundos.
stats show-legends # Mostra legendas no relatório de estatísticas.
stats show-node # Mostra o nome do node do HAProxy no relatório.
Dentro do backend nginx-ha_service
é onde a mágica vai acontecer, por isso, resolvi deixar uma explicação dos parâmetros usados fora do arquivo de configuração:
server-template nginx-
Define um modelo de nome para os servidores backend. O prefixonginx-
será usado para nomear dinamicamente os servidores descobertos, seguido de um número sequencial. Por exemplo, os servidores terão nomes comonginx-1
,nginx-2
, ..., até o limite especificado.20
Especifica o número máximo de servidores que podem ser criados dinamicamente a partir do modelo. Neste caso, até 20 servidores serão gerados com base na resolução de DNS do serviçonginx-ha
.nginx-ha:80
Define o endereço e a porta para os servidores backend. Aqui,nginx-ha
é o nome do serviço Docker que será resolvido dinamicamente usando DNS, e80
é a porta que será usada para acessar os containers correspondentes.check
Habilita verificações de saúde (health checks) nos servidores. O HAProxy verificará periodicamente se os servidores estão operacionais, e apenas os servidores saudáveis receberão tráfego.resolvers dns-docker
Especifica o resolvedor DNS que será usado para obter os IPs do serviço. Neste caso,dns-docker
é o resolvedor previamente configurado na seçãoresolvers
, apontando para o DNS interno do Docker.init-addr libc,none
Define o comportamento do HAProxy ao inicializar os endereços dos servidores:- libc: Usa o resolvedor de DNS padrão do sistema operacional para tentar resolver o nome inicialmente.
- none: Se a resolução falhar durante a inicialização, permite que o servidor comece sem um endereço válido. Isso é útil em ambientes onde os containers podem ser escalados dinamicamente após o HAProxy ser iniciado.
Agora vamos criar um container para ter o serviço do HAProxy.
docker service create \
--name haproxy-ha \
--replicas 1 \
--publish published=80,target=80,protocol=tcp,mode=ingress \
--publish published=443,target=443,protocol=tcp,mode=ingress \
--mount type=bind,src=/etc/haproxy/,dst=/etc/haproxy,ro=true \
--dns=127.0.0.11 \
--network ctos \
haproxytech/haproxy-debian:3.2
Impedindo que os Managers atuem como Workers
Para impedir que os managers em um cluster Docker Swarm executem containers de serviços, podemos alterar o comportamento padrão do Swarm, configurando os nodes managers para não agirem como worker node. Podemos fazer isso desativando o agendamento de tarefas neles. Execute o comando abaixo em cada node manager:
docker node update --availability drain <nome-do-node>
O parâmetro --availability drain
vai colocar o node em estado de drenagem, impedindo que novos containers sejam agendados nele e migrando os containers existentes para outros workers nodes restantes. Com isso o Swarm não agendará novos containers nesses Nodes. Após executar o comando, verifique o estado do node:
docker node inspect <nome-do-node> --format '{{ .Spec.Availability }}'
O resultado deve ser
drain
.
Uma alternativa é incluir a flag --availability drain
durante a criação do cluster. Essa flag já impede que os managers entrem no clsuter com a opção de atuarem como Worker.
docker swarm join --manager --availability drain --token <manager-token> <ip-manager>:2377
Rede Overlay com criptografia
No Docker Swarm, redes do tipo overlay podem ser configuradas para fornecer comunicação criptografada entre os nodes do cluster. Isso é útil para garantir a segurança dos dados transmitidos, especialmente em ambientes distribuídos ou com requisitos de compliance.
Use o comando abaixo para criar a rede com o parâmetro --opt encrypted
, que ativa a criptografia:
docker network create \
--driver overlay \
--opt encrypted \
--attachable \
my-network
A criptografia é baseada no protocolo IPSec. Todas as comunicações entre containers em diferentes nodes passam por túneis IPSec. A chave usada para a criptografia é gerenciada automaticamente pelo Docker Swarm, tornando o processo transparente. Para verificar que a rede foi criada corretamente com criptografia ativada, use o comando:
docker network inspect my-secure-network
# No campo 'Options', você verá a opção "encrypted": "true".
Stacks
No Docker Swarm, as stacks são uma abstração de alto nível usada para gerenciar um conjunto de serviços, redes e volumes como uma única unidade. Elas permitem que você defina toda a configuração de sua aplicação em um arquivo YAML, geralmente utilizando o formato do Docker Compose, e depois implante essa configuração diretamente no cluster Swarm.
Diferença Entre Serviços e Stacks
Os serviços são gerenciados com comandos individuais (docker service create
, docker service update
) e permitem configurar componentes de uma aplicação um por vez. Já as stacks gerenciam coleções de serviços, redes e volumes definidos em um arquivo Compose (docker-compose.yml
), simplificando a implantação de aplicações mais complexas.
Para usar stacks no Docker Swarm, precisamos do arquivo Compose em formato versão 3 ou superior, que suporta recursos específicos do Swarm. Abaixo podemos ver um exemplo de arquivo Compose para Swarm:
version: '3.9' # Versão mínima para suporte completo ao Swarm
services:
web:
image: nginx
ports:
- "80:80"
deploy:
replicas: 3
restart_policy:
condition: on-failure
update_config:
parallelism: 1
delay: 10s
networks:
- app-network
app:
image: my-app-image:latest
deploy:
replicas: 2
resources:
limits:
memory: 512M
reservations:
memory: 256M
networks:
- app-network
networks:
app-network:
driver: overlay
attachable: true
driver_opts:
encrypted: "true"
Certifique-se de já ter iniciado o Docker Swarm. Para implantar a stack com o arquivo Compose, faça:
docker stack deploy -c docker-compose.yml my-stack
A seção deploy
é específica do Swarm e permite configurar:
replicas
: Número de instâncias do serviço.update_config
: É usada para configurar como o Docker Swarm realiza atualizações de serviços dentro de uma stack. É essencial para controlar o comportamento de atualizações ao implantar novas versões de imagens ou alterar configurações de serviços.resources
: Limites e reservas de CPU/memória (também funciona no Docker Compose).
Os parâmetros de CLI usados foram:
-c docker-compose.yml
: Especifica o arquivo Compose.my-stack
: Nome da stack.
A opção update_config
possui várias subopções que podem ser usadas para controlar o comportamento das atualizações de serviços no Docker Swarm, como:
parallelism
Define quantas tarefas (containers) serão atualizadas simultaneamente (padrão: 1).delay
Define o tempo de espera entre a atualização de um grupo de containers e o próximo. Se você configurardelay: 10s
eparallelism: 2
, o Docker atualizará 2 containers, aguardará 10 segundos e então atualizará os próximos 2.order
Controla a ordem em que as tarefas são atualizadas. Os valores possíveis são:- start-first: Inicializa as novas tarefas antes de parar as antigas (pode causar consumo extra de recursos).
- stop-first: Para as tarefas antigas antes de iniciar as novas (modo padrão).
failure_action
Define o que acontece se uma atualização falhar. Os valores possíveis são:- pause: Interrompe o processo de atualização (padrão).
- rollback: Reverte automaticamente para a versão anterior do serviço.
- continue: Continua a atualização, ignorando as falhas.
Abaixo segue alguns comandos interessantes
# Verifique a Stack Implantada:
docker stack ls
# Listar Serviços de uma Stack:
docker stack services my-stack
# Listar Containers (Tasks) da Stack:
docker stack ps my-stack
# Remover uma Stack:
docker stack rm my-stack
Opções do deploy
Vou deixar um resumo das opções mais usadas no contexto de deployment e stack.
endpoint_mode
Especifica o método de exposição do endpoint do serviço, determinando como as requisições serão roteadas para as réplicas. Valores comuns:vip
(Virtual IP): cria um IP virtual para o serviço e faz o balanceamento entre réplicas.dnsrr
(DNS Round Robin): usa DNS para distribuir a carga diretamente entre as réplicas.
labels
Adiciona metadados (key-value) ao serviço. É útil para organização, filtragem, automação ou integração com outras ferramentas.mode
Define como o serviço será executado. Valores comuns:replicated
: cria um número especificado de réplicas.global
: executa uma instância do serviço em cada nó disponível.
placement
Controla onde as tarefas serão alocadas, com base em restrições ou preferências. Existem duas opções disponíveis em placement para configurar onde e como as tarefas de um serviço serão alocadas:constraints
Define regras obrigatórias que um node deve cumprir para que possa receber tarefas do serviço. Use para especificar critérios como rótulos, papéis de node (manager ou worker), ou outras propriedades. O exemplo abaixo mostra um serviço que só será implantado em nodes com o papel demanager
e com o rótuloenvironment=production
.placement:
constraints:
- "node.role == manager"
- "node.labels.environment == production"O exemplo abaixo faz com que o serviço só seja executado em nodes com o rótulo
environment=production
.deploy:
placement:
constraints:
- "node.labels.environment == production"preferences
Define uma estratégia opcional para distribuir tarefas entre os nodes qualificados de forma equilibrada. A única estratégia disponível atualmente éspread
, que distribui tarefas uniformemente com base nos valores de um rótulo. O exemplo abaixo mostra que as tarefas serão distribuídas de forma uniforme entre os nodes com base no rótuloregion
, comous-east
ouus-west
.placement:
preferences:
- spread: node.labels.regionO exemplo abaixo faz com que as tarefas sejam distribuídas uniformemente entre os nodes com base no rótulo
region
.deploy:
placement:
preferences:
- spread: node.labels.regionResumindo: Para
node.labels.region
, se tem o labelregion
(não importa o valor do label) coloca os container nesses nodes. Paranode.labels.environment == production
, se tem o labelenvironment: production
coloca nesses nodes. E paranode.role == manager
, se for um node manager, executa nele.Para adicionar um label num node, faça:
docker node update --label-add key=value <node-name>
.
replicas
Número de réplicas desejadas para o serviço. É aplicável apenas quando omode
éreplicated
.max_replicas_per_node
Limita o número de réplicas que podem ser executadas em um único node. Usado para evitar a concentração de instâncias em um único node.resources
Define limites e reservas de recursos para o serviço.- limits: quantidade máxima de recursos que o serviço pode usar.
- reservations: quantidade mínima de recursos reservados para o serviço.
- Exemplo:
resources:
limits:
memory: 512M
cpus: "0.5"
reservations:
memory: 256M
cpus: "0.25"
restart_policy
Configura como o serviço será reiniciado em caso de falha. Os parâmetros são:- condition: Quando reiniciar (
none
,on-failure
,any
). - delay: Tempo de espera entre tentativas de reinício.
- max_attempts: Número máximo de tentativas.
- window: Período de tempo para contabilizar falhas.
- condition: Quando reiniciar (
rollback_config
Configura o comportamento de rollback se o deploy falhar. Os parâmetros são:- parallelism: Número de tarefas revertidas simultaneamente.
- delay: Intervalo entre cada rollback.
- failure_action: O que fazer se o rollback falhar (
pause
,continue
). - monitor: Tempo de monitoramento após o rollback.
- max_failure_ratio: Taxa máxima de falhas aceitável.
update_config
Configura como as atualizações do serviço serão feitas. Os parâmetros são:- parallelism: Número de tarefas atualizadas simultaneamente.
- delay: Tempo entre atualizações de tarefas.
- failure_action: O que fazer se a atualização falhar (
pause
,continue
,rollback
). - monitor: Tempo de monitoramento após cada atualização.
- max_failure_ratio: Taxa máxima de falhas aceitável.