Pular para conteúdo

Lições do bootstrap

O bootstrap completo do node ldsa (os 10 itens do checklist) rodou de ponta a ponta em produção em 2026-08-21, com Ansible e Argo CD validados de verdade, não só em teoria. Esta página reúne o que deu certo e o que precisou de correção no caminho, pra quem for reprovisionar este node ou provisionar um novo não repetir a mesma descoberta.

Erros reais, encontrados só contra o node de verdade

Nenhum dos três bugs abaixo apareceu em lint (ansible-lint/yamllint) nem tinha como aparecer: os três só existem quando o role roda contra um systemd real, num host que ainda não tem o pacote/serviço instalado.

  • systemd falha sob --check na primeira execução de um role: as tasks que habilitam/iniciam uma unit (ansible.builtin.systemd) consultam o estado real do systemd mesmo sob --check, então se a task anterior (package ou copy) só simulou a instalação, a unit genuinamente não existe e o módulo falha com erro fatal em vez de simular. Apareceu duas vezes, no firewalld e no self-pull-timer, mesma causa, mesma correção (ignore_errors: "{{ ansible_check_mode }}"). Ver a explicação genérica em Modo --check.
  • firewall-cmd trava esperando o D-Bus/polkit ficar pronto: a task original só conferia systemd: state=started do firewalld, sem esperar a autorização de D-Bus ficar disponível de verdade. Descoberto rodando o role contra um firewalld real via Molecule (ver por que este role não tem um scenario Molecule), corrigido com retries/until numa task dedicada, mantido no role mesmo depois do scenario de teste ter sido descartado.
  • argocd app list --core falha com configmap "argocd-cm" not found: o --core fala direto com a API do Kubernetes usando o namespace do contexto atual do kubectl, não assume argocd sozinho. Sem kubectl config set-context --current --namespace=argocd primeiro, ele procura argocd-cm no namespace errado. Documentado no passo 8 do bootstrap.

O que foi tentado e descartado

Um scenario Molecule completo foi escrito pro firewalld (Docker com systemd real, imagem geerlingguy/docker-debian12-ansible) e chegou a convergir o role inteiro com sucesso, expondo a race de D-Bus/polkit acima no processo. Mas a fragilidade documentada do polkit dentro de um container aninhado (Ansible#36483, systemd#13955) tornava o tempo de execução do teste inconsistente. Decisão: manter a correção real no role, descartar o scenario de teste, confiar na verificação manual supervisionada que já é exigida pra essa mudança (ver passo 8). Raciocínio completo em firewalld.

O que deu certo

  • O restart condicional do k3s funcionou como projetado: o issue #7542 do k3s documenta que firewall-cmd --reload contra um k3s já ativo há muito tempo flusha regras de iptables que só se recuperam parcialmente sozinhas. O role reiniciou o k3s uma única vez, só porque houve mudança real de configuração (não em toda execução idempotente), e o cluster recuperou 100% (nodes Ready, todos os apps do Argo CD Synced, nenhum pod com restart inesperado). Ver por que o role reinicia o k3s depois do reload.
  • O dead man switch nunca precisou disparar: armado antes da execução real do firewalld, cancelado manualmente depois de conferir SSH, kubectl get nodes e argocd app list --core, exatamente o fluxo descrito no passo 8 do bootstrap. A rede de segurança existiu, mas não foi necessária, o que é o resultado desejado, não um sinal de que era dispensável.
  • A idempotência real bateu com a esperada: rodar --tags firewalld e --tags self-pull-timer uma segunda vez, de verdade, resultou em changed=0 nos dois, confirmando que o padrão query-then-act usado no repositório inteiro (conferir o estado atual antes de decidir se aplica, ver Idempotência na prática) funciona contra o sistema real, não só na teoria dos lints.

Efeito colateral do firewalld revisado e aceito, não uma regressão

Ativar o firewalld também bloqueou o acesso público direto às portas NodePort dos serviços de dados (ver foundation): a zona pública só libera 22/80/443, confirmado com firewall-cmd --zone=public --list-all e uma tentativa real de conexão de fora resultando em "connection refused". Antes de assumir que era um bug a corrigir, essa mudança de comportamento foi levada de volta pra decisão humana: banco de dados e storage expostos direto na internet pública é risco desnecessário, o acesso administrativo a essas portas deveria vir só pela malha ZeroTier (zona trusted), não da zona pública. Confirmado como o comportamento correto, não uma regressão a reverter. Registrado aqui porque o efeito só apareceu ao investigar outra coisa (a migração de Postgres pro CloudNativePG), não porque alguém tinha pensado nisso durante o passo 8.