Ansible --limit e blast radius: por que alvo vazio não pode ser detalhe de interface
Como tornar o alvo da automação explícito, bloquear execuções amplas por engano e transformar PLAY RECAP e escalonamento em parte do contrato operacional.
Em Ansible, uma diferença pequena na linha de comando pode mudar completamente o blast radius:
| |
versus:
| |
Em um catálogo real de operações executadas via Semaphore, o runbook N1 colocou uma regra simples no topo:
preencher sempre o Limite quando o campo existir. Em branco, a tarefa pode alcançar todos os servidores do inventory.
Isso não é ergonomia.
É controle de risco.
O playbook define hosts; --limit reduz o conjunto #
Um playbook pode declarar:
| |
ou um grupo amplo.
--limit aplica uma restrição adicional ao conjunto resolvido pelo inventory.
Exemplo:
| |
O problema aparece quando a interface torna o limite opcional para uma operação que não deveria ser ampla.
Campo vazio não deve significar “todos” silenciosamente #
No runbook analisado, o alerta existe justamente porque uma execução sem Limite pode cair no comportamento amplo do playbook/inventory.
Para tarefas de mudança, eu prefiro inverter a lógica:
| |
em vez de:
| |
Isso pode ser validado no próprio playbook.
Guardrail dentro do playbook #
Se o target vem como variável:
| |
Quando o limit é aplicado pelo orquestrador, também vale validar a expectativa de escopo por preflight ou wrappers.
A interface sozinha não deve ser a única barreira.
O risco depende da operação #
Um all pode ser aceitável para um inventário LOW, desde que a concorrência seja conhecida.
Por exemplo:
| |
Pode ser deliberadamente executado na frota inteira.
Já:
| |
precisa de uma política muito mais estreita.
O alvo faz parte da classificação de risco.
Blast radius precisa aparecer antes do Run #
O catálogo operacional recuperado descreve tarefas com campos como:
| |
Isso é uma boa interface mental.
Antes de executar, a pessoa consegue responder:
se eu errar, quantos hosts posso afetar?
Uma receita de provisionamento, por exemplo, estava documentada com blast radius de um host novo.
Outras operações cloud podiam variar de risco conforme a ação escolhida.
Survey deve ajudar a reduzir espaço de erro #
Em vez de um texto completamente livre, dependendo do template podemos usar:
- select com grupos/hosts permitidos;
- regex para hostname esperado;
- lista gerada do inventory;
- bloqueio de
all,*ou grupo global; - confirmação extra para grupos maiores;
- defaults vazios, nunca defaults perigosos.
Se o operador precisa digitar um hostname, valide o formato antes de chamar Ansible.
Um alvo válido também precisa existir #
Validar regex evita string absurda.
Não prova que o host existe.
Um preflight pode consultar inventory:
| |
ou:
| |
E conferir se o alvo resolve.
Outra opção é um smoke:
| |
antes de uma mudança mais crítica.
serial e throttle resolvem outro problema #
--limit responde:
quem pode ser atingido?
serial responde:
quantos ao mesmo tempo?
Exemplo:
| |
Mesmo com um grupo de dez hosts deliberadamente selecionado, talvez a mudança precise passar um por um.
Para operações de frota, eu considero as duas dimensões separadamente:
| |
Resultado esperado precisa estar documentado #
O runbook N1 não termina em “task finished”.
Ele orienta o operador a olhar o PLAY RECAP.
Uma regra operacional documentada:
| |
Isso reduz outra classe de incidente: o loop humano de clicar novamente numa automação que falhou sem entender em qual ponto parou.
Repetir task falha pode piorar estado parcial #
Ansible tende à idempotência quando os módulos/playbooks são escritos para isso.
Mas nem toda task é perfeitamente idempotente.
Um playbook pode ter:
- shell;
- API externa;
- reboot;
- deploy;
- operação cloud;
- side effect fora do host.
Então failed=1 não deveria automaticamente virar:
roda de novo.
Primeiro entender:
| |
O log é parte do contrato #
Para N1, a orientação recuperada era acompanhar a aba Log e, em falha, copiar o log completo para escalonamento.
Isso transforma o Semaphore em mais do que botão de execução.
Ele passa a ser também fonte de evidência:
| |
Um exemplo de contrato de mudança #
Eu modelaria uma receita HIGH assim:
| |
A automação continua simples.
A governança é que fica explícita.
O que a fonte sustenta #
O runbook operacional recuperado documenta diretamente:
- categoria e risco por tarefa;
- blast radius;
- pré-requisitos;
- parâmetros;
- resultado esperado;
- preenchimento obrigatório de
Limitequando aplicável; - alerta de que limite vazio pode atingir todos os servidores;
- acompanhamento de Log;
PLAY RECAP failed=0como critério operacional de sucesso;- orientação para não repetir sozinho quando houver falha e escalar com o log.
Nomes de cliente, host, domínio e IP da fonte não são necessários para aplicar o método e foram omitidos.
O principal aprendizado #
Em automação de frota, o alvo não é uma variável qualquer.
É uma fronteira de segurança.
Eu quero que uma mudança só saia do control plane quando três coisas estiverem explícitas:
| |
Se o alvo vazio significa “todo mundo”, a interface está escolhendo o default mais perigoso possível.
Me chama.
Manda o contexto, os sintomas e o que já foi testado. Bora organizar as evidências antes de sair mexendo.