Skip to main content
O módulo de Chaos Engineering permite injetar falhas em workloads Kubernetes e observar como a plataforma AIOps reage. Diferente de ferramentas de chaos standalone, os experimentos aqui são integrados ao pipeline de AIOps: Issues abertas enquanto um experimento roda são marcadas como simulações de chaos, então não acionam ninguém e não poluem o histograma de MTTR de produção.
Cada experimento é um custom resource ChaosExperiment reconciliado pelo controller de chaos do operator. As proteções (listas de namespaces permitidos/bloqueados, mínimo de pods saudáveis, limite de concorrência, abortar ao surgir uma nova Issue) são campos declarativos do CR. Nada vem protegido por padrão: toda proteção é opt-in.
O que funciona sem ajustes. O RBAC distribuído pelo Helm chart do operator e por operator/config/rbac/role.yaml deixa o operator fazer get, list, watch, create, update e delete em pods, então todos os tipos de experimento suportados podem rodar:
  • pod_kill e pod_failure deletam pods do alvo.
  • cpu_stress, memory_stress e disk_stress criam um pod de stress que passa no Pod Security Standard restricted.
  • network_delay e network_loss não são suportados. O CRD os aceita, mas um experimento de qualquer um dos dois falha na hora, em Pending, com um result dizendo que nada foi injetado: falhas de rede precisam de um injetor tc/netem privilegiado que o operator não instala.
Se você gerencia o RBAC do operator por conta própria, veja Concedendo permissões em pods abaixo.

Chaos Engineering no Contexto AIOps

Validação de Remediações

Depois de corrigir um incidente, recrie a falha com um novo experimento e veja se a plataforma detecta e remedia de novo.

Testes de Resiliência

Confira se os workloads voltam à prontidão total depois que pods são derrubados.

Game Days

Rode experimentos sob demanda. Agendamentos recorrentes não são suportados (um experimento com schedule falha); use um agendador externo para criar experimentos periodicamente.

Analytics que Reconhece Simulações

Issues induzidas por chaos são contadas à parte, então simulações não inflam os números de incidentes de produção.

Correlação Automática com Issues

Quando o controller de anomalias cria uma Issue, ele procura um ChaosExperiment no mesmo namespace do recurso afetado cujo spec.target tenha o mesmo kind, name e namespace, e que esteja Running ou tenha terminado (Completed/Aborted) há menos de 2 minutos. Se encontrar, a Issue recebe dois labels:
A Issue então segue o pipeline normal de AIOps, com estas diferenças:
Os endpoints REST analytics/mttd e analytics/mttr deixam as simulações de chaos de fora, como o histograma de resolução do Prometheus. As regras de NotificationPolicy não conseguem casar por label, então as simulações ainda chegam a todo canal cuja regra case com a severidade, namespace, kind ou estado da Issue. Rode as simulações num namespace dedicado se quiser roteá-las separadamente.
Crie o ChaosExperiment no mesmo namespace do alvo. A busca de correlação só olha o namespace do alvo, enquanto linkedIssueRef e o pedido de aprovação são resolvidos no namespace do experimento.

ChaosExperiment CRD

Short name: chaos. Colunas do kubectl get: Type, Target, State, Duration, Age.

Especificação Completa

O controller nunca preenche status.conditions. Acompanhe o experimento por status.state e status.result (um resumo legível).

7 Tipos de Experimento

A falha é injetada uma única vez, no primeiro reconcile depois que o experimento entra em Running. duration é a janela de observação: o controller espera ela passar (verificando a cada 10 segundos no máximo) e então executa os passos pós-experimento. Os pods do alvo são os pods do Deployment (via seus ReplicaSets) ou do StatefulSet. Qualquer outro target.kind faz o experimento falhar. Parâmetros ausentes ou que não são inteiros válidos caem no padrão sem aviso.

1. Pod Kill

Deleta pods do alvo escolhidos aleatoriamente, com gracePeriodSeconds: 0. A seleção aleatória é um embaralhamento Fisher-Yates com crypto/rand.
Pod kill simula uma falha abrupta (ex.: queda de node). Use safetyChecks.minHealthyPods para não derrubar todas as réplicas.

