Dominando Implantações Multi-Estágio Usando Playbooks Sequenciais do Ansible
Aprenda a projetar e executar implantações de aplicativos complexas e multi-estágio usando Ansible. Este guia aborda a criação de playbooks sequenciais para fases distintas de implantação, implementação de tratamento eficaz de erros e desenvolvimento de estratégias de reversão. Domine a arte da entrega robusta e automatizada de aplicativos com exemplos práticos e melhores práticas.
Dominando Implantações Multi-Estágio Usando Playbooks Sequenciais do Ansible
Implantações multi-estágio do Ansible tornam-se necessárias quando "copiar os arquivos e reiniciar o serviço" não é mais honesto. Uma implantação real pode precisar de uma migração de banco de dados, uma alteração de feature flag, um rollout de pacote, um recarregamento de serviço, uma verificação de saúde e um caminho de reversão se a nova versão falhar. Se tudo isso viver em um grande playbook com limites pouco claros, cada implantação falha se transforma em um exercício de leitura.
Playbooks sequenciais dão a cada estágio um trabalho claro. Você pode executá-los a partir de um pipeline CI/CD, AWX, Ansible Automation Platform ou um script de shell simples. A parte importante não é a ferramenta que aperta o botão. A parte importante é que a implantação tem uma ordem, cada estágio pode ser repetido com segurança e o tratamento de falhas é explícito.
Por que Playbooks Sequenciais para Implantações Multi-Estágio?
Implantar um aplicativo geralmente envolve mais do que apenas copiar arquivos. Você pode precisar:
- Preparar o ambiente: Criar diretórios, definir permissões, instalar dependências.
- Atualizar o banco de dados: Executar migrações de esquema, semear dados iniciais.
- Implantar o código do aplicativo: Transferir novas versões de código, reiniciar serviços.
- Configurar serviços: Atualizar configurações do aplicativo, recarregar daemons.
- Realizar verificações pós-implantação: Executar testes de fumaça, verificar disponibilidade do serviço.
A sequência é importante porque algumas operações são fáceis de reverter e outras não. Reverter um link simbólico para a versão anterior geralmente é simples. Reverter uma migração de banco de dados destrutiva pode não ser. Essa diferença deve moldar o plano de implantação antes que alguém escreva YAML.
Dividir essas etapas em playbooks sequenciais distintos oferece várias vantagens:
- Modularidade: Cada playbook foca em um único estágio, tornando-os mais fáceis de entender, manter e reutilizar.
- Legibilidade: A lógica complexa é dividida em partes gerenciáveis.
- Controle: Você pode executar estágios específicos de forma independente ou como parte de um fluxo de trabalho maior.
- Isolamento de Erros: Se uma falha ocorrer em um estágio, é mais fácil identificar a causa e reverter alterações específicas sem afetar outras partes da implantação.
- Idempotência: Playbooks bem escritos são inerentemente idempotentes, o que significa que executá-los várias vezes tem o mesmo efeito que executá-los uma vez. Isso é crucial para repetições seguras.
Há uma troca. Playbooks separados adicionam trabalho de orquestração. Variáveis, artefatos e status podem precisar se mover de um estágio para outro. Para um serviço interno pequeno, um playbook com blocos marcados pode ser suficiente. Para um aplicativo voltado para o cliente com requisitos de migração e reversão, a estrutura extra geralmente se paga.
Projetando Seu Fluxo de Trabalho de Implantação Multi-Estágio
Antes de escrever qualquer código Ansible, planeje seus estágios de implantação. Identifique as etapas lógicas, suas dependências e a ordem de execução. Um fluxo de trabalho comum pode ser assim:
- Verificações de Pré-implantação: Garantir que o ambiente de destino esteja pronto.
- Migração de Banco de Dados: Aplicar as alterações de esquema de banco de dados necessárias.
- Implantação do Aplicativo: Implantar a nova versão do código do aplicativo.
- Reinicialização/Recarregamento de Serviço: Colocar os serviços do aplicativo online com o novo código.
- Verificação Pós-implantação: Executar testes para confirmar o sucesso da implantação.
Para cada estágio, considere quais tarefas do Ansible são necessárias e qual playbook as conterá.
Decida também quais estágios podem alterar o estado de produção. Um playbook de teste de fumaça não deve reparar silenciosamente a configuração. Um playbook de pré-verificação não deve instalar pacotes ausentes, a menos que isso faça parte explícita do contrato de implantação. Manter verificações somente leitura separadas das etapas de mutação torna o fluxo de trabalho mais confiável.
Aqui está um layout de diretório prático:
deploy/
inventories/
staging.ini
production.ini
group_vars/
all.yml
production.yml
playbooks/
00-preflight.yml
01-migrate-db.yml
02-deploy-app.yml
03-reload-services.yml
04-smoke-test.yml
rollback-app.yml
Os números não são mágicos. Eles apenas tornam a ordem visível nas listagens de arquivos e logs de CI.
Executando Playbooks Sequencialmente
O Ansible fornece uma maneira direta de executar playbooks um após o outro usando os comandos --playbook-dir e ansible-playbook. O método mais simples é encadear comandos em seu pipeline CI/CD ou na linha de comando.
Vamos supor que você tenha os seguintes arquivos de playbook:
01-database-migration.yml02-deploy-application.yml03-restart-services.yml04-smoke-tests.yml
Você pode executá-los sequencialmente assim:
ansible-playbook -i inventory.ini 01-database-migration.yml
ansible-playbook -i inventory.ini 02-deploy-application.yml
ansible-playbook -i inventory.ini 03-restart-services.yml
ansible-playbook -i inventory.ini 04-smoke-tests.yml
Na prática, envolva essa sequência para que um estágio com falha pare o pipeline:
set -euo pipefail
ansible-playbook -i inventories/production.ini playbooks/00-preflight.yml
ansible-playbook -i inventories/production.ini playbooks/01-migrate-db.yml
ansible-playbook -i inventories/production.ini playbooks/02-deploy-app.yml
ansible-playbook -i inventories/production.ini playbooks/03-reload-services.yml
ansible-playbook -i inventories/production.ini playbooks/04-smoke-test.yml
set -e não é uma estratégia de implantação por si só, mas impede o pior erro: continuar após um estágio com falha como se nada tivesse acontecido. Os sistemas de CI geralmente fornecem seu próprio comportamento de falha, mas a mesma ideia se aplica.
Usando ansible-playbook --skip-tags ou --limit
Em cenários mais avançados, você pode combinar várias etapas lógicas em um único playbook, mas usar tags para controlar a execução. No entanto, para uma separação verdadeiramente multi-estágio, playbooks distintos são geralmente preferidos. Se você quiser executar um subconjunto de playbooks ou pular alguns, pode usar argumentos de linha de comando.
Pulando um playbook: Se 03-restart-services.yml falhar devido a um problema temporário de serviço, você pode executar novamente apenas esse estágio após corrigir a causa. Não pule estágios cegamente quando estágios anteriores produzem artefatos ou estado dos quais estágios posteriores dependem.
Limitando a um estágio específico: Você também pode limitar a execução a um host ou grupo específico usando o sinalizador --limit, o que pode ser útil para testes.
Para implantações contínuas, --limit também pode reduzir o raio de explosão:
ansible-playbook -i inventories/production.ini playbooks/02-deploy-app.yml --limit web_canary
Execute a implantação em um host ou um pequeno grupo, verifique e continue para o resto do parque. Isso é especialmente útil quando seu balanceador de carga suporta drenar hosts antes de recarregar ou reiniciar.
Incorporando Tratamento de Erros e Estratégias de Reversão
Implantações robustas exigem um plano para quando as coisas dão errado.
ignore_errors e failed_when
Por padrão, o Ansible interrompe a execução se uma tarefa falhar. Você pode controlar esse comportamento:
ignore_errors: true: Permite que o playbook continue mesmo se uma tarefa falhar. Use isso com cautela, normalmente para tarefas não críticas ou quando você tem uma tarefa subsequente para limpar ou compensar.failed_when:: Defina condições personalizadas sob as quais uma tarefa deve ser considerada como falha. Isso é poderoso para lidar com erros não fatais esperados ou validar resultados específicos.
- name: Verificar status do serviço (potencialmente não fatal)
command: systemctl status myapp
register: service_status
ignore_errors: true
- name: Falhar se o serviço não estiver ativo
fail:
msg: "O serviço myapp não está em execução!"
when: "service_status.rc != 0"
Use ignore_errors com moderação. Muitas vezes é melhor registrar o resultado e tomar uma decisão clara. Um log de implantação cheio de falhas ignoradas ensina as pessoas a parar de ler falhas.
Para comandos, prefira módulos específicos quando existirem. Por exemplo, use ansible.builtin.service, ansible.builtin.systemd, ansible.builtin.copy, ansible.builtin.template e módulos de pacote em vez de usar shell. Os módulos geralmente fornecem melhor idempotência e estados de alteração e falha mais claros.
Playbooks de Reversão
Para implantações críticas, tenha playbooks de reversão dedicados. Esses playbooks devem ser projetados para reverter as alterações feitas por seus playbooks de implantação correspondentes.
01-database-migration-rollback.yml: Reverte alterações de esquema.02-deploy-application-rollback.yml: Implanta a versão anterior do aplicativo ou restaura um backup.03-restart-services-rollback.yml: Reinicia os serviços em seu estado anterior.
A reversão do banco de dados merece cuidado especial. Algumas migrações não podem ser revertidas com segurança após as gravações começarem a usar o novo esquema. Um padrão mais seguro é frequentemente expandir e contrair: adicionar alterações de esquema compatíveis com versões anteriores, implantar código do aplicativo que possa funcionar com formas antigas e novas, preencher dados de volta, se necessário, e remover colunas ou campos antigos em uma implantação posterior.
Com esse modelo, a reversão geralmente significa reverter o código do aplicativo e deixar o esquema compatível no lugar, não tentar desfazer uma alteração arriscada no banco de dados sob pressão.
Exemplo de Gatilho de Reversão: Em seu pipeline CI/CD, se o playbook 04-smoke-tests.yml falhar, você acionaria a execução de playbooks de reversão em ordem inversa.
# Se 04-smoke-tests.yml falhar:
ansible-playbook -i inventory.ini 03-restart-services-rollback.yml
ansible-playbook -i inventory.ini 02-deploy-application-rollback.yml
ansible-playbook -i inventory.ini 01-database-migration-rollback.yml
Usando block, rescue e always
As construções block, rescue e always do Ansible fornecem uma maneira mais estruturada de lidar com erros dentro de um único playbook. Embora não sejam para sequenciar entre playbooks, são excelentes para encapsular uma série de tarefas que podem falhar e definir o que fazer em caso de falha.
- block:
- name: Implantar novo código do aplicativo
copy:
src: /path/to/new/app/
dest: /var/www/myapp/
- name: Reiniciar serviço do aplicativo
service:
name: myapp
state: restarted
rescue:
- name: Tentar reverter para versão anterior
copy:
src: /path/to/old/app/
dest: /var/www/myapp/
- name: Reiniciar serviço do aplicativo após reversão
service:
name: myapp
state: restarted
always:
- name: Registrar tentativa de implantação
debug:
msg: "Tentativa de implantação concluída."
Essa abordagem é útil para agrupar tarefas relacionadas dentro de um único playbook de estágio de implantação.
Para reversão entre playbooks, deixe o orquestrador tomar a decisão. Um pipeline de CI pode executar playbooks de reversão apenas se um estágio posterior falhar. Os fluxos de trabalho de trabalho do AWX podem modelar os mesmos ramos de sucesso e falha visualmente. Mantenha o comando de reversão chato e ensaiado.
Passando Estado de Lançamento Entre Estágios
Playbooks sequenciais geralmente precisam de um identificador de lançamento compartilhado. Por exemplo, o estágio de implantação precisa saber qual artefato instalar, o teste de fumaça precisa saber qual versão esperar e a reversão precisa saber a versão anterior.
Passe esse estado explicitamente:
ansible-playbook -i inventories/production.ini playbooks/02-deploy-app.yml \
-e release_version=2026.05.24.3 \
-e artifact_url=https://artifacts.example.com/myapp/2026.05.24.3.tar.gz
Dentro do playbook, registre o que mudou:
- name: Escrever marcador de lançamento atual
ansible.builtin.copy:
dest: /opt/myapp/current-release.txt
content: "{{ release_version }}\n"
owner: root
group: root
mode: "0644"
Esse marcador ajuda durante incidentes. Quando alguém faz SSH em um host, pode ver qual versão o host acredita estar executando. Você também pode fazer o playbook de teste de fumaça ler o marcador e compará-lo com o lançamento esperado.
Considerações Avançadas
Gerenciando Estado Entre Playbooks
Às vezes, uma tarefa em um playbook precisa informar outro playbook sobre seu resultado. Você pode conseguir isso usando:
- Cache de Facts: Se o cache de facts estiver ativado, os facts coletados por um playbook podem estar disponíveis para os subsequentes executados na mesma sessão do Ansible.
- Arquivos/Bancos de Dados Temporários: Escreva informações críticas de status ou saídas para um arquivo temporário ou uma tabela de status dedicada que playbooks subsequentes possam ler.
Prefira estado explícito a estado oculto. O cache de facts pode ser útil, mas também pode confundir as pessoas quando os valores estão desatualizados ou quando um runner tem o cache ativado e outro não. Arquivos de lançamento, metadados de artefatos, variáveis de CI e registros de implantação são mais fáceis de inspecionar.
Controle de Versão e Ferramentas de Orquestração
Para orquestrações complexas, considere integrar seus playbooks sequenciais do Ansible em uma ferramenta de nível superior:
- Pipelines CI/CD: Ferramentas como Jenkins, GitLab CI, GitHub Actions ou CircleCI são excelentes para definir e acionar implantações multi-estágio. Você define a sequência de comandos
ansible-playbookdentro da configuração do pipeline. - Ansible Tower/AWX: Para orquestração de nível empresarial, o Ansible Tower (agora Automation Platform) ou sua contraparte de código aberto AWX fornece uma UI robusta para agendar, monitorar e gerenciar modelos de trabalho complexos que podem encadear vários playbooks.
Se várias pessoas implantam o mesmo sistema, a orquestração centralizada torna-se menos sobre conveniência e mais sobre controle. Ela fornece inventários consistentes, credenciais, logs de auditoria, aprovações e um histórico visível de qual estágio falhou. Esses detalhes são importantes durante um incidente de produção.
Usando Tags para Controle Granular
Embora defendamos playbooks separados para estágios distintos, você também pode usar tags dentro dos playbooks. Se você tiver um playbook muito grande para um único estágio (por exemplo, migração de banco de dados), pode marcar tarefas específicas e executar apenas aquelas usando ansible-playbook --tags <nome_da_tag>.
Isso é mais sobre controle granular dentro de um estágio do que sobre sequenciamento entre estágios.
Melhores Práticas para Implantações Multi-Estágio
- Mantenha os Playbooks Focados: Cada playbook deve fazer uma coisa bem (por exemplo, migração de banco de dados, implantação de aplicativo).
- Nomeie os Playbooks Claramente: Use uma convenção de nomenclatura que reflita o estágio e a ordem (por exemplo,
01-,02-). - Implemente Idempotência: Garanta que todas as tarefas sejam idempotentes para permitir repetições seguras.
- Teste Reversões: Teste regularmente seus procedimentos de reversão para garantir que funcionem conforme o esperado.
- Use Controle de Versão: Armazene todos os seus playbooks e arquivos de inventário em um sistema de controle de versão (como Git).
- Automatize a Orquestração: Use pipelines CI/CD ou ferramentas como Ansible Tower/AWX para automatizar a execução de seus playbooks sequenciais.
- Documente Seu Fluxo de Trabalho: Documente claramente os estágios, seu propósito, dependências e procedimentos de reversão.
- Torne os testes de fumaça reais: Verifique o endpoint real, caminho de login, worker de fila ou trabalho em segundo plano que importa. Uma verificação de processo simples não é suficiente.
- Proteja os inventários de produção: Use inventários e credenciais separados para staging e produção. Um erro de digitação em
--limitnão deve implantar no lugar errado. - Use rollout serial quando possível:
serialpermite que você atualize alguns hosts de cada vez e pare antes que todo o parque seja afetado.
- name: Implantar aplicativo gradualmente
hosts: web
serial: 2
tasks:
- name: Instalar lançamento
ansible.builtin.unarchive:
src: "{{ artifact_path }}"
dest: /opt/myapp/releases/{{ release_version }}
remote_src: true
Com serial, o Ansible processa hosts em lotes. Combine-o com a drenagem do balanceador de carga se seu aplicativo não puder ser reiniciado sem descartar solicitações ativas.
Um Fluxo de Implantação Concreto
Uma implantação segura do Ansible para um aplicativo web pode ser assim:
00-preflight.yml verifica o espaço em disco, confirma que o lançamento de destino existe, verifica a conectividade do banco de dados e garante que os hosts estejam no ambiente esperado. Ele não altera o sistema.
01-migrate-db.yml executa apenas migrações compatíveis com versões anteriores. Ele registra a versão da migração e falha se o banco de dados já estiver à frente do lançamento solicitado.
02-deploy-app.yml baixa o artefato, descompacta-o em um diretório de lançamento versionado, cria modelos de configuração e atualiza um link simbólico current. Ele ainda não reinicia os serviços.
03-reload-services.yml drena cada host do balanceador de carga, recarrega ou reinicia o serviço, aguarda o endpoint de saúde local e, em seguida, retorna o host ao serviço.
04-smoke-test.yml chama o endpoint público através do mesmo caminho que os usuários usam. Ele verifica o corpo da resposta ou o endpoint da versão, não apenas um 200 de uma página padrão do balanceador de carga.
Este fluxo é mais lento do que uma reinicialização de um comando. Também é muito mais fácil de raciocinar quando a implantação falha no meio do caminho.
O Hábito Que Faz Isso Funcionar
Playbooks sequenciais do Ansible funcionam melhor quando cada um tem um contrato estreito: o que espera, o que muda, como prova o sucesso e o que fazer se falhar. Esse contrato é mais importante do que o número de arquivos YAML.
Comece com os estágios que refletem seu risco real: pré-verificação, migração, implantação, recarregamento, teste de fumaça, reversão. Mantenha os comandos chatos. Teste a reversão antes de precisar dela. Quando uma implantação quebrar, você deve ser capaz de apontar para o estágio exato que falhou e decidir o próximo passo sem reler toda a árvore de automação.