Ir para o conteúdo

Blogue ·

Reinstalar um contentor é uma substituição

Um contentor não tem disco de modelo nem cloud-init, por isso reinstalar é destruir e voltar a construir. Isso muda o que se deve ao cliente logo à partida.

Por Provibr

Reinstalar uma máquina virtual no Proxmox é quase aborrecido. Pará-la, eliminá-la, clonar o modelo por cima do mesmo identificador e deixar o cloud-init tratar do resto. O modelo transporta um disco e o disco transporta um sistema operativo, por isso «reinstalar» é na verdade «fazer uma cópia nova de uma coisa que se sabe boa».

Um contentor Linux não tem nem uma coisa nem outra. É desempacotado a partir de um tarball e tudo aquilo que é depois disso, os núcleos, a memória, a swap, o tamanho do sistema de ficheiros raiz, a interface de rede, o resolvedor, o nome de anfitrião, vive num ficheiro de configuração no hipervisor e em mais lado nenhum. Não há imagem para clonar por cima. Portanto reinstalar um contentor é destruir seguido de criar e, assim que isso é dito em voz alta, surge um conjunto de obrigações que uma reinstalação de máquina virtual nunca tem.

Foi assim que o construímos, e a parte que demorou mais tempo não foi a de destruir.

Duas fases, porque a plataforma não sabe o que está montado

O fluxo está dividido. A primeira fase apenas lê e não altera nada: o agente vai buscar a configuração do contentor e devolve-a. A segunda fase para, destrói, cria e arranca, usando como precondição aquilo que a primeira fase leu.

A alternativa óbvia é uma só fase com uma pré-visualização construída a partir do que a plataforma já sabe. Aqui isso não está disponível. A inspeção de hardware para contentores não está implementada, porque o analisador que usaria lê chaves de configuração do QEMU, pelo que não existe em lado nenhum da nossa base de dados um retrato guardado dos pontos de montagem de um contentor. Uma pré-visualização que rotula todos os pontos de montagem como «desconhecido» não é uma pré-visualização, é uma declaração de desresponsabilização.

Cinco palavras para o que acontece aos dados

Cada ponto de montagem da configuração recebe exatamente um rótulo, e o rótulo é sobre os dados, não sobre a montagem.

RótuloSignificado
erasedo volume é destruído juntamente com o contentor; o sistema de ficheiros raiz, sempre
excludedo volume pertence a outro convidado, por isso o Proxmox salta-o e nada é tocado
externally_managedum bind mount, um caminho do anfitrião; o diretório sobrevive, a montagem não volta
unknowna linha não pôde ser lida, e este é o único rótulo que bloqueia a operação inteira
preservedos dados ficam e a montagem regressa

A última linha está na lista e nunca é produzida. Manter um volume ao longo de uma destruição significa desanexá-lo, eliminar o contentor sem recolher os discos sem referência e voltar a anexá-lo depois: três passos cujo passo do meio, ao falhar, deixa um volume de que já ninguém é dono. Isso é um trabalho à parte, com o seu próprio ciclo de limpeza. O valor existe no vocabulário para que uma versão posterior não tenha de o arrumar em silêncio sob outro nome, uma função declara que ainda não é oferecido, e um teste afirma que o classificador nunca o devolve.

A distinção importante é a da primeira frase. Um ponto de montagem pode ver os seus dados sobreviverem e mesmo assim não regressar, porque a chamada de criação que enviamos só define o sistema de ficheiros raiz. Todas as outras montagens desaparecem do contentor novo, independentemente do que aconteceu aos seus bytes. Trocar isto ao contrário produz a frase mais perigosa de toda esta funcionalidade: preserved ao lado de uma montagem que depois não vai existir.

A posse está no identificador de volume

O Proxmox escreve um volume numa de duas formas, e ambas dizem de que convidado ele é. local-lvm:vm-5001-disk-0 e local:5001/vm-5001-disk-0.raw pertencem os dois ao contentor 5001. Um bind mount não é nenhuma das duas: é um caminho absoluto, e a barra inicial é aquilo que o próprio Proxmox testa.

Essa leitura decide entre excluded e erased. Um ponto de montagem na configuração deste contentor que aponta para o volume de outro convidado é saltado pela destruição, porque o Proxmox verifica a posse, pelo que esses dados não são apagados. Sem a comparação, a pré-visualização diria erased sobre dados que ficam. Alguém iria depois repor uma cópia de segurança de que não precisava, o que é um desastre menor do que o inverso mas ainda assim causado por nós.

A pré-visualização é uma precondição, não um retrato

Aquilo que o cliente viu viaja de volta com o comando de aplicação, como uma lista de confirmações, e o agente lê a configuração outra vez imediatamente antes de destruir. Se ela diferir, um ponto de montagem acrescentado, um volume diferente sob a mesma chave, recusa.

Entre a pré-visualização e o clique está um ser humano e, nesse intervalo, um administrador pode anexar um disco na interface do Proxmox. «Os bind mounts e os pontos de montagem geridos pelo anfitrião não fazem parte automaticamente de uma reinstalação» só é verdade se alguma coisa o impuser.

Cada confirmação é uma chave e um volume, e deliberadamente não o rótulo. O rótulo é o juízo da plataforma e não tem nada para decidir na outra ponta; se fosse entregue ao agente como parte daquilo com que ele compara, haveria um ramo que escolhia com base nele, e então as regras viveriam em dois sítios. O rótulo é registado à mesma, ao lado das confirmações no registo do comando e na linha de intenção, porque esse é o lado da auditoria, e aí deve dizer exatamente o que foi mostrado ao cliente.

Só crescer, comparado em bytes, mostrado em gibibytes