2. Pod Failure

Mesma seleção do pod_kill, mas deleta com um grace period definido no experimento (ele sobrepõe o terminationGracePeriodSeconds do próprio pod).

3. CPU Stress

Cria um pod stress-ng fixado no node do primeiro pod do alvo. Ele estressa o node, não o container do alvo.
Pod de stress gerado (mesmo formato para os três tipos de stress; só mudam o prefixo do nome e o comando):
Os recursos do pod de stress são fixos: ele usa no máximo 500m de CPU e 512Mi de memória, não importa o que cores, loadPercent ou bytes digam. A imagem (alexeiled/stress-ng:latest, do Docker Hub) não pode ser trocada. O pod passa no Pod Security Standard restricted: roda como UID/GID 65534, não-root, com o perfil seccomp RuntimeDefault, sem escalada de privilégio, com todas as capabilities removidas, root filesystem somente leitura (um emptyDir em /tmp é o único caminho gravável) e sem token de ServiceAccount.

4. Memory Stress

Cria um pod stress-ng que aloca memória no node do alvo: stress-ng --vm <workers> --vm-bytes <bytes> --timeout <duration>.
Por causa do limite de 512Mi, pedir mais memória faz o container de stress ser morto por OOM em vez de pressionar o node.

5. Network Delay

Não suportado. O tipo é aceito pelo CRD por compatibilidade, mas injetar latência exige um injetor tc/netem privilegiado que o operator não instala. O experimento falha assim que é pego, ainda em Pending e antes de qualquer safety check, aprovação ou dry run; nenhum pod é tocado:
Use uma ferramenta dedicada de chaos de rede para testes de latência.

6. Network Loss

Não suportado, pelo mesmo motivo do network_delay. Um experimento desse tipo falha em Pending com result: "network_loss is not supported: ... nothing was injected", e nenhum pacote é descartado.

7. Disk Stress

Cria um pod stress-ng que gera I/O de disco no node do alvo: stress-ng --hdd <workers> --hdd-bytes <size> --timeout <duration>. O I/O vai para o filesystem do próprio container de stress.

Resumo dos Tipos

Concedendo Permissões em Pods

O chart (rbac.create: true) e o operator/config/rbac/role.yaml já concedem esses verbos. Se você roda o operator com um RBAC gerenciado por você (rbac.create: false), os tipos de stress precisam de create em pods; sem isso, os tipos de stress falham (execution failed: creating ... stress pod: ... forbidden). Por exemplo, no cluster inteiro:
Para limitar o raio de impacto, aplique as mesmas regras com Role/RoleBinding só nos namespaces onde você roda experimentos.

Safety Checks

Os safety checks rodam nesta ordem enquanto o experimento está Pending. Todos são avaliados uma única vez, antes da injeção da falha, exceto abortOnIssueDetected, que é verificado durante a execução.

AllowedNamespaces / BlockedNamespaces

Comparados com spec.target.namespace. Um namespace bloqueado, ou ausente de uma lista de permitidos não vazia, leva o experimento a Failed (namespace "<ns>" is not allowed by safety checks).
Lista de permitidos. Se estiver definida, somente esses namespaces podem ser alvo. Se estiver vazia, todo namespace não bloqueado é permitido.
blockedNamespaces tem precedência sobre allowedNamespaces. Não existem namespaces bloqueados por padrão: kube-system e chatcli-system só ficam protegidos se você os listar.

MaxConcurrentExperiments

Conta os experimentos em estado Running em todos os namespaces e compara com o maxConcurrentExperiments do próprio experimento (padrão 1; 0 ou menos é tratado como 1). Quando o limite é atingido, o experimento continua Pending e é tentado de novo a cada 15 segundos. Ele não falha.

MinHealthyPods

