Identificando e Corrigindo Gargalos em Playbooks Lentos do Ansible
Acelere drasticamente suas implantações Ansible identificando e eliminando gargalos de desempenho. Este guia fornece etapas práticas, exemplos de configuração e melhores práticas para perfilagem de playbooks lentos, otimização de coleta de fatos, gerenciamento de conexões e ajuste de execução de tarefas. Aprenda a aproveitar os recursos do Ansible para automação de infraestrutura eficiente e rápida.
Identificando e Corrigindo Gargalos em Playbooks Lentos do Ansible
Playbooks lentos do Ansible são frustrantes porque o atraso raramente está em um lugar óbvio. Uma execução pode gastar alguns segundos coletando fatos, mais alguns abrindo conexões SSH e, em seguida, minutos copiando arquivos um host de cada vez. Se você apenas adivinhar, geralmente ajusta a coisa errada.
Comece medindo onde o tempo é gasto. Em seguida, corrija a maior fonte de atraso primeiro. Em um ambiente pequeno, isso pode ser uma única tarefa de shell que executa um gerenciador de pacotes toda vez. Em um ambiente maior, geralmente é a configuração de conexão, coleta de fatos, baixo forks ou um playbook que serializa o trabalho mais do que o pretendido.
Compreendendo as Métricas de Desempenho do Ansible
Antes de mergulhar em técnicas de otimização específicas, é crucial entender como medir e interpretar o desempenho do Ansible. O Ansible fornece informações de tempo integradas que podem ser inestimáveis para diagnósticos.
Use a Saída de Tempo Antes de Logs Detalhados
Uma saída muito detalhada pode ajudar com problemas de conexão, mas é ruidosa para o trabalho de desempenho. Uma primeira passagem mais limpa é o callback profile_tasks, que mostra as durações das tarefas no final da execução.
No ansible.cfg:
[defaults]
callbacks_enabled = profile_tasks
Em seguida, execute o playbook normalmente:
ansible-playbook my_playbook.yml
Observe as tarefas mais lentas primeiro. Se uma tarefa leva a maior parte da execução, não passe a manhã debatendo forks.
Controlando a Verbosidade da Saída
Use -vvv quando precisar ver detalhes do SSH, comportamento de transferência de módulo, novas tentativas ou descoberta de interpretador. Para tempo de rotina, isso pode esconder o sinal sob páginas de saída de log.
Gargalos Comuns e Estratégias de Otimização
Vários fatores podem contribuir para playbooks lentos do Ansible. Aqui, exploraremos gargalos comuns e forneceremos estratégias acionáveis para resolvê-los.
1. Coleta Excessiva de Fatos
Por padrão, o Ansible coleta fatos (informações do sistema) dos hosts gerenciados no início de cada play. Embora útil, isso pode ser demorado, especialmente em um grande número de hosts ou redes lentas. Se o seu playbook não requer todos os fatos coletados, você pode desabilitar ou limitar a coleta de fatos.
Desabilitando a Coleta de Fatos
Para desabilitar completamente a coleta de fatos para um play, use a diretiva gather_facts: no:
- name: Meu Playbook
hosts: webservers
gather_facts: no
tasks:
- name: Garantir que o Apache esteja instalado
apt: name=apache2 state=present
Limitando a Coleta de Fatos
Se você precisar de alguns fatos, mas não de todos, pode especificar quais fatos coletar usando gather_subset.
- name: Meu Playbook
hosts: webservers
gather_facts: yes
gather_subset:
- '!all'
- '!any'
- hardware
- network
tasks:
- name: Usar fatos de rede
debug: var=ansible_default_ipv4.address
Armazenando Fatos em Cache
Para ambientes onde os fatos não mudam com frequência, armazená-los em cache pode acelerar drasticamente as execuções subsequentes do playbook. O Ansible suporta vários plugins de cache de fatos (por exemplo, jsonfile, redis, memcached).
Para habilitar o cache de fatos, configure-o no seu arquivo ansible.cfg:
[defaults]
fact_caching = jsonfile
fact_caching_connection = /caminho/para/ansible/facts_cache
fact_caching_timeout = 86400 # Cache por 24 horas
Em seguida, seu playbook usará automaticamente os fatos em cache quando disponíveis.
2. Execução Ineficiente de Tarefas
Algumas tarefas podem ser inerentemente lentas, ou podem ser executadas de maneira ineficiente.
Execução Paralela (Forking)
O comportamento padrão do Ansible é executar tarefas em hosts sequencialmente dentro de um play. Você pode aumentar o número de processos paralelos (forks) que o Ansible usa para gerenciar hosts simultaneamente. Isso é controlado pela configuração forks no ansible.cfg ou através da opção de linha de comando -f.
ansible.cfg:
[defaults]
forks = 10
Linha de comando:
ansible-playbook my_playbook.yml -f 10
Dica: Comece com um número moderado de forks e aumente gradualmente enquanto observa o nó de controle, a rede e o serviço de destino. Mais forks podem tornar uma implantação mais rápida, mas também podem sobrecarregar um repositório de pacotes, balanceador de carga ou etapa de migração de banco de dados.
Idempotência e Gerenciamento de Estado
Garanta que suas tarefas sejam idempotentes. Isso significa que executar uma tarefa várias vezes deve ter o mesmo efeito que executá-la uma vez. Os módulos do Ansible são geralmente projetados para serem idempotentes, mas scripts ou comandos personalizados podem não ser. Verificações ineficientes dentro das tarefas também podem adicionar sobrecarga.
Por exemplo, em vez de executar um comando que verifica se um serviço está em execução e depois o inicia, use o módulo service dedicado:
Ineficiente:
- name: Iniciar serviço (verificação ineficiente)
command: systemctl start my_service.service || true
when: "'inactive' in service_status.stdout"
register: service_status
changed_when: false # Esta tarefa não altera o estado
Eficiente (usando o módulo service):
- name: Garantir que my_service esteja em execução
service:
name: my_service
state: started
Usando async e poll para Operações de Longa Duração
Para tarefas que podem levar muito tempo para serem concluídas (por exemplo, atualizações de pacotes, migrações de banco de dados), usar as diretivas async e poll do Ansible pode evitar que seu playbook trave.
async: Especifica o tempo máximo que a tarefa deve ser executada em segundo plano.poll: Especifica com que frequência o Ansible deve verificar o status da tarefa assíncrona.
- name: Executar uma operação de longa duração
command: /usr/local/bin/long_script.sh
async: 3600 # Executar por no máximo 1 hora
poll: 60 # Verificar status a cada 60 segundos
3. Otimização de Conexão
Como o Ansible se conecta aos seus nós gerenciados desempenha um papel crucial no desempenho.
Multiplexação de Conexão SSH
A multiplexação SSH (ControlMaster) permite que várias sessões SSH compartilhem uma única conexão de rede. Isso pode acelerar significativamente as conexões subsequentes ao mesmo host.
Habilite no seu ansible.cfg:
[ssh_connection]
control_master = auto
control_path = ~/.ansible/cp/ansible-%%r@%%h:%%p
control_persist = 600 # Manter a conexão de controle aberta por 10 minutos
Tentativas e Tempo Limite SSH
Ajustar os parâmetros de conexão SSH pode evitar atrasos desnecessários quando os hosts estão temporariamente indisponíveis.
[ssh_connection]
sf_retries = 3
sf_delay = 1
ssh_args = -o ControlMaster=auto -o ControlPersist=60s -o ConnectionAttempts=5 -o ConnectTimeout=10
Usando pipelining
O pipelining permite que o Ansible execute comandos diretamente no host remoto sem criar uma nova sessão SSH para cada comando. Isso pode reduzir drasticamente a sobrecarga para muitas tarefas.
Habilite no ansible.cfg:
[ssh_connection]
pipelining = True
Aviso: O pipelining pode entrar em conflito com algumas configurações de escalonamento de privilégios, especialmente quando requiretty está habilitado para sudo em distribuições mais antigas. Teste com o mesmo caminho become que seus playbooks de produção usam.
4. Otimizando a Estrutura e Lógica do Playbook
Às vezes, a maneira como um playbook é escrito pode ser a fonte da lentidão.
Usando delegate_to e run_once
Se uma tarefa precisa ser executada apenas em um host, mas afeta vários outros (por exemplo, reiniciar um balanceador de carga), use delegate_to e run_once para executá-la de forma eficiente.
- name: Reiniciar balanceador de carga
service: name=haproxy state=restarted
delegate_to: lb_server_1
run_once: true
Uso Estratégico de Roles e Includes
Embora roles e includes ajudem na organização, includes profundamente aninhados ou estruturados de forma ineficiente podem adicionar uma pequena sobrecarga. Certifique-se de que suas dependências de role e lógica de include sejam limpas.
Palavra-chave serial
A palavra-chave serial limita o número de hosts que podem ser afetados simultaneamente dentro de um play. Embora frequentemente usada para implantações controladas, também pode ser um gargalo se definida muito baixa para o desempenho desejado.
- name: Implantar aplicativo em um subconjunto de servidores
hosts: appservers
serial: 2 # Executar apenas em 2 hosts por vez
tasks:
- name: Atualizar código do aplicativo
copy: src=app/ dest=/opt/app/
Se você não está limitando intencionalmente o paralelismo, certifique-se de que serial não esteja definido ou esteja definido com um número alto o suficiente.
Corrija Tarefas Lentas, Não Apenas Transporte Lento
O ajuste de conexão ajuda quando o playbook tem muitas tarefas curtas. Não corrige uma tarefa que faz muito trabalho toda vez.
Um exemplo comum é usar shell para executar um comando de pacote:
- name: Instalar nginx com shell
shell: apt-get update && apt-get install -y nginx
Essa tarefa é difícil para o Ansible raciocinar. Pode relatar alterado toda vez, pode atualizar metadados do pacote a cada execução e fornece menos informações estruturadas sobre falhas. Prefira módulos que entendem estado:
- name: Atualizar cache apt quando necessário
apt:
update_cache: true
cache_valid_time: 3600
- name: Instalar nginx
apt:
name: nginx
state: present
A mesma ideia se aplica à implantação de arquivos. Copiar um diretório grande com centenas de arquivos pequenos através do módulo copy pode ser lento porque o Ansible verifica e transfere arquivo por arquivo. Para lançamentos de aplicativos, pode ser mais rápido construir um artefato uma vez, fazer upload do arquivo e descompactá-lo no destino:
- name: Fazer upload do artefato de lançamento
copy:
src: dist/app.tar.gz
dest: /tmp/app.tar.gz
- name: Descompactar lançamento
unarchive:
src: /tmp/app.tar.gz
dest: /opt/app
remote_src: true
Isso nem sempre é o design certo, mas é a pergunta certa: você está pedindo ao Ansible para sincronizar milhares de pequenas decisões quando um artefato seria mais claro?
Verifique o Inventário e o Trabalho de Variáveis
O inventário dinâmico pode ser outro atraso oculto. Se toda execução de playbook chama uma API de nuvem, espera pela paginação e reconstrói toda a lista de hosts, o playbook pode parecer lento antes mesmo da primeira tarefa começar. Armazene dados de inventário em cache quando seu plugin suportar e mantenha padrões de host estreitos. Executar uma implantação web contra all e depois pular a maioria dos hosts com condições when desperdiça tempo.
O carregamento de variáveis também pode ficar confuso. Arquivos grandes group_vars/all.yml, lookups caros e renderização repetida de templates podem se acumular. Se um lookup acessa um gerenciador de segredos ou endpoint HTTP, armazene o resultado em uma variável uma vez por play em vez de chamá-lo em muitas tarefas.
Ferramentas e Técnicas de Perfilagem
Além da saída detalhada do próprio Ansible, a perfilagem dedicada pode oferecer insights mais profundos.
ansible-playbook --syntax-check
Este comando verifica seu playbook em busca de erros de sintaxe, mas não o executa. É uma maneira rápida de validar a estrutura do seu playbook antes de uma execução completa.
Registrando Eventos do Ansible
O Ansible pode registrar seus eventos de execução em um arquivo, que pode ser analisado posteriormente. Isso é particularmente útil para playbooks de longa duração ou para auditoria.
Configure o registro de eventos no ansible.cfg:
[defaults]
log_path = /var/log/ansible.log
Plugins de Callback Personalizados
Para perfilagem avançada, você pode escrever plugins de callback personalizados para capturar métricas específicas ou criar relatórios personalizados sobre a execução do playbook.
Use Async para Esperar, Não para Tudo
Parte do tempo do playbook é espera real: uma reinicialização de serviço, uma compilação de pacote, uma instância de nuvem ficando pronta ou uma migração de banco de dados que leva alguns minutos. Se essas tarefas não precisam bloquear todos os hosts em sincronia, o async e poll do Ansible podem ajudar.
- name: Iniciar geração de relatório de longa duração
command: /opt/tools/build-report
async: 1800
poll: 0
register: report_job
- name: Verificar trabalho do relatório
async_status:
jid: "{{ report_job.ansible_job_id }}"
register: report_status
until: report_status.finished
retries: 60
delay: 10
Use isso com cuidado. Async não é um atalho para tornar tarefas inseguras paralelas. Se dez hosts iniciarem uma migração de banco de dados ao mesmo tempo, o playbook pode terminar mais rápido e ainda quebrar o ambiente. Async funciona melhor para trabalho independente, onde o destino pode continuar com segurança enquanto o Ansible verifica mais tarde.
Meça do Ponto de Vista do Usuário
Um playbook pode ser tecnicamente mais rápido e ainda parecer lento se o operador esperar muito tempo antes de ver feedback útil. Divida uma implantação grande em fases com nomes de tarefas claros: verificações de pré-voo, upload de artefato, atualização de serviço, verificação de saúde, limpeza. Quando uma fase é lenta, a saída do perfil e o humano lendo o terminal entendem para onde o tempo foi.
Isso também ajuda nas decisões de reversão. Se o playbook gasta 12 minutos antes da primeira verificação de saúde, você pode estar descobrindo falhas tarde demais. Uma pequena tarefa de pré-voo que verifica espaço em disco, acesso ao repositório de pacotes e credenciais de serviço pode economizar muito mais tempo do que reduzir um segundo na configuração do SSH.
O melhor trabalho de desempenho do Ansible é chato de uma boa maneira: habilite o tempo das tarefas, encontre a etapa mais lenta, mude uma coisa e meça novamente. Desabilite fatos apenas quando não precisar deles. Aumente forks apenas quando os destinos e dependências puderem lidar com o paralelismo. Substitua comandos de shell ruidosos por módulos com reconhecimento de estado. Use multiplexação SSH e pipelining depois de confirmar que a sobrecarga de conexão é realmente parte do problema.
Essa disciplina mantém o playbook legível enquanto ainda o torna mais rápido. Uma implantação que termina rapidamente, mas que ninguém entende, é apenas a interrupção de amanhã com uma barra de progresso mais curta.