Incidente 2026-05-10 — ArgoCD apps degradados
Sessão de diagnóstico e correção dos apps com problemas no ArgoCD CPPS (vm-cpps-02, 192.168.0.51).
OJS — MariaDB em CrashLoop por senha regenerada
Duração: ~21 dias em CrashLoop antes da resolução.
Causa raiz
apps/ojs/templates/secret.yaml usava randAlphaNum para gerar as senhas do MariaDB:
# ANTES (errado)data: mariadb-root-password: {{ randAlphaNum 24 | b64enc | quote }}Cada sync do ArgoCD renderizava uma senha nova. O banco de dados tinha a senha antiga. O probe de liveness tentava conectar com a senha nova → acesso negado → CrashLoop.
Diagnóstico
kubectl logs ojs-mariadb-0 -n ojs# ERROR 1045 (28000): Access denied for user 'root'@'localhost' using password: YESResolução
Passo 1: reset da senha no banco via pod auxiliar (MariaDB 12.x — usar ALTER USER, não UPDATE mysql.user).
# Pod com acesso ao PVC data-ojs-mariadb-0, rodando como root (UID 0)mariadbd --datadir=/bitnami/mariadb/data --socket=/tmp/mysql.sock \ --skip-grant-tables --skip-networking --user=root &until test -S /tmp/mysql.sock; do sleep 1; donemariadb --socket=/tmp/mysql.sock -u root -e " FLUSH PRIVILEGES; ALTER USER 'root'@'%' IDENTIFIED BY '<senha>'; CREATE USER IF NOT EXISTS 'root'@'localhost' IDENTIFIED BY '<senha>'; ALTER USER 'root'@'localhost' IDENTIFIED BY '<senha>'; FLUSH PRIVILEGES;"Atenção: MariaDB 12.x removeu a coluna
Passworddemysql.user. ComandosUPDATE mysql.user SET Password=...retornamERROR 1348: Column 'Password' is not updatable. UseALTER USER.
Passo 2: corrigir secret.yaml para preservar valores existentes via lookup:
# DEPOIS (correto){{- $secretName := printf "%s-secret" (include "ojs-app.fullname" .) }}{{- $existing := lookup "v1" "Secret" .Release.Namespace $secretName }}{{- $existingData := $existing.data | default dict }}data: mariadb-root-password: {{ index $existingData "mariadb-root-password" | default (randAlphaNum 24 | b64enc) | quote }}O lookup retorna o secret existente no cluster. Se não existir (primeiro deploy), gera aleatório. Se já existir, reutiliza — sem drift em syncs subsequentes.
Lição
randAlphaNum em secret.yaml sem lookup quebra qualquer app stateful. Sempre usar o padrão lookup + default para segredos de banco de dados.
Rancher — pod em CreateContainerConfigError por 22h
Causa raiz
O ArgoCD sincronizou o chart do Rancher com uma nova variável de ambiente (IMPERATIVE_API_APP_SELECTOR), disparando um rollout. O novo pod referenciava bootstrap-secret com optional: false, mas esse secret havia sido deletado após o bootstrap inicial do Rancher.
Warning Failed 22h kubelet Error: secret "bootstrap-secret" not foundO pod antigo (rancher-7db5f6c845) continuava rodando — o Rancher funcionava normalmente, só o rollout estava travado.
Resolução
Recriar o secret com o bootstrapPassword do values.yaml:
kubectl create secret generic bootstrap-secret \ --from-literal=bootstrapPassword='<senha>' \ -n cattle-systemO novo pod subiu e o Rancher auto-atualizou seus sub-componentes (rancher-webhook, system-upgrade-controller).
Lição
O bootstrap-secret do Rancher é consumido no primeiro login mas o chart continua referenciando-o. Ele precisa existir permanentemente para que novos rollouts do pod funcionem.
tutor-openedx — LMS/CMS/workers em CrashLoop por 22 dias
Dois problemas independentes, ambos com 22 dias de duração.
Problema 1: ALLOWED_HOSTS rejeitando probe de liveness
Causa raiz: o Kubernetes envia o probe HTTP com Host: <pod-ip>:8000. O Django verifica o header Host contra ALLOWED_HOSTS = ["lms.colabh.org", "lms"]. IPs de pod não estão na lista → retorna 400 → uWSGI recebe SIGTERM → pod reinicia → loop.
Resolução: adicionar httpHeaders nos probes para forçar o header correto:
# k8s/deployments.yml — deployment lmsreadinessProbe: httpGet: path: /heartbeat port: 8000 httpHeaders: - name: Host value: lms # já está em ALLOWED_HOSTSlivenessProbe: httpGet: path: /heartbeat port: 8000 httpHeaders: - name: Host value: lmsAplicar o mesmo para o deployment cms com value: cms.
Efeito cascata: o Caddy usa a saúde do LMS como probe próprio (GET / Host: lms.colabh.org). Com o LMS em CrashLoop, o Caddy também ficava em CrashLoop, bloqueando o sync do ArgoCD (que aguardava o Caddy ficar saudável antes de aplicar os demais recursos).
Problema 2: workers Celery em OOMKill
Causa raiz: concorrência padrão do Celery = número de CPUs do node (12). Cada worker Django consome ~307 MB RSS. 12 × 307 MB = 3.7 GB > limite de 1 Gi. O kernel matava os processos com SIGKILL (OOMKill via cgroup), mas o K8s reportava exitCode: 137 com reason: Error — não OOMKilled — porque o processo morto era um worker filho, não o processo principal.
Confirmação via dmesg:
oom-kill:constraint=CONSTRAINT_MEMCG ... task=celery ... anon-rss:307716kBMemory cgroup out of memory: Killed process ... (celery)Resolução: limitar concorrência explicitamente:
# k8s/deployments.yml — lms-worker e cms-workerargs: - "--concurrency=2"2 workers × 307 MB = ~614 MB, dentro do limite de 1 Gi.
Lição
- Probes HTTP no K8s não enviam
Hostpor padrão. Em Django comALLOWED_HOSTSconfigurado, sempre especificarhttpHeaders. exitCode: 137+reason: Error(nãoOOMKilled) pode ser OOMKill em nível de cgroup. Confirmar comdmesg | grep oom-kill.
Airflow — OutOfSync perpétuo por Helm hooks
Causa raiz
O chart oficial do Airflow cria airflow-fernet-key e airflow-broker-url como Helm pre-install hooks (helm.sh/hook: pre-install). O ArgoCD não inclui hooks no “desired state” regular — por isso esses secrets aparecem como requiresPruning: true.
A cada sync:
- ArgoCD prune os apaga (são
requiresPruning) - O hook pré-sync os recria (possivelmente com valores novos)
- Os Deployments têm annotations
checksum/fernet-keyechecksum/result-backend-secretque mudam junto com os secrets - ArgoCD detecta divergência nas annotations → OutOfSync → loop infinito
Resolução
Adicionar ignoreDifferences para as annotations de checksum nos Deployments em apps/argocd/airflow.yaml:
ignoreDifferences: - group: apps kind: Deployment jqPathExpressions: - .spec.template.metadata.annotations["checksum/airflow-config"] - .spec.template.metadata.annotations["checksum/extra-configmaps"] - .spec.template.metadata.annotations["checksum/extra-secrets"] - .spec.template.metadata.annotations["checksum/jwt-secret"] - .spec.template.metadata.annotations["checksum/metadata-secret"] - .spec.template.metadata.annotations["checksum/pgbouncer-config-secret"] - .spec.template.metadata.annotations["checksum/result-backend-secret"]Requer RespectIgnoreDifferences=true em syncOptions (já estava configurado).
Lição
Charts Helm que usam hooks para criar secrets causam drift perpétuo no ArgoCD. O padrão de ignoreDifferences nas annotations de checksum é a solução oficial recomendada pelo Apache Airflow para deploy via ArgoCD.
Estado final
Após as correções, todos os 17 apps no ArgoCD CPPS: Synced + Healthy.