VPS 복제 후 중복된 machine-id 해결 및 재생성 방법
복제된 VPS가 동일한 /etc/machine-id를 사용하면 DHCP 임대 충돌이 발생합니다. 시스템 안정성을 위해 machine-id를 안전하게 삭제하고 재생성하는 4단계 명령어와 골든 이미지 생성 전 필수 초기화 과정을 상세히 설명합니다.
/etc/machine-id의 정의와 중복이 중요한 이유
복제된 VPS는 복제 원본 서버와 동일한 /etc/machine-id을 가진 채 부팅되는데, 이 값은 단 하나의 설치 환경에만 고유하게 할당되어야 합니다. 해결 방법은 네 가지 명령어를 실행하는 것입니다. 파일을 비우고, D-Bus 복사본이 실제 파일인 경우 이를 삭제한 뒤, 재생성하고 재부팅합니다. 재부팅은 사람들이 흔히 건너뛰는 단계이지만, 변경 사항을 실제로 적용하는 핵심 단계입니다.
/etc/machine-id에는 줄 바꿈 문자로 끝나는 32자 길이의 소문자 16진수 문자열이 저장됩니다. 이를 디코딩하면 16바이트(128비트) 값이 됩니다. machine-id(5) 매뉴얼 페이지는 이 값을 기밀로 분류하며, 네트워크상에 노출해서는 안 된다고 명시합니다. 이 값을 읽을 수 있는 대상은 나중에 해당 머신을 다시 식별할 수 있기 때문입니다. 이 값은 시스템 설치 시 한 번 기록되며, 이후에는 변경되지 않습니다.
이 과정에서 세 가지 식별자가 혼동되기 쉬우므로 구분할 필요가 있습니다. 호스트네임은 사용자가 선택하며 언제든지 변경할 수 있는 레이블입니다. /sys/class/dmi/id/product_uuid에 있는 DMI(desktop management interface) 제품 UUID는 하이퍼바이저에서 제공하며 root 사용자만 읽을 수 있습니다. 머신 ID는 세 번째 식별자로, 운영 체제가 직접 생성하며 시스템의 모든 사용자가 읽을 수 있습니다.
실제로 머신 ID를 읽는 대상
DHCP 클라이언트 식별자. 이것이 가장 문제가 되는 부분입니다. systemd.network(5)은 [DHCPv4] 섹션에서 ClientIdentifier=가 기본적으로 duid를 사용한다고 명시하며, 이는 IAID와 DUID(DHCP 고유 식별자)로 구성된 RFC 4361 클라이언트 ID를 전송합니다. networkd.conf(5)는 기본 DUID 유형을 vendor으로 정의하는데, 여기서 DUID 값은 벤더 식별자(systemd)인 43793과 머신 ID의 해시값을 사용하여 생성됩니다. DHCPv6도 동일한 DUID를 사용합니다. 동일한 머신 ID를 가진 두 개의 클론은 동일한 DUID로 해시되며, 인터페이스 이름까지 같다면 바이트 단위로 동일한 클라이언트 식별자를 전송하게 됩니다. 그러면 DHCP 서버는 두 대의 클라이언트를 하나로 인식하여 두 서버 모두에 동일한 임대(lease)를 제공합니다. 이로 인해 주소가 두 서버 사이를 이동하거나, 한 서버가 갱신을 시도할 때 다른 서버의 주소가 사라지는 현상이 발생합니다.
journald. 저널 파일은 /var/log/journal/<machine-id>/에 저장됩니다. 해당 디렉터리는 문자 그대로 머신 ID를 이름으로 사용합니다. 두 클론의 저널을 하나의 수집기로 전송하면 동일한 디렉터리에 저장되어 하나의 호스트로 인식됩니다.
D-Bus. /var/lib/dbus/machine-id은 이 파일 형식이 시작된 곳입니다. Debian과 Ubuntu에서는 /etc/machine-id에 대한 심볼릭 링크로 되어 있습니다. 일부 시스템에서는 별도의 실제 파일로 자체 복사본을 유지하는데, 이 복사본이 아래 절차에서 함정이 됩니다.
호스트별 에이전트. 모니터링 에이전트, 라이선스 검사 도구, 인벤토리 도구 및 백업 클라이언트는 머신 ID가 안정적이고 별도의 설정이 필요 없기 때문에 기본 호스트 식별자로 자주 사용합니다. 두 서버가 하나의 ID를 보고하면 메트릭 데이터가 하나로 합쳐지거나, 하나의 라이선스 시트가 두 대의 머신에 적용되는 결과가 초래됩니다. 에이전트가 호스트 이름을 사용한다고 가정하지 말고, 에이전트가 어떤 방식으로 호스트 ID를 도출하는지 확인하십시오.
중복 여부 확인 방법
두 서버 모두에서 다음 명령을 실행한 뒤 출력 결과를 비교합니다.
cat /etc/machine-id
ls -l /var/lib/dbus/machine-id
sudo cat /sys/class/dmi/id/product_uuid두 운영 중인 서버의 machine ID가 동일하다면 한 서버가 다른 서버를 복제하여 생성된 것입니다. 하나의 명령어를 선호한다면 hostnamectl을 사용하여 Machine ID: 라인에서 동일한 값을 확인할 수 있습니다.
ls -l의 결과에 따라 다음 단계를 결정합니다. 심볼릭 링크는 다음과 같이 표시됩니다.
lrwxrwxrwx 1 root root 15 Aug 21 09:12 /var/lib/dbus/machine-id -> /etc/machine-id-rw-r--r--으로 시작하는 라인은 해당 파일이 이전 ID의 복사본을 직접 가지고 있는 실제 파일임을 의미합니다. 이 경우 파일을 삭제해야 합니다. systemd-machine-id-setup는 다른 작업을 수행하기 전에 이 파일을 먼저 읽기 때문입니다.
제품 UUID 또한 중요합니다. systemd-machine-id-setup(1)는 무작위 생성으로 넘어가기 전에 KVM UUID를 먼저 사용합니다. 따라서 서비스 제공자가 두 복제본에 동일한 SMBIOS(system management BIOS) UUID를 할당했다면, 재생성하더라도 동일한 machine ID가 생성됩니다. 두 서버의 제품 UUID가 서로 다르다면 이 부분은 걱정할 필요가 없습니다.
복제된 VPS에서 machine ID 재생성하기
순서가 중요합니다. systemd-machine-id-setup(1)에 따르면 시스템에 유효한 D-Bus machine ID가 이미 설정되어 있는 경우, 해당 D-Bus machine ID가 복사되어 /etc/machine-id을 초기화하는 데 사용됩니다. 실제 /var/lib/dbus/machine-id을 그대로 두면 제거하려던 바로 그 값을 다시 생성하게 됩니다.
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먼저 파일을 비우는 작업이 필수적입니다. 이 도구는 파일이 없거나 비어 있을 때만 작동하며, 이미 유효한 ID가 들어 있는 파일에는 아무런 작업도 하지 않기 때문입니다. systemd-machine-id-setup는 수행한 작업을 표준 오류로 보고합니다. KVM VPS에서는 보통 다음과 같이 표시됩니다.
Initializing machine ID from KVM UUID.Initializing machine ID from random generator.은 하이퍼바이저 UUID를 사용할 수 없을 때 나타나는 메시지입니다. cat /etc/machine-id이 다른 서버와 다른 값을 출력하기만 한다면 두 결과 모두 정상입니다.
심볼릭 링크는 D-Bus와 systemd가 하나의 값을 공유하도록 유지합니다. 별도의 실제 파일을 선호한다면 대신 sudo dbus-uuidgen --ensure를 실행하십시오. 이 명령은 파일이 존재하지 않을 때 새로운 UUID로 파일을 생성합니다. dbus가 설치되어 있지 않으면 /var/lib/dbus 디렉터리 자체가 존재하지 않으며, ln는 No such file or directory 오류와 함께 실패하므로 이 두 줄은 건너뛰어도 됩니다.
그런 다음 재부팅하십시오.
sudo reboot재부팅이 필수적인 이유
이전 값을 이미 읽어 들인 모든 프로세스는 여전히 해당 값을 사용하고 있습니다. sd_id128_get_machine()은 호출하는 프로세스 내부에서 ID를 캐싱하므로, 실행 중인 데몬은 파일이 변경되었음을 결코 알아차리지 못합니다. journald는 이미 /var/log/journal/<old-id>/system.journal을 열어둔 상태이며 계속해서 내용을 추가합니다. systemd-networkd는 시작 시점에 DUID를 계산했으며, 갱신할 때마다 이전 클라이언트 식별자를 계속 전송합니다. 이는 보통 해결하고자 했던 바로 그 오류의 원인이 됩니다. D-Bus 역시 시작 시점에 ID를 읽었습니다. 서비스를 하나씩 재시작할 수도 있지만, 하나를 놓치게 될 것이며 PID 1 또한 이전 값을 유지하고 있습니다.
재부팅 후에는 다음 두 가지를 확인하십시오.
cat /etc/machine-id
ls /var/log/journal//var/log/journal/에는 이제 새로운 ID로 명명된 두 번째 디렉터리가 생성되어 있으며, 새로운 항목은 그곳에 저장됩니다. 일반적인 journalctl는 현재 머신의 디렉터리만 읽으므로, 복제 이전의 기록은 기본 보기에서 사라집니다. 하지만 데이터는 여전히 디스크에 남아 있습니다. journalctl --merge은 이전 디렉터리를 포함한 모든 저널 디렉터리를 읽습니다. 해당 로그가 더 이상 필요 없다고 확신할 때 이전 디렉터리를 삭제하십시오.
이것이 바로 컨테이너에서 이 절차를 연습할 수 없는 이유입니다. 컨테이너는 호스트 커널을 공유하며 자체적인 PID 1으로 부팅하지 않는데, 재부팅이야말로 이 작업의 핵심이기 때문입니다. 운영 환경과 동일한 방식으로 테스트하십시오. VM을 복제하고, 명령어를 실행하고, 재부팅한 다음, 원본 머신과 ID를 비교하십시오.
복제 후가 아니라 스냅샷 생성 전에 잘라내기(Truncate)를 수행하십시오
복제본을 하나씩 수정하는 방식은 효과가 있습니다. 하지만 이미지 자체를 수정하는 것이 더 좋습니다. 잘못된 스냅샷에서 복원된 모든 서버는 동일한 값을 그대로 물려받기 때문입니다. 템플릿을 종료하기 직전에 이 작업을 마지막으로 수행하십시오.
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파일을 비우십시오. 삭제해서는 안 됩니다. machine-id(5)은 여러 대의 머신에서 사용하는 이미지의 경우 빈 파일을 유지할 것을 권장합니다. 파일이 비어 있으면 이미지를 읽기 전용으로 사용할 때 실제 파일 위에 임시 파일을 바인드 마운트(bind-mount)할 수 있기 때문입니다. 읽기 전용 /etc 환경에서는 부팅 시 생성된 ID가 해당 임시 파일에 저장되며, 파일 시스템이 쓰기 가능해지면 systemd-machine-id-setup --commit이 이를 기록합니다.
계획 시 고려해야 할 부작용이 하나 있습니다. 값이 채워지지 않은 머신 ID는 다음 부팅을 첫 번째 부팅으로 간주하게 만듭니다. 따라서 ConditionFirstBoot=yes가 포함된 유닛은 해당 부팅 시에만 실행되고 이후의 모든 부팅에서는 건너뛰게 됩니다. 템플릿을 빌드하기 전에 grep -rl ConditionFirstBoot /usr/lib/systemd/system/를 사용하여 이미지에서 무엇이 실행될지 확인하십시오.
템플릿과 스냅샷은 서로 다른 객체이며, 이 차이에 따라 식별 정보가 복사되는지 여부가 결정됩니다. 템플릿은 의도적으로 준비하는 빌드 아티팩트인 반면, 스냅샷은 실행 중인 서버의 특정 시점 복사본이며 데이터와 함께 해당 서버의 식별 정보를 그대로 포함합니다.
클라우드 이미지는 올바르게 작동하는데 직접 만든 스냅샷은 그렇지 않은 이유
배포판의 클라우드 이미지는 복제될 것을 전제로 빌드되므로, machine ID가 비어 있는 상태로 제공되며 첫 부팅 시점에 값이 채워집니다. cloud-init에는 정확히 이 과정을 위한 단계가 문서화되어 있습니다. cloud-init clean --machine-id은 systemd 시스템에서 /etc/machine-id을 uninitialized이라는 문자열로 설정하며, cloud-init CLI 참조 문서에서는 골든 이미지를 복제할 때 이를 모범 사례로 권장합니다. 따라서 해당 이미지를 다음번에 부팅하면 고유한 machine ID가 생성됩니다.
직접 생성한 스냅샷은 상황이 다릅니다. 스냅샷을 생성할 당시 이미 파일에 값이 채워져 있었기 때문에, 해당 스냅샷으로 복원된 모든 서버는 동일한 값을 가지게 되며 복원 과정에서 이를 초기화하는 절차도 없습니다. 이는 실행 중인 서버를 새로운 VPS로 이전할 때 발생하는 문제와 동일한 유형입니다. 복사본은 원본을 그대로 재현하지만, 복제되어서는 안 될 식별 정보까지 함께 복사되기 때문입니다.
복제본이 추가로 복제하는 항목
- SSH host keys.
/etc/ssh/ssh_host_*도 함께 복사되므로 두 서버 모두 클라이언트에게 동일한 핑거프린트를 제시합니다. 해당 파일들을 삭제한 뒤sudo ssh-keygen -A을 실행하거나, Debian 및 Ubuntu에서는sudo dpkg-reconfigure openssh-server을 실행하십시오. 이후 클라이언트에서 호스트 키가 변경되었다는 경고가 나타나는데, 이는 정상적인 동작입니다. - 호스트 이름(Hostname).
sudo hostnamectl set-hostname app02로 설정한 뒤,/etc/hosts이 새로운 이름을 올바르게 해석하는지 확인하십시오. - 정적 네트워크 설정. 고정 IP 주소를 가진 서버를 복제하면 네트워크에 연결되는 즉시 원본과 충돌합니다. 복제본을 네트워크에 연결하기 전에
/etc/netplan/를 읽어보십시오. - 시스템 시계. 복원된 스냅샷은 스냅샷을 생성했을 당시의 시간으로 재개됩니다. 복원된 VPS의 큰 시간 도약은 TLS 인증서 검증을 실패하게 만들고 시간 동기화가 완료될 때까지 로그 순서를 뒤섞습니다.
복제본에 대해서도 새로운 VPS를 위한 초기 10분 체크리스트를 수행하십시오. 복제된 서버는 원본 서버의 사용자 계정, SSH 키, 방화벽 규칙, 예약된 작업 등을 그대로 물려받으며, 이 중 어느 것도 복제본이 수행할 새로운 작업에 맞춰 검토되지 않았기 때문입니다.
FAQ
/etc/machine-id를 변경한 뒤에 재부팅해야 합니까?
네, 그렇습니다. 프로세스는 machine ID를 한 번 읽은 뒤 캐시하므로, 이미 실행 중인 프로세스에는 새로운 값이 반영되지 않습니다. journald는 이전 ID로 명명된 저널 디렉터리에 계속 기록하며, DHCP 클라이언트는 이전 값에서 파생된 클라이언트 식별자를 계속 전송합니다. 이것이 보통 ID를 변경하는 이유이기도 합니다. 개별 서비스를 재시작하면 일부 문제는 해결되지만, PID 1도 이전 값을 유지하고 있습니다. 재부팅을 수행한 뒤 cat /etc/machine-id 명령으로 확인하고 다른 서버와 비교하십시오.
/etc/machine-id는 하드웨어 UUID와 동일합니까?
아니요, 그렇지 않습니다. /sys/class/dmi/id/product_uuid에 있는 DMI 제품 UUID는 하이퍼바이저에서 가져온 것이며 root 사용자만 읽을 수 있습니다. machine ID는 운영체제가 생성하며 모든 사용자가 읽을 수 있는 일반 파일에 저장됩니다. 이 둘은 한 방향으로 연결됩니다. KVM 게스트 환경에서는 복사할 D-Bus ID가 없을 때 systemd-machine-id-setup이 하이퍼바이저 UUID를 사용하여 새로운 machine ID를 생성합니다. 두 클론 서버가 동일한 제품 UUID를 공유하면 동일한 machine ID를 생성하게 되므로, 결과를 신뢰하기 전에 해당 파일도 함께 비교해야 합니다.
/etc/machine-id를 삭제해야 합니까, 아니면 비워두어야 합니까?
이미지를 준비 중이라면 파일을 비워두십시오. machine-id(5)은 빈 파일을 선호합니다. 이미지가 읽기 전용 /etc로 실행될 때 systemd가 그 위에 임시 파일을 바인드 마운트할 수 있기 때문입니다. 쓰기 가능한 시스템에서는 파일을 삭제해도 작동하며 일부 클론 스크립트는 그렇게 처리하지만, 빈 파일로 두는 것이 더 안전한 기본값입니다. cloud-init은 동일한 목적을 위해 파일 안에 uninitialized이라는 단어를 기록합니다.
왜 복제한 두 서버가 동일한 DHCP 주소를 할당받습니까?
두 서버가 동일한 클라이언트 식별자를 전송했기 때문입니다. systemd-networkd는 DHCPv4에 대해 기본적으로 ClientIdentifier=duid을 사용하며, 기본 DUID는 /etc/machine-id의 해시값으로 생성됩니다. 따라서 동일한 인터페이스 이름을 유지한 클론 서버들은 machine ID가 같으면 식별자도 동일하게 생성됩니다. DHCP 서버는 이 식별자를 기준으로 일치 여부를 판단하므로, 두 요청을 하나의 클라이언트로 간주하여 하나의 임대(lease)만 할당합니다. 각 서버에 고유한 machine ID를 부여하고 둘 다 재부팅하십시오. 만약 서버가 여전히 이전 주소를 제공한다면, DHCP 서버 자체에서 만료된 임대 정보를 삭제하십시오.