SSD Nodes Learn Hosting plans →
Przewodniki Matt ConnorAutor: Matt Connor

Jak naprawić zduplikowany machine-id po klonowaniu VPS

Zduplikowany plik /etc/machine-id powoduje konflikty w dzierżawie DHCP. Dowiedz się, jak bezpiecznie zregenerować identyfikator i poprawnie przygotować obraz systemu do klonowania.

Czym jest /etc/machine-id i dlaczego duplikaty stanowią problem

Sklonowany VPS uruchamia się z tym samym /etc/machine-id, co serwer źródłowy, podczas gdy wartość ta powinna być unikalna dla każdej instalacji. Rozwiązanie wymaga wykonania czterech poleceń: opróżnienia pliku, usunięcia kopii D-Bus, jeśli jest ona zwykłym plikiem, wygenerowania nowej wartości i restartu. Restart jest krokiem często pomijanym, a to właśnie on sprawia, że zmiany wchodzą w życie.

/etc/machine-id przechowuje 32-znakowy ciąg szesnastkowy zakończony znakiem nowej linii. Po zdekodowaniu jest to wartość 16-bajtowa (128-bitowa). Strona podręcznika systemowego machine-id(5) określa ten identyfikator jako poufny i wskazuje, że nie powinien być on ujawniany w sieci, ponieważ każdy podmiot, który go odczyta, może później zidentyfikować daną maszynę. Wartość ta jest zapisywana jednorazowo podczas instalacji systemu i nie zmienia się w późniejszym czasie.

W tym kontekście często mylone są trzy rodzaje identyfikatorów, dlatego warto je rozróżnić. Nazwa hosta (hostname) to etykieta, którą użytkownik wybiera i może w dowolnym momencie zmienić. Identyfikator produktu DMI (desktop management interface) w /sys/class/dmi/id/product_uuid pochodzi z hypervisora i jest dostępny do odczytu tylko dla użytkownika root. Identyfikator maszyny (machine ID) jest trzecim z nich: generuje go system operacyjny i każdy użytkownik w systemie może go odczytać.

Co faktycznie odczytuje machine ID

Identyfikator klienta DHCP. To najbardziej problematyczny element. ClientIdentifier= w sekcji [DHCPv4] pliku .network korzysta z wartości ustawionej w networkd.conf(5), która domyślnie przyjmuje duid: identyfikator klienta zgodny z RFC 4361, zbudowany z IAID oraz DUID (DHCP unique identifier). networkd.conf(5) definiuje domyślny typ DUID jako vendor, gdzie wartość DUID jest generowana przy użyciu 43793 jako identyfikatora producenta (systemd) oraz haszowanej zawartości machine ID. DHCPv6 używa tego samego DUID. Dwie sklonowane maszyny z tym samym machine ID generują ten sam DUID, a jeśli zachowają tę samą nazwę interfejsu, wysyłają identyczny bajtowo identyfikator klienta. Serwer DHCP rozpoznaje wtedy jednego klienta zamiast dwóch i oferuje obu maszynom ten sam dzierżawiony adres. Objawia się to adresem IP "wędrującym" między serwerami lub utratą adresu przez jeden serwer w momencie odnowienia dzierżawy przez drugi.

journald. Pliki dziennika znajdują się w /var/log/journal/<machine-id>/. Katalog jest nazwany bezpośrednio identyfikatorem. Przesłanie dzienników z dwóch klonów do jednego kolektora spowoduje ich zapisanie w jednym katalogu i odczytanie jako dane z jednego hosta.

D-Bus. /var/lib/dbus/machine-id to miejsce, w którym ten format pliku powstał. W systemach Debian i Ubuntu jest to dowiązanie symboliczne do /etc/machine-id. W niektórych systemach jest to osobny, rzeczywisty plik przechowujący własną kopię, a ta kopia stanowi pułapkę w poniższej procedurze.

Agenci działający na hoście. Agenci monitorujący, mechanizmy weryfikacji licencji, narzędzia inwentaryzacyjne oraz klienci kopii zapasowych często używają machine ID jako domyślnego identyfikatora hosta, ponieważ jest on stabilny i nie wymaga konfiguracji. Dwa serwery zgłaszające tę samą tożsamość oznaczają scalone serie metryk lub jedną licencję przypisaną do dwóch maszyn. Należy sprawdzić, w jaki sposób agent wyznacza identyfikator hosta, zamiast zakładać, że używa on nazwy hosta (hostname).

