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.
systemdfalha sob--checkna 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 (packageoucopy) 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, nofirewallde noself-pull-timer, mesma causa, mesma correção (ignore_errors: "{{ ansible_check_mode }}"). Ver a explicação genérica em Modo--check.firewall-cmdtrava esperando o D-Bus/polkit ficar pronto: a task original só conferiasystemd: state=starteddo firewalld, sem esperar a autorização de D-Bus ficar disponível de verdade. Descoberto rodando o role contra umfirewalldreal via Molecule (ver por que este role não tem um scenario Molecule), corrigido comretries/untilnuma task dedicada, mantido no role mesmo depois do scenario de teste ter sido descartado.argocd app list --corefalha comconfigmap "argocd-cm" not found: o--corefala direto com a API do Kubernetes usando o namespace do contexto atual dokubectl, não assumeargocdsozinho. Semkubectl config set-context --current --namespace=argocdprimeiro, ele procuraargocd-cmno 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 --reloadcontra 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% (nodesReady, todos os apps do Argo CDSynced, 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 nodeseargocd 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 firewallde--tags self-pull-timeruma segunda vez, de verdade, resultou emchanged=0nos 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.