Se for maior que 0, o controller conta os pods do alvo com condição Ready igual a True, subtrai o parâmetro count (padrão 1, seja qual for o tipo do experimento) e leva o experimento a Failed quando o resultado fica abaixo de minHealthyPods:
Essa verificação roda uma vez, antes da injeção. Ela não acompanha a saúde dos pods durante o experimento.

RequireApproval

Quando true, o controller procura um ApprovalRequest chamado chaos-<nome-do-experimento> no namespace do experimento, cria se não existir (pertencente ao experimento, então é apagado junto com ele) e verifica de novo a cada 30 segundos. O experimento só começa quando o status.state desse pedido for Approved. Se o pedido ficar Rejected ou Expired, o experimento vai para Failed (approval rejected by <aprovador>: <motivo> ou approval request chaos-<nome-do-experimento> expired without a decision). O pedido que o controller monta é este:
policyRef: chaos-safety não é uma policy embutida. Quando existe no namespace do experimento uma ApprovalPolicy chamada chaos-safety com uma regra chamada chaos-experiment-approval, é essa regra que decide o pedido (por exemplo, um quorum ou uma change window). Sem ela, o pedido é avaliado com as próprias configurações: uma aprovação humana, expirando depois de 30 minutos. Aprove ou rejeite como qualquer outro pedido, com a anotação platform.chatcli.io/approve / reject, a API REST ou o dashboard:

AbortOnIssueDetected

Enquanto o experimento está Running e a duration ainda não passou, cada reconcile (a cada 10 segundos no máximo) lista as Issues do namespace do alvo. Se alguma Issue tiver exatamente o mesmo kind, nome e namespace em spec.resource que o alvo e tiver sido criada depois de status.startedAt, o experimento vai para Aborted com result: "aborted: new issue detected: <issue>". Em seguida os pods de stress são deletados.
A verificação não distingue Issues causadas pelo próprio experimento. Se o AIOps detectar a falha que você injetou (o objetivo habitual de uma simulação), o experimento é abortado. Deixe abortOnIssueDetected: false quando você espera que o AIOps abra uma Issue para o alvo.

Verificação Pós-Experimento

Quando a duration passa, o controller deleta os pods de stress, grava o postExperimentSnapshot e executa os passos abaixo. A partir daqui o experimento sempre termina em Completed, mesmo que a recuperação não tenha sido verificada.

VerifyRecovery

O alvo é considerado saudável quando um Deployment tem readyReplicas e availableReplicas pelo menos iguais a spec.replicas, ou quando um StatefulSet tem readyReplicas pelo menos igual a spec.replicas. Se ainda não estiver saudável, o controller verifica de novo a cada 5 segundos.

RecoveryTimeout

Por quanto tempo continuar verificando depois que a duration passou. Padrão 5m. Um valor inválido cai em 5m sem aviso. Quando o prazo estoura, o experimento é marcado Completed com recoveryVerified: false, recoveryTime: "timeout" e um result terminando em recovery NOT verified (timeout). Ele não é marcado Failed. O recoveryTime (e o histograma chatcli_operator_chaos_recovery_time_seconds) é medido do fim da injeção (startedAt + duration) até a primeira verificação de saúde que passa. As verificações rodam a cada 5 segundos, então o valor tem essa granularidade; um alvo que já está saudável quando o experimento termina registra os poucos segundos entre o fim da injeção e essa verificação.

RunRemediationTest

Esta opção não reinjeta a falha. Ao concluir, o controller lê a Issue indicada em linkedIssueRef (no namespace do experimento) e só verifica se o status.state dela é Resolved:
  • Resolved: result: "completed: <type> experiment finished; remediation validation passed"
  • qualquer outro estado, ou sem linkedIssueRef: result: "completed: <type> experiment finished; no remediation was applied during experiment"
Se a Issue vinculada já estava Resolved antes do experimento começar, a verificação passa independentemente do que aconteceu durante o experimento. Com runRemediationTest: true, o texto do result não fala da recuperação; consulte recoveryVerified para isso.

Máquina de Estados