Jak sprawdzić, czy występuje duplikat

Uruchom poniższe polecenie na obu serwerach i porównaj wyniki.

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

Identyczne identyfikatory maszyn na dwóch działających serwerach oznaczają, że jeden został sklonowany z drugiego. hostnamectl wyświetla tę samą wartość w linii Machine ID:, jeśli preferowane jest użycie jednego polecenia.

Wynik ls -l determinuje dalsze kroki. Dowiązanie symboliczne wygląda następująco:

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

Linia rozpoczynająca się od -rw-r--r-- oznacza, że jest to rzeczywisty plik zawierający własną kopię starego identyfikatora. Należy go usunąć, ponieważ systemd-machine-id-setup odczytuje go przed sprawdzeniem UUID hypervisora lub generatora liczb losowych.

Istotny jest również UUID produktu. systemd-machine-id-setup(1) używa UUID KVM przed przejściem do generowania losowego, więc jeśli dostawca nadał obu klonom ten sam UUID SMBIOS (system management BIOS), ponowne wygenerowanie identyfikatora spowoduje uzyskanie tej samej wartości. Różne UUID produktów na obu maszynach oznaczają, że w tym zakresie nie ma powodów do obaw.

Generowanie nowego identyfikatora maszyny na sklonowanym VPS

Kolejność działań ma znaczenie. systemd-machine-id-setup(1) stanowi, że jeśli w systemie skonfigurowano już poprawny identyfikator maszyny D-Bus, jest on kopiowany i używany do inicjalizacji /etc/machine-id. Pozostawienie istniejącego pliku /var/lib/dbus/machine-id spowoduje wygenerowanie tej samej wartości, którą próbowano usunąć.

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

Wcześniejsze wyczyszczenie zawartości pliku jest wymagane, ponieważ narzędzie działa tylko wtedy, gdy plik nie istnieje lub jest pusty; w przypadku pliku zawierającego poprawny identyfikator narzędzie nie podejmuje żadnych działań. systemd-machine-id-setup raportuje wykonane operacje na standardowe wyjście błędów. Na serwerze KVM VPS z systemd w wersji 258 lub nowszej zazwyczaj widoczny jest komunikat:

Initializing machine ID from SMBIOS/DMI UUID.

W systemd 255 ten sam krok jest opisywany jako Initializing machine ID from VM UUID.. Initializing machine ID from random generator. to komunikat wyświetlany, gdy identyfikator UUID hypervisora jest niedostępny. Oba wyniki są poprawne, o ile cat /etc/machine-id zwraca teraz wartość inną niż na pozostałych serwerach.

Dowiązanie symboliczne zapewnia spójność wartości dla D-Bus i systemd. Jeśli preferowane jest użycie osobnego pliku, należy wykonać sudo dbus-uuidgen --ensure: polecenie to utworzy plik z nowym identyfikatorem UUID, jeśli plik jeszcze nie istnieje. Jeśli pakiet dbus nie jest zainstalowany, katalog /var/lib/dbus nie istnieje, ln kończy się błędem No such file or directory i oba te wiersze można pominąć.

Następnie należy wykonać restart systemu.

sudo reboot

Dlaczego restart nie jest opcjonalny

Każdy proces, który odczytał już starą wartość, nadal z niej korzysta. sd_id128_get_machine() buforuje ID wewnątrz procesu wywołującego, więc działający demon nigdy nie zauważy zmiany pliku. journald ma już otwarte /var/log/journal/<old-id>/system.journal i stale dopisuje do niego dane. systemd-networkd wyznaczył swój DUID podczas uruchomienia i przy każdym odnowieniu wysyła stary identyfikator klienta, co zazwyczaj jest dokładnie tą awarią, którą użytkownik zamierza naprawić. D-Bus również odczytał swoje ID podczas startu. Można restartować usługi pojedynczo, jednak zawsze pominie się którąś z nich, a PID 1 również przechowuje starą wartość.

Po restarcie należy sprawdzić obie części:

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

/var/log/journal/ zawiera teraz drugi katalog nazwany zgodnie z nowym ID, do którego trafiają nowe wpisy. Standardowe journalctl odczytuje tylko katalog bieżącej maszyny, więc historia sprzed klonowania znika z domyślnego widoku. Dane nadal znajdują się na dysku: journalctl --merge odczytuje każdy katalog dziennika, w tym ten stary. Należy usunąć stary katalog, gdy pewność co do braku potrzeby korzystania z tych logów zostanie potwierdzona.

