Skip to content
Published on

VMI status, metrics, guest agent, debugging: KubeVirt는 내부 상태를 어떻게 드러내는가

Authors

들어가며

KubeVirt를 운영하다 보면 가장 어려운 질문은 이것이다. "지금 이 VM이 정말 어디까지 살아 있는가?" Pod는 Running인데 guest는 멈췄을 수 있고, guest는 살아 있어도 migration은 실패 직전일 수 있다. 그래서 KubeVirt는 상태를 한 군데가 아니라 여러 층에서 수집한다.

  • Kubernetes 객체 상태
  • libvirt domain 상태
  • guest agent가 알려 주는 guest 내부 정보
  • network status와 migration status
  • Prometheus metrics

이번 글에서는 이 관측 레이어가 어떻게 연결되는지 본다.

1. VMI status는 가장 중요한 운영 표면이다

staging/src/kubevirt.io/api/core/v1/types.goVirtualMachineInstanceStatus를 보면 운영자가 보고 싶은 정보가 꽤 많이 들어 있다.

  • phase
  • conditions
  • interfaces
  • guestOSInfo
  • migrationState
  • qosClass
  • activePods
  • selinuxContext
  • memory
  • currentCPUTopology

이 타입만 읽어도 KubeVirt가 상태를 단순히 "켜짐 또는 꺼짐"으로 보지 않는다는 걸 알 수 있다. VM 상태는 Kubernetes phase와 guest 내부 정보, migration 진행도, 네트워크 인터페이스 상태가 합쳐진 결과다.

2. phase만 보면 부족하고 conditions를 같이 봐야 한다

phase는 상위 흐름을 요약한다. Pending, Scheduling, Scheduled, Running, Succeeded, Failed, Unknown 같은 값은 큰 방향을 보여 준다.

하지만 실제 운영 판단은 conditionsreason, message에서 나온다. API 타입에는 다음 같은 condition과 reason이 미리 정의돼 있다.

  • LiveMigratable
  • StorageLiveMigratable
  • MigrationRequired
  • EvictionRequested
  • DataVolumesReady
  • DisksNotLiveMigratable
  • InterfaceNotLiveMigratable
  • HostDeviceNotLiveMigratable
  • SEVNotLiveMigratable
  • SecureExecutionNotLiveMigratable

즉 KubeVirt는 "안 된다"라고만 말하지 않고, 왜 live migration이 안 되는지까지 타입 시스템에 표준화해 두었다.

3. activePods는 migration 시점에 특히 중요하다

VirtualMachineInstanceStatus.ActivePods는 pod UID와 node 이름의 매핑이다. 주석에도 적혀 있듯 migration 중에는 하나의 VMI에 여러 Pod가 동시에 걸릴 수 있다.

이 필드는 "현재 어떤 virt-launcher Pod가 source이고 target인지"를 읽는 데 중요하다. 실제 운영에서 migration 타이밍의 혼란은 대부분 여기서 시작된다. 단일 VM이라고 생각했는데, control plane 입장에서는 source launcher와 target launcher가 동시에 존재하는 짧은 구간이 있기 때문이다.

activePods는 migration debugging에서 숨은 핵심 필드다.

4. 네트워크 상태는 Pod annotation과 guest 정보가 합쳐진다

pkg/network/controllers/vmi.go를 보면 VMI status의 interfaces는 한 군데에서만 오지 않는다.

  • Multus network status에서 pod interface 이름을 읽고
  • primary와 secondary interface를 계산하고
  • 기존 status 중 spec에 없는 항목도 보존한다

또 API 타입의 VirtualMachineInstanceNetworkInterface에는 다음이 들어 있다.

  • guest IP
  • MAC
  • 네트워크 이름
  • Pod interface 이름
  • VM 내부 interface 이름
  • info source

특히 infoSource는 이 정보가 guest-agent에서 왔는지, domain에서 왔는지, multus-status에서 왔는지를 구분한다. 이 설계 덕분에 운영자는 "이 IP는 guest 내부에서 보고된 값인지, CNI가 보고한 값인지"를 따져 볼 수 있다.

5. guest agent는 guest 내부 정보를 꺼내오는 창구다

pkg/virt-launcher/virtwrap/manager.goDomainManager 인터페이스를 보면 guest 관련 메서드가 꽤 많다.

  • GetGuestInfo
  • GetUsers
  • GetFilesystems
  • GetGuestOSInfo
  • GuestPing

이건 중요한 신호다. KubeVirt는 libvirt와 QEMU 레벨 상태만으로는 부족하다고 보고, guest agent를 통해 OS 안쪽 정보를 따로 수집한다.

pkg/virt-handler/rest/lifecycle.go는 이 데이터를 launcher client를 통해 받아서 API 응답으로 내보낸다. 즉 운영자가 보는 guest 정보는 결국:

  • virt-handler REST endpoint
  • launcher client RPC
  • virt-launcher 내부 domain manager
  • qemu guest agent

