TT Lab
블로그 시작하기
배우기 러닝패스 코스

KubeVirt 라이브 마이그레이션 — 옮기고, 막히고, 끊기는 시간 재기

라이브 마이그레이션 — 무엇이 옮겨 가고 무엇이 막나

TT Lab 에서 이어서 보기

한 줄 요약

라이브 마이그레이션은 VM 의 메모리를 돌아가는 채로 다른 노드에 복사하고, 마지막 몇 백 밀리초만 멈춰 나머지를 넘긴 뒤 대상에서 이어 돌리는 일입니다. KubeVirt 에서는 이것이 「새 virt-launcher 파드를 하나 더 만들고, 두 파드의 QEMU 가 메모리를 주고받는 일」 입니다.

왜 이게 필요했나

쿠버네티스의 기본 단위인 파드는 옮겨지지 않습니다. 노드를 비우면 파드는 지워지고 다른 곳에 새로 만들어집니다. 상태를 바깥(DB, 볼륨)에 두는 컨테이너는 그래도 괜찮습니다. VM 은 다릅니다. 게스트 운영체제의 메모리 전체가 상태입니다. 지우고 새로 만들면 재부팅이고, 열린 연결과 메모리 캐시가 모두 사라집니다.

KubeVirt 는 VM 하나를 파드 하나(virt-launcher) 안의 QEMU 프로세스로 돌립니다. 마이그레이션은 이 파드를 「옮기는」 것이 아니라, 대상 노드에 virt-launcher 를 하나 더 만들고 원본 QEMU 가 메모리를 대상 QEMU 로 흘려보낸 뒤 원본 파드를 끝내는 것입니다.

어떻게 동작하나

사전 복사(pre-copy). 기본 방식입니다. 게스트를 돌린 채 메모리 전체를 한 번 보내고, 그동안 게스트가 바꾼 페이지(더티 페이지)를 다시 보내기를 반복합니다. 남은 더티 페이지를 정해진 시간(최대 중단 시간) 안에 보낼 수 있을 만큼 줄어들면, 게스트를 잠깐 멈추고 나머지와 CPU 상태를 넘긴 뒤 대상에서 이어 돌립니다. 이 멈춘 시간이 중단 시간(downtime) 입니다.

수렴하지 않을 때. 게스트가 대역폭보다 빨리 메모리를 바꾸면 남은 양이 줄지 않습니다. 그러면 정해진 시간(KubeVirt 기본 completionTimeoutPerGiB 150초 × 메모리 GiB) 뒤 마이그레이션을 포기합니다(abort). 게스트는 원본에서 그대로 돌고 있어 손해는 없지만, 노드는 비워지지 않습니다. 이때 쓰는 손잡이가 MigrationPolicy 의 allowAutoConverge(게스트 CPU 를 점점 늦춰 더티 속도를 낮춤)와 allowPostCopy(먼저 대상에서 돌리고 모자란 페이지를 나중에 끌어옴)입니다.

누가 옮길 수 있나 — LiveMigratable. VMI 가 뜨면 KubeVirt 가 조건 하나를 계산합니다. 실측(KubeVirt v1.9.0)에서 본 거절 이유는 셋이었습니다.

원인 조건 이유 메시지
ReadWriteOnce PVC(NFS 위든 local-path 든) DisksNotLiveMigratable PVC … is not shared, live migration requires that all PVCs must be shared (using ReadWriteMany access mode)
hostDisk DisksNotLiveMigratable cannot migrate VMI with non-shared HostDisk
pod 네트워크에 bridge InterfaceNotLiveMigratable cannot migrate VMI which does not use masquerade or a migratable plugin to connect to the pod network

조건이 False 면 마이그레이션 요청 자체가 승인 웹훅에서 거절됩니다. containerDisk(이미지 안의 디스크)는 옮길 수 있습니다 — 쓰기 층을 블록 마이그레이션으로 함께 보냅니다.

조건이 보지 않는 것 — CPU. 게스트에게 보여 준 CPU 기능은 대상 노드에도 있어야 합니다. 그런데 LiveMigratable 은 이것을 계산하지 않습니다. 대신 대상 파드에 노드 선택자를 붙입니다.

현장에서 만나는 모습

저장소는 RWX 인데 PVC 가 RWO 인 경우. NFS 는 원래 여러 노드가 함께 엽니다. 그래도 PVC 를 ReadWriteOnce 로 만들면 KubeVirt 는 옮기지 않습니다. 이 홈랩 운영 클러스터의 VM 둘이 정확히 이 상태였습니다(2026-10-31, nfs-synology, RWO). 고치는 길은 디스크를 RWX PVC 로 다시 만드는 것이고, KubeVirt v1.9 는 볼륨 마이그레이션(updateVolumesStrategy: Migration)으로 VM 을 켠 채 디스크를 바꿔 끼우는 길도 냅니다.

중단 시간과 서비스 중단은 다릅니다. 실측에서 libvirt 가 잰 중단 시간은 338–490ms 였지만, 바깥에서 Service 를 거쳐 20ms 마다 두드린 TCP 연결은 1.2–3.0초 동안 응답하지 않았고 유지하던 연결은 매번 끊겼습니다. masquerade 는 파드 IP 를 거쳐 들어오는데, 마이그레이션이 끝나면 파드(=IP)가 바뀌고 Service 의 엔드포인트가 새 파드로 갈아탈 때까지 시간이 듭니다. 게스트는 멈추지 않았어도 연결은 끊깁니다. 애플리케이션 쪽 재연결이 여전히 필요합니다.

노드 비우기에서는 축출 전략이 갈림길입니다. evictionStrategy: LiveMigrate 인 VM 의 virt-launcher 를 drain 이 내보내려 하면 KubeVirt 가 거절하고 대신 마이그레이션을 만듭니다. 옮길 수 없는 VM 에 LiveMigrate 를 두면 drain 이 끝나지 않습니다. None 이면 VM 은 꺼졌다가(runStrategy 에 따라) 다른 노드에서 새로 뜹니다.

다음 실습에서 할 것

controlplane 의 NFS 를 RWX 스토리지 클래스로 잇고, KubeVirt 와 CDI 를 설치하고, 바탕 디스크를 RWX 로 가져옵니다. 두 워커의 CPU 라벨을 읽어 함께 낼 수 있는 모델을 고르고, RWX 디스크 VM 을 띄워 다른 워커로 옮긴 뒤 libvirt 가 잰 중단 시간을 읽습니다. RWO 디스크 VM 이 어떤 말로 거절되는지 보고, 마지막으로 노드를 비워 두 VM 이 각각 어떻게 되는지 봅니다.