Jest to również powód, dla którego kontener nie jest właściwym miejscem do przećwiczenia tej procedury. Kontener współdzieli jądro systemu hosta. Może uruchomić systemd jako własny PID 1, ale nigdy nie uruchamia własnego jądra, a wewnątrz kontenera systemd-machine-id-setup inicjuje ID na podstawie UUID menedżera kontenerów, a nie UUID hypervisora, którego używa VPS. Procedurę należy przetestować w sposób odpowiadający środowisku produkcyjnemu: sklonować maszynę wirtualną, wykonać polecenia, zrestartować system, a następnie porównać ID z maszyną źródłową.

Wyzeruj plik przed wykonaniem migawki, a nie po klonowaniu

Naprawianie każdego klona z osobna jest skuteczne. Lepszym rozwiązaniem jest jednak poprawienie obrazu, ponieważ każdy serwer przywrócony z błędnej migawki dziedziczy ten sam identyfikator. Należy wykonać tę czynność jako ostatnią przed wyłączeniem szablonu.

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

Opróżnij plik. Nie usuwaj go. machine-id(5) zaleca pozostawienie pustego pliku w obrazach używanych na wielu maszynach. Pusty plik w docelowym miejscu pozwala na zamontowanie (bind-mount) tymczasowego pliku na istniejący, gdy obraz jest używany w trybie tylko do odczytu. Na systemie plików /etc w trybie tylko do odczytu, identyfikator wygenerowany podczas rozruchu jest zapisywany w tym tymczasowym pliku, a systemd-machine-id-setup --commit utrwala go, gdy system plików staje się zapisywalny.

Skutek uboczny zależy od stanu, w jakim pozostawisz plik. Dokumentacja machine-id(5) jasno wskazuje, że jeśli /etc/machine-id istnieje i jest pusty, rozruch nie jest uznawany za pierwszy, więc powyższy pusty plik nie uruchamia jednostek zawierających ConditionFirstBoot=yes. Brak pliku lub plik zawierający ciąg uninitialized sprawia, że kolejny rozruch jest traktowany jako pierwszy: jednostki te są uruchamiane, a systemd stosuje również ustawienia domyślne (presets). Przed utworzeniem szablonu sprawdź, co zostanie uruchomione w obrazie za pomocą polecenia grep -rl ConditionFirstBoot /usr/lib/systemd/system/.

Szablon i migawka to różne obiekty, a różnica ta decyduje o tym, czy tożsamość zostanie skopiowana. Szablon to artefakt kompilacji przygotowywany celowo, podczas gdy migawka jest kopią działającego serwera w określonym punkcie czasowym i przenosi tożsamość tego serwera wraz z jego danymi.

Dlaczego obrazy chmurowe radzą sobie z tym poprawnie, a własne migawki nie

Dystrybucyjne obrazy chmurowe są przygotowane do klonowania, dlatego są dostarczane z pustym identyfikatorem maszyny, który jest uzupełniany przy pierwszym uruchomieniu. Narzędzie cloud-init posiada udokumentowany krok przeznaczony dokładnie do tego celu. cloud-init clean --machine-id ustawia /etc/machine-id na ciąg znaków uninitialized w systemach z systemd, a dokumentacja CLI cloud-init wskazuje to jako najlepszą praktykę przy klonowaniu obrazu wzorcowego, dzięki czemu kolejne uruchomienie tego obrazu generuje unikalny machine ID.

Własna migawka działa inaczej. Plik był już uzupełniony w momencie tworzenia migawki, więc każdy serwer przywrócony z niej posiada tę samą wartość, a proces przywracania nie czyści tego pola. Jest to ten sam rodzaj problemu, co przenoszenie działającego serwera na nowy VPS, gdzie kopia jest wierna, a tożsamość jest elementem, którego nie chciano kopiować.