Uma reinstalação não pode encolher o sistema de ficheiros raiz. A comparação corre sobre bytes e o ecrã arredonda para cima, para gibibytes inteiros.

Arredondar para cima é a direção conservadora, e o contraexemplo diz porquê. Arredonde-se 8,5 GiB para baixo, para «8 GiB» no ecrã, aceite-se contra isso um pedido de 8 GiB, e desaparece meio gibibyte que ninguém pediu para perder. Medido contra um Proxmox reconstruído, um contentor a comunicar 16 GiB em que o plano pedia 8 foi recusado.

Há uma armadilha uma camada abaixo desta. O Proxmox escreve os tamanhos como 8G, 512M ou como um número simples, e um número simples são kibibytes. Lido como bytes, 8388608 são 8 MiB; lido corretamente são 8 GiB. Um analisador que se engane aqui não lança erro nenhum, limita-se a aprovar todos os encolhimentos que alguma vez lhe mostrem.

Nove razões para recusar

Antes de acontecer o que quer que seja de irreversível há nove bloqueios com nome: o contentor desapareceu, protection=1 está definido, o Proxmox tem um bloqueio sobre o convidado, uma das nossas próprias tarefas de cópia de segurança ou de restauro está a correr, existe um ponto de restauro protegido, o sistema de ficheiros raiz encolheria, o seu tamanho atual não pôde ser lido, um ponto de montagem não pôde ser classificado, ou já há uma reinstalação em curso.

Cada um é um valor tipado com a sua própria frase traduzida em nove idiomas, pelo que uma razão que não esteja na lista não pode ter uma. São verificados duas vezes do nosso lado, uma quando a pré-visualização é desenhada e outra quando o botão de confirmação é premido, e uma terceira vez pelo agente contra a configuração que ele próprio lê. Três fechos, porque este é o passo irreversível do capítulo.

A palavra-passe de root é pedida na segunda fase e não na primeira, e viaja como dado transitório em vez de ser guardada. Um segredo que se escreve mesmo antes do passo irreversível não passa meia hora pousado num separador do navegador.

Precisa de reconciliação é o terceiro desfecho, e mantém o bloqueio

Se alguma coisa falhar entre a destruição e a criação, a execução não passa a «falhada». Passa a «precisa de reconciliação», levando consigo o identificador do contentor, o passo em que morreu e se o contentor ainda existia quando o agente desistiu. Esse último campo pode ser null, e null não é false: «não consegui determinar» não pode ler-se como «o identificador está livre».

Se uma falha é ou não destrutiva é derivado da posição do passo na lista ordenada de etapas, a partir da destruição. É por isso que as etapas são uma lista e não um conjunto de textos soltos: a pergunta «já tinha acontecido alguma coisa irreversível» é respondida exatamente num sítio.

Uma execução nesse estado mantém fechado o bloqueio sobre o servidor. Começar uma segunda substituição num identificador onde ninguém sabe se está pousado um contentor é precisamente aquilo que este desenho proíbe, e tem de ser uma pessoa a encerrar o caso.

Quem perde um compare and swap tem de voltar a ler

Não há nenhum trabalhador a atualizar estas linhas. O estado avança quando alguém o lê: a leitura olha para o comando a que a intenção está presa e faz a linha avançar, com um compare and swap sobre um contador de geração, pelo que dois leitores em simultâneo executam em conjunto cada transição exatamente uma vez.

Isso foi desenhado. O que não foi desenhado, e o que o teste de navegador apanhou, é o que deve devolver quem perde essa troca.

O painel consulta uma vez por segundo depois de uma pré-visualização ser pedida, e essa consulta executa a mesma transição. Se o cliente carregar a página nesse mesmo segundo, a consulta ganha a troca, a página devolve a sua própria linha, agora desatualizada, e o ecrã continua a dizer «à espera do agente» enquanto a pré-visualização já está na base de dados. Uma navegação, um pedido, e um ecrã a mostrar um estado que já não existia. Só um segundo recarregamento resolvia.

A correção tem uma frase e vale a pena interiorizá-la: perder um compare and swap significa, por construção, que outra pessoa acabou de fazer exatamente a transição que se queria. A resposta correta é portanto a linha dessa outra pessoa, e custa um select. Devolver a própria é o que a intuição manda fazer e está sempre errado.

O que registaríamos

  1. Se aquilo que se substitui não tem imagem, chame-lhe uma substituição. A palavra muda o que se deve ao cliente antes de se começar.
  2. Rotule os dados e a montagem em separado. São duas perguntas, e juntar uma resposta verdadeira a uma com uma resposta falsa à outra é o pior resultado que o sistema consegue produzir.
  3. Faça a pré-visualização viajar de volta como condição, releia-a na outra ponta e recuse a qualquer diferença. Houve um ser humano a carregar pelo meio.
  4. Arredonde de forma conservadora quando um erro de arredondamento só pode destruir.
  5. Dê a uma operação destrutiva a meio um estado próprio, mantenha o bloqueio fechado e nunca a deixe cair em sucesso nem em falha.
  6. Volte a ler depois de perder um compare and swap, sempre.

O suporte a contentores no Proxmox está a ser lançado por etapas, e a reinstalação fica tarde nessa ordem pelas razões acima. Para quem está mais cedo nessa sequência, as vantagens e desvantagens entre os dois tipos de convidado estão em VM ou contentor no Proxmox, e a razão pela qual uma chamada de API bem sucedida não é um trabalho terminado está em porque um 200 do Proxmox não é um resultado.

Do trabalho de Proxmox no Provibr.

Comece com um host e um agente

Crie uma conta, instale o agente com um único comando e ligue o seu primeiro host Proxmox. O período experimental dura 14 dias e não pede quaisquer dados de pagamento.