SSD Nodes Learn 🎉 VPS desde $5.50/mês
Guias Matt ConnorPor Matt Connor

Corrigir machine-id duplicado após clonar uma VPS

Duas VPS clonadas com o mesmo /etc/machine-id podem disputar o lease DHCP. Veja os 4 comandos para regenerar o valor e limpe-o antes do snapshot.

O que é /etc/machine-id e por que uma duplicata é importante

Uma VPS clonada arranca com o mesmo /etc/machine-id do servidor a partir do qual foi clonada, mas esse valor deve pertencer a uma única instalação. A correção consiste em quatro comandos: esvaziar o ficheiro, remover a cópia do D-Bus se for um ficheiro real, gerar um novo valor e reiniciar. O reinício é o passo que as pessoas normalmente ignoram, mas é ele que faz a alteração entrar em vigor.

/etc/machine-id contém uma cadeia hexadecimal minúscula com 32 caracteres e terminada por uma quebra de linha. Depois de descodificada, corresponde a um valor de 16 bytes (128 bits). A página de manual de machine-id(5) chama-lhe confidencial e afirma que não deve ser exposta na rede, porque qualquer pessoa que a leia pode voltar a reconhecer a sua máquina mais tarde. O valor é escrito uma vez, quando o sistema é instalado, e nada o altera depois disso.

Três identificadores costumam ser confundidos neste contexto, por isso convém separá-los. O nome do host é uma etiqueta que escolhe e pode alterar a qualquer momento. O UUID do produto DMI (desktop management interface) em /sys/class/dmi/id/product_uuid vem do hypervisor e só pode ser lido por root. O machine ID é o terceiro: o sistema operativo gera-o e todos os utilizadores da máquina podem lê-lo.

O que efetivamente lê o ID da máquina

O identificador do cliente DHCP. Este é o caso mais problemático. systemd.network(5) documenta ClientIdentifier= na secção [DHCPv4] como tendo duid por predefinição, o que envia um ID de cliente RFC 4361 construído a partir de um IAID e de um DUID (identificador único DHCP). networkd.conf(5) documenta o tipo de DUID predefinido como vendor, no qual o valor do DUID é gerado usando 43793 como identificador do fornecedor (systemd) e um hash do conteúdo do ID da máquina. O DHCPv6 usa o mesmo DUID. Dois clones com o mesmo ID da máquina produzem o mesmo hash do DUID e, se também mantiverem o mesmo nome de interface, enviam um identificador de cliente idêntico byte a byte. O servidor DHCP vê então um cliente em vez de dois e atribui o mesmo lease às duas máquinas. O sintoma é um endereço que muda entre os dois servidores ou um servidor perder o endereço sempre que o outro renova o lease.

journald. Os ficheiros do journal ficam em /var/log/journal/<machine-id>/. O diretório tem literalmente o nome do ID. Se enviar os journals de dois clones para o mesmo coletor, ficam no mesmo diretório e são interpretados como pertencendo ao mesmo host.

D-Bus. /var/lib/dbus/machine-id é o local onde este formato de ficheiro começou. No Debian e no Ubuntu, é um symlink para /etc/machine-id. Em alguns sistemas, é um ficheiro real separado que contém a sua própria cópia. Essa cópia é o problema no procedimento abaixo.

Agentes por host. Os agentes de monitorização, as verificações de licenças, as ferramentas de inventário e os clientes de backup usam frequentemente o ID da máquina como identificador de host predefinido, porque é estável e não requer configuração. Dois servidores a comunicar uma única identidade resultam numa única série de métricas combinada ou numa licença que cobre duas máquinas. Verifique como o seu agente obtém o ID do host, em vez de assumir que usa o hostname.

Como saber se existe uma duplicação

Execute isto nos dois servidores e compare a saída.

cat /etc/machine-id
ls -l /var/lib/dbus/machine-id
sudo cat /sys/class/dmi/id/product_uuid

IDs de máquina idênticos em dois servidores ativos indicam que um foi clonado a partir do outro. hostnamectl imprime o mesmo valor na linha Machine ID: se preferir usar um único comando.

O resultado de ls -l determina o próximo passo. Um link simbólico tem este aspeto:

lrwxrwxrwx 1 root root 15 Aug 21 09:12 /var/lib/dbus/machine-id -> /etc/machine-id

Uma linha que começa com -rw-r--r-- indica que se trata de um ficheiro real que contém a sua própria cópia do ID antigo. Tem de o remover, porque systemd-machine-id-setup lê esse ficheiro antes de fazer qualquer outra coisa.

O UUID do produto também é importante. systemd-machine-id-setup(1) usa primeiro o UUID do KVM e só depois recorre à geração aleatória. Por isso, se o fornecedor atribuiu o mesmo UUID SMBIOS (BIOS de gestão do sistema) aos dois clones, a regeneração produzirá duas vezes o mesmo ID de máquina. UUIDs de produto diferentes nos dois servidores significam que não há nada a corrigir neste aspeto.

Regenerar o ID da máquina numa VPS clonada

A ordem é importante. systemd-machine-id-setup(1) indica que, se já estiver configurado um ID de máquina D-Bus válido para o sistema, esse ID de máquina D-Bus será copiado e usado para inicializar /etc/machine-id. Deixe um /var/lib/dbus/machine-id real no lugar e irá regenerar exatamente o valor que pretendia eliminar.

sudo truncate -s 0 /etc/machine-id
sudo rm -f /var/lib/dbus/machine-id       # only if ls -l showed a real file
sudo systemd-machine-id-setup
sudo ln -sf /etc/machine-id /var/lib/dbus/machine-id
cat /etc/machine-id

É necessário truncar o ficheiro primeiro, porque a ferramenta só atua quando o ficheiro está ausente ou vazio. Não faz nada num ficheiro que já contenha um ID válido. systemd-machine-id-setup informa o que fez na saída de erro padrão. Numa VPS KVM, normalmente verá:

Initializing machine ID from KVM UUID.

Initializing machine ID from random generator. é a mensagem apresentada quando não está disponível nenhum UUID do hipervisor. Qualquer um dos resultados é aceitável, desde que cat /etc/machine-id apresente agora um valor diferente do outro servidor.

O link simbólico mantém o D-Bus e o systemd a usar o mesmo valor. Se preferir um ficheiro real separado, execute sudo dbus-uuidgen --ensure: o comando cria o ficheiro com um novo UUID quando ele não existe. Se o dbus não estiver instalado, não existirá o diretório /var/lib/dbus, ln falhará com No such file or directory e poderá ignorar ambas as linhas.

Depois, reinicie.

sudo reboot

Por que o reboot não é opcional

Todos os processos que já leram o valor antigo continuam a utilizá-lo. sd_id128_get_machine() coloca o ID em cache dentro do processo que o chama, por isso um daemon em execução nunca deteta que o ficheiro mudou. O journald já tem /var/log/journal/<old-id>/system.journal aberto e continua a acrescentar dados ao ficheiro. O systemd-networkd determinou o seu DUID quando arrancou e continua a enviar o identificador de cliente antigo em cada renovação. Normalmente, essa é precisamente a falha que pretende corrigir. O D-Bus também leu o seu ID no arranque. Pode reiniciar os serviços um a um, mas algum ficará por reiniciar. Além disso, o PID 1 também mantém o valor antigo.

Depois do reboot, verifique as duas partes:

cat /etc/machine-id
ls /var/log/journal/

/var/log/journal/ contém agora um segundo diretório com o nome do novo ID, e as novas entradas são gravadas aí. O journalctl simples lê apenas o diretório da máquina atual, por isso o histórico anterior ao clone desaparece da vista predefinida. Continua no disco: journalctl --merge lê todos os diretórios do journal, incluindo o antigo. Elimine o diretório antigo quando tiver a certeza de que já não precisa desses logs.

É também por isso que não pode ensaiar o procedimento num contentor. Um contentor partilha o kernel do host e nunca arranca o seu próprio PID 1, e o reboot é precisamente o objetivo do procedimento. Teste-o da forma como ocorre em produção: clone uma VM, execute os comandos, faça reboot e compare o ID com o da máquina de origem.

Limpe antes de criar o snapshot, não depois de clonar

Corrigir os clones um de cada vez funciona. Corrigir a imagem é melhor, porque todos os servidores restaurados a partir de um snapshot incorreto herdam o mesmo valor. Faça isto como a última tarefa antes de desligar o template.

sudo truncate -s 0 /etc/machine-id
sudo rm -f /var/lib/dbus/machine-id
sudo ln -s /etc/machine-id /var/lib/dbus/machine-id
sudo shutdown -h now

Esvazie o ficheiro. Não o elimine. machine-id(5) recomenda um ficheiro vazio para imagens usadas em várias máquinas, porque um ficheiro vazio no local permite montar um ficheiro temporário com bind sobre o ficheiro real quando a imagem é usada no modo somente leitura. Num /etc somente leitura, o ID gerado no boot fica nesse ficheiro temporário, e systemd-machine-id-setup --commit grava-o quando o filesystem fica gravável.

Há um efeito secundário a considerar: uma machine ID não preenchida faz o próximo boot ser tratado como o primeiro boot. Por isso, as unidades que contêm ConditionFirstBoot=yes são executadas nesse boot e ignoradas em todos os boots seguintes. Veja o que a sua imagem executaria com grep -rl ConditionFirstBoot /usr/lib/systemd/system/ antes de criar o template.

Um template e um snapshot são objetos diferentes, e essa diferença determina se a identidade é copiada. Um template é um artefacto de build que prepara deliberadamente, enquanto um snapshot é uma cópia num determinado momento de um servidor em execução e transporta a identidade desse servidor juntamente com os seus dados.

Por que as imagens cloud acertam nisto e o seu snapshot não

As imagens cloud das distribuições são criadas para serem clonadas. Por isso, são distribuídas sem o machine ID preenchido, e o primeiro arranque preenche esse valor. O cloud-init tem um passo documentado para este caso. cloud-init clean --machine-id define /etc/machine-id como a cadeia literal uninitialized em sistemas systemd. A referência da CLI do cloud-init descreve esta prática como recomendada ao clonar uma golden image. Assim, o arranque seguinte dessa imagem gera um machine ID exclusivo.

Um snapshot criado por si é diferente. O ficheiro já estava preenchido quando criou o snapshot. Por isso, cada servidor restaurado a partir dele mantém esse mesmo valor, e nada no processo de restauro o limpa. Este é o mesmo tipo de problema que mover um servidor em execução para um novo VPS, em que a cópia é fiel e a identidade é a parte que não queria copiar.

O que mais um clone duplica

  • Chaves de host SSH. /etc/ssh/ssh_host_* também é copiado, por isso os dois servidores apresentam a mesma impressão digital aos clientes. Remova esses ficheiros e execute sudo ssh-keygen -A ou sudo dpkg-reconfigure openssh-server no Debian e no Ubuntu. Depois, os seus clientes vão avisar sobre uma chave de host alterada. Esse é o comportamento correto.
  • O nome do host. Defina-o com sudo hostnamectl set-hostname app02 e confirme depois que /etc/hosts continua a resolver o novo nome.
  • Configuração de rede estática. Um clone de uma máquina com um endereço estático entra em conflito com a original assim que é iniciado. Consulte /etc/netplan/ antes de o clone entrar na rede.
  • O relógio. Um snapshot restaurado retoma a hora que tinha quando o snapshot foi criado. Um grande salto no relógio de um VPS restaurado interrompe a validação de certificados TLS e altera a ordem dos logs até a sincronização da hora ser concluída.

Siga também no clone a lista de verificação dos primeiros dez minutos para um VPS novo. Uma máquina clonada herda as contas de utilizador, as chaves SSH, as regras da firewall e os trabalhos agendados da máquina de origem. Nada disso foi analisado para a função que o clone vai desempenhar.

FAQ

Tenho de reiniciar depois de alterar /etc/machine-id?

Sim. Os processos leem o machine ID uma vez e colocam-no em cache, por isso o novo valor não chega a nada que já esteja em execução. O journald continua a escrever no diretório do journal com o nome baseado no ID antigo, e o cliente DHCP continua a enviar um identificador de cliente derivado do valor antigo, que normalmente é a razão da alteração. Reiniciar serviços individuais resolve alguns casos, mas o PID 1 também mantém o valor antigo. Reinicie o servidor e confirme depois com cat /etc/machine-id, comparando o resultado com o outro servidor.

O /etc/machine-id é igual ao UUID do hardware?

Não. O UUID de produto DMI apresentado em /sys/class/dmi/id/product_uuid vem do hypervisor e só pode ser lido por root. O machine ID é gerado pelo sistema operativo e fica num ficheiro simples que qualquer utilizador pode ler. A relação funciona apenas numa direção: num guest KVM, systemd-machine-id-setup usa o UUID do hypervisor para gerar um novo machine ID quando não existe um ID D-Bus para copiar. Se dois clones partilharem o mesmo UUID de produto, vão gerar novamente o mesmo machine ID. Por isso, compare também esse ficheiro antes de confiar no resultado.

Devo eliminar o /etc/machine-id ou deixá-lo vazio?

Deixe-o vazio quando estiver a preparar uma imagem. machine-id(5) prefere um ficheiro vazio, porque o systemd pode fazer bind-mount de um ficheiro temporário sobre ele quando a imagem é executada com um /etc apenas de leitura. Eliminar o ficheiro funciona num sistema com acesso de escrita, e alguns scripts de clonagem fazem isso, mas o ficheiro vazio é a opção predefinida mais segura. O cloud-init escreve a palavra uninitialized no ficheiro com o mesmo objetivo.

Por que razão os meus dois servidores clonados receberam o mesmo endereço DHCP?

Porque ambos enviaram o mesmo identificador de cliente. O systemd-networkd usa ClientIdentifier=duid por predefinição para DHCPv4, e o DUID predefinido é criado a partir de um hash de /etc/machine-id. Assim, machine IDs idênticos produzem identificadores idênticos nos clones que também mantiveram o mesmo nome de interface. O servidor DHCP associa os pedidos a esse identificador, considera ambos como um único cliente e atribui uma única lease. Atribua a cada servidor o seu próprio machine ID e reinicie ambos. Se o servidor continuar a oferecer o endereço antigo, limpe a lease obsoleta diretamente no servidor DHCP.

#machine-id#systemd#cloning#snapshots#dhcp