Experimentos em estado terminal nunca rodam de novo. Para repetir um experimento, delete e crie de novo (redefinir o status manualmente não reinjeta a falha, porque o controller pula a injeção quando podsAffected já está preenchido). Não existe campo para abortar um experimento em execução. Deletar o CR ou definir enabled: false faz o controller parar de tratá-lo, mas sem limpeza: os pods de stress continuam rodando até o --timeout do stress-ng.
A duration só é interpretada quando o experimento já está Running, então um valor inválido (por exemplo 1d) só é detectado depois que os safety checks e a aprovação já passaram.

DryRun Mode

Com dryRun: true, o controller roda as verificações de Pending (namespaces, concorrência, minHealthyPods e aprovação, se exigida) e leva o experimento direto para Completed, sem tocar em nenhum pod. Ele não seleciona pods nem planeja ações individuais.
Resultado de um DryRun:
Um dry run incrementa chatcli_operator_chaos_experiments_total{result="dry_run"}.
Rode um dry run primeiro para confirmar que as listas de namespaces e o minHealthyPods aceitam o alvo. Se um safety check falhar, o dry run termina em Failed com a mesma mensagem que uma execução real teria.

Schedule (Experimentos Recorrentes)

O campo schedule existe no CRD, mas experimentos recorrentes não são suportados. Um experimento que define schedule falha na hora, em Pending, sem injetar nada, com result: "schedule is not supported: recurring experiments are not implemented; remove spec.schedule and create one ChaosExperiment per run".
Para game days recorrentes, crie um ChaosExperiment novo de forma agendada, fora do operator, por exemplo com um CronJob do Kubernetes que rode kubectl create -f num manifesto com metadata.generateName (assim cada execução ganha um nome e um status novos). Limpe os experimentos antigos por conta própria; o operator não os remove.

LinkedIssueRef

linkedIssueRef aceita só um name; a Issue é buscada no namespace do experimento. Ele é usado em dois lugares:
  1. Aprovação: quando requireApproval é true, vira o spec.issueRef do ApprovalRequest gerado.
  2. runRemediationTest: ao concluir, o controller verifica se essa Issue está Resolved e grava o resultado em status.result.
O controller não altera a Issue nem o RemediationPlan dela, e não registra o vínculo em nenhum outro lugar do status do experimento.

Exemplos YAML Completos

Métricas

O controller de chaos registra três métricas no endpoint de métricas do operator (porta 8080 por padrão): result="failed" significa que um safety check ou a injeção falhou. Um alvo que não se recuperou a tempo ainda conta como completed.

Exemplo de Alertas

Para alertar sobre recuperação não verificada, consulte os CRs (status.recoveryVerified: false em experimentos Completed); não existe métrica para isso.

Boas Práticas

1

Comece com DryRun

Confirme que as listas de namespaces e o minHealthyPods aceitam o alvo antes de rodar um experimento de verdade.
2

Staging Primeiro

Rode experimentos em staging antes de ambientes de tier mais alto. Defina allowedNamespaces e blockedNamespaces explicitamente; nada é bloqueado por padrão.
3

Safety Checks Conservadores

Configure minHealthyPods com margem. Se o deployment tem 5 réplicas e precisa de 3 para operar, use minHealthyPods: 3 e mantenha count baixo: um count igual ou maior que o número de réplicas deleta todos os pods.
4

Escolha o abortOnIssueDetected com Intenção

Ligue para parar a simulação assim que o AIOps reagir; desligue quando o objetivo da simulação é deixar o AIOps detectar e remediar.
5

Recrie a Cada Execução

Experimentos rodam uma vez. Use um agendador externo que crie um CR novo (com generateName) para game days recorrentes.

Próximos Passos

Fluxo de Aprovação

Como os ApprovalRequests são decididos, usados pelo requireApproval.

Ciclo de Vida de Incidentes

O pipeline de Issues pelo qual as Issues induzidas por chaos passam.

Dashboard Web

Mostre ou oculte simulações de chaos nas telas de incidentes.

Plataforma AIOps

Retorne à visão geral da plataforma AIOps.