Skip to content

v0.41.0 — um pod voltava do respawn do holder sem rede, em silêncio

Choose a tag to compare

@github-actions github-actions released this 05 Aug 08:09
· 12 commits to main since this release

v0.41.0 — um pod voltava do respawn do holder sem rede, em silêncio

Continuação directa da v0.40.0, que trouxe pods e VMs para dentro do isolamento
de namespace. Trazê-los para dentro tornou visível a pergunta seguinte: e quando
o holder morre e volta?

A resposta, medida antes de escrever código:

recovered 1 container(s) stranded by the previous holder (restarted)

pa-c0   Up 32 seconds   →  ping: Network unreachable

O container foi recuperado. O pod ficou vivo, sem rede, sem a sua chain de
isolamento, e sem uma linha a dizê-lo. Uma recuperação que reporta sucesso
por cima de um workload que acabou de abandonar é pior do que uma que não faz
nada — porque a primeira é lida como "está tratado".

A raiz: a associação ao pod nunca era persistida

Container tem um campo pod desde sempre. O describe sempre o imprimiu.
Nada alguma vez lho atribuiu — o único traço de pertença em disco era uma
label. É a quarta vez que este repositório paga exactamente esta armadilha (o
-v não persistido, o -p numa rede custom, as redes extra perdidas no
restart), e a regra continua a mesma: estado necessário para RECONSTRUIR o
recurso tem de ser persistido, não só usado uma vez na criação.

Duas consequências, ambas reproduzidas:

  • container describe num membro de pod não mostrava pod nenhum;
  • container restart de um membro morria com clone failed: EPERM e deixava-o
    Dead, sem caminho de volta — o cmd_start reconstrói o spec a partir do
    registo e não tinha como saber que devia re-entrar na netns partilhada.

O que passou a funcionar

  • container restart de um membro de pod volta a entrar na netns do pod,
    com o mesmo IP, sem tocar nos peers. Se a netns já não existir (o holder foi
    substituído), é recriada — com a namespace do membro, portanto o isolamento
    volta com ela.
  • Um respawn do holder recupera pods como já recuperava containers.

Dois bugs apanhados pelo caminho, ambos só visíveis ao vivo

reexec_start ignorava o seu próprio parâmetro netns e usava o id.
Funcionava por coincidência: o único chamador passava um netns igual ao id. Um
membro de pod é o primeiro caso em que diferem — com o código antigo teria
tentado entrar numa netns com o nome do container, que não existe. Mesma família
dos ajudantes públicos, mortos e com defeito à espera do primeiro chamador que
este repo já teve de apagar duas vezes. O caminho de falha ganhou também um
owns_netns: só se desmonta uma netns que seja nossa — a de um pod é partilhada,
e derrubá-la porque um membro não voltou tiraria a rede aos outros.

A guarda de idempotência da recuperação estava a saltar membros. Perguntava,
dentro do ciclo, «o holder serve esta netns?» — e a resposta passa a sim assim
que o primeiro membro recupera, pelo que todos os seguintes eram tratados
como saudáveis enquanto continuavam dentro da netns morta. Foi a primeira versão
desta correcção, e só um pod de dois containers a mostrou:

recovered 2 container(s)     pa-c0 → Network unreachable

A pergunta passou a ser feita uma vez, antes do ciclo. Aí é a pergunta certa:
no início da passagem, ou o holder servia a netns do pod (nada morreu — saltam-se
todos os membros) ou não servia (estão todos encalhados — reiniciam-se todos).
Para um container, cuja netns é só sua, snapshot e consulta ao vivo são
equivalentes.

Validação

Ao vivo, no sandbox isolado: restart de um membro com um peer a correr (o peer
não perde um pacote, o membro volta ao mesmo IP do pod); respawn do holder com um
pod de dois membros + um container em rede custom — os três recuperados, os
dois membros no mesmo IP, e o isolamento reconstruído (cross-namespace bloqueado
nos dois sentidos, mesmo-pod aberto).

Cenário de caos novo (pod_holder_respawn), deliberadamente com dois
containers no pod: com um só, a guarda partida ainda passava. Falha com a
correcção revertida (c0=down c1=down) e passa com ela. Arnês completo:
16 PASS · 0 FAIL · 0 SKIP.

Ainda em aberto

A recuperação continua a ser por reinício, não por adopção: adoptar a netns
viva para dentro do holder novo é impossível no kernel em rootless (ip netns attach precisa de CAP_SYS_ADMIN sobre o userns do holder que morreu), e isso
está medido e documentado desde a v0.39. VMs continuam fora da reconciliação — o
tap morre com o holder e nada o repõe.