를 거쳐 나온 결과다.

6. domain stats는 host 관측성과 guest 관측성의 중간층이다

같은 DomainManager 인터페이스에는 GetDomainStatsGetDomainDirtyRateStats도 있다. 이는 guest agent와 별개로 libvirt가 보고하는 domain-level 통계를 끌어온다는 뜻이다.

이 계층은 guest 내부에서 agent가 응답하지 않아도 여전히 볼 수 있는 정보가 많다.

  • CPU 사용량
  • 메모리 상태
  • block I/O
  • 네트워크 트래픽
  • dirty page 비율

즉 guest agent는 guest 내부 의미를 알려 주고, domain stats는 hypervisor가 관찰한 실행 사실을 알려 준다. 둘은 경쟁 관계가 아니라 서로 보완 관계다.

7. Prometheus metrics는 virt-handler에서 많이 나온다

pkg/monitoring/metrics/virt-handler/domainstats를 보면 CPU, memory, block, vcpu 등 도메인 통계를 Prometheus metric으로 변환하는 collector가 있다.

이 구조는 꽤 현실적이다.

  • 실제 VM 프로세스와 가장 가까운 곳은 node다.
  • node에서 domain stats를 수집하기 가장 쉽다.
  • 그래서 metrics export도 virt-handler에 가깝게 붙는다.

즉 KubeVirt 관측성은 중앙 controller보다 node-local agent에서 더 많은 실행 사실을 수집하는 구조에 가깝다.

8. guest agent가 없으면 무엇이 줄어드는가

guest agent가 없다고 VM이 안 뜨는 것은 아니다. 하지만 운영자가 볼 수 있는 의미 있는 정보가 많이 줄어든다.

  • guest 내부 사용자 목록
  • filesystem 목록
  • OS pretty name
  • interface 이름과 일부 guest IP 정보

즉 guest agent는 필수 boot dependency라기보다, 운영 가시성과 자동화를 풍부하게 만드는 확장 계층이다.

그래서 "Pod는 정상인데 VM 내부가 안 보인다"라는 상황에서는 guest agent 설치와 연결 상태를 가장 먼저 의심해야 한다.

9. 디버깅은 control plane, node, guest를 나눠서 봐야 한다

KubeVirt 문제를 볼 때 가장 흔한 실수는 계층을 섞는 것이다. 다음처럼 쪼개서 보는 편이 좋다.

control plane에서 볼 것

  • VMI phase
  • conditions
  • migrationState
  • activePods
  • 이벤트와 migration CR 상태

node에서 볼 것

  • virt-handler 로그
  • virt-launcher 로그
  • libvirt domain 상태
  • domain stats
  • Pod 네트워크와 TAP 상태

guest에서 볼 것

  • qemu guest agent 응답 여부
  • guest OS info
  • users
  • filesystems
  • 실제 서비스 health

즉 KubeVirt 디버깅은 결국 "어느 계층의 truth를 보고 있는가"를 구분하는 작업이다.

10. status가 항상 진실을 즉시 반영하지는 않는다

API 타입 주석에 아예 적혀 있듯, VirtualMachineInstanceStatus는 실제 시스템 상태를 뒤따를 수 있다. 이건 매우 중요한 운영 포인트다.

왜냐하면 status는 informer, controller, launcher, libvirt, guest agent를 거쳐 갱신되기 때문이다. 따라서 아주 짧은 순간에는:

  • Pod는 이미 바뀌었는데 status가 늦을 수 있고
  • migration target은 떴는데 phase가 아직 예전 값일 수 있고
  • guest agent는 죽었는데 domain은 Running일 수 있다

즉 KubeVirt는 강한 일관성 대신, 여러 관측면을 조합해 판단해야 하는 시스템이다.

운영자가 기억해야 할 핵심

  • phase만 보면 부족하다. conditions, reason, migrationState를 함께 봐야 한다.
  • activePods는 migration 중 source와 target Pod를 읽는 데 중요하다.
  • 네트워크 상태는 Multus, domain, guest-agent 정보가 합쳐진 결과다.
  • guest agent와 domain stats는 서로 대체재가 아니라 보완재다.

마무리

KubeVirt의 관측성은 단일 상태 값이 아니라 여러 계층의 정보를 합쳐 만든다. VMI status는 Kubernetes 리소스 관점의 현재 상태를 보여 주고, guest agent는 guest 내부 의미를 드러내며, domain stats와 Prometheus metrics는 실제 실행 데이터 plane을 관찰하게 해 준다. 그래서 KubeVirt 운영은 "VM이 떴는가"를 묻는 일보다, "어느 계층에서 어떤 신호가 깨졌는가"를 구분하는 일에 더 가깝다.

다음 글에서는 이 관측 모델을 바탕으로, drain, eviction, migration failure, non-migratable condition 같은 실제 실패 모드를 정리해 보겠다.