Co jeszcze powiela klonowanie

  • Klucze hosta SSH. Plik /etc/ssh/ssh_host_* również jest kopiowany, przez co oba serwery prezentują klientom ten sam odcisk klucza. Należy usunąć te pliki i wykonać sudo ssh-keygen -A lub sudo dpkg-reconfigure openssh-server w systemach Debian i Ubuntu. Klienci otrzymają ostrzeżenie o zmianie klucza hosta, co jest prawidłowym zachowaniem.
  • Nazwa hosta. Należy ją ustawić za pomocą sudo hostnamectl set-hostname app02, a następnie sprawdzić, czy /etc/hosts nadal poprawnie rozpoznaje nową nazwę.
  • Statyczna konfiguracja sieci. Klon maszyny ze statycznym adresem IP wywoła konflikt z oryginałem w momencie połączenia z siecią. Przed podłączeniem klona do sieci należy zapoznać się z /etc/netplan/.
  • Zegar systemowy. Przywrócona migawka wznawia pracę z czasem, który obowiązywał w momencie jej wykonania. Duży skok czasu na przywróconym VPS powoduje błędy walidacji certyfikatów TLS i zaburza kolejność wpisów w dziennikach, dopóki synchronizacja czasu nie zostanie zakończona.

Na sklonowanej maszynie należy również wykonać listę kontrolną pierwszych dziesięciu minut dla nowego VPS. Klon dziedziczy konta użytkowników, klucze SSH, reguły zapory sieciowej oraz zaplanowane zadania z serwera źródłowego, a żadne z nich nie zostało zweryfikowane pod kątem nowego przeznaczenia klona.

FAQ

Czy po zmianie /etc/machine-id konieczny jest restart?

Tak. Procesy odczytują identyfikator maszyny jednokrotnie i przechowują go w pamięci podręcznej, więc nowa wartość nie dotrze do już uruchomionych usług. journald kontynuuje zapis do katalogu dziennika nazwanego według starego identyfikatora, a klient DHCP nadal wysyła identyfikator klienta wygenerowany na podstawie starej wartości, co zazwyczaj jest powodem zmiany. Restartowanie poszczególnych usług rozwiązuje problem tylko częściowo, ponieważ PID 1 również przechowuje starą wartość. Należy wykonać restart, a następnie potwierdzić zmianę za pomocą cat /etc/machine-id oraz porównując wynik z drugim serwerem.

Czy /etc/machine-id to to samo co UUID sprzętowy?

Nie. UUID produktu DMI w /sys/class/dmi/id/product_uuid pochodzi z hypervisora i jest dostępny do odczytu tylko dla użytkownika root. Identyfikator maszyny jest generowany przez system operacyjny i znajduje się w zwykłym pliku, który może odczytać każdy użytkownik. Są one powiązane jednostronnie: na gościu KVM, systemd-machine-id-setup inicjuje nowy identyfikator maszyny na podstawie UUID hypervisora, jeśli nie ma dostępnego identyfikatora D-Bus do skopiowania. Jeśli dwa klony współdzielą ten sam UUID produktu, wygenerują ten sam identyfikator maszyny, dlatego przed uznaniem wyniku za wiarygodny należy porównać również ten plik.

Czy należy usunąć /etc/machine-id, czy pozostawić go pustym?

Podczas przygotowywania obrazu plik należy pozostawić pusty. machine-id(5) preferuje pusty plik, ponieważ systemd może wykonać montowanie typu bind-mount pliku tymczasowego w jego miejsce, gdy obraz działa z systemem plików /etc w trybie tylko do odczytu. Usunięcie pliku działa w systemach z możliwością zapisu i niektóre skrypty klonowania stosują tę metodę, jednak pusty plik jest bezpieczniejszym ustawieniem domyślnym. cloud-init wpisuje słowo uninitialized do pliku. Ta wartość, podobnie jak brak pliku, sprawia, że kolejny rozruch jest traktowany jako pierwszy, więc jednostki z ConditionFirstBoot=yes zostaną uruchomione. Pusty plik nie wywołuje tego zachowania.

Dlaczego dwa sklonowane serwery otrzymały ten sam adres DHCP?

Ponieważ oba wysłały ten sam identyfikator klienta. systemd-networkd domyślnie używa ClientIdentifier=duid dla DHCPv4, a domyślny DUID jest tworzony na podstawie skrótu /etc/machine-id, więc identyczne identyfikatory maszyn generują identyczne identyfikatory klienta na klonach, które zachowały tę samą nazwę interfejsu. Serwer DHCP dopasowuje żądania na podstawie tego identyfikatora, traktuje oba żądania jako jednego klienta i przydziela jedną dzierżawę. Należy nadać każdej maszynie unikalny identyfikator maszyny i zrestartować obie. Jeśli serwer nadal oferuje stary adres, należy usunąć nieaktualną dzierżawę bezpośrednio na serwerze DHCP.

Czy ten artykuł był przydatny?

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