- Published on
Eviction, drain, migration failure modes: KubeVirt는 실패를 어떻게 처리하는가
- Authors

- Name
- Youngju Kim
- @fjvbn20031
- 들어가며
- 1. KubeVirt는 drain을 곧바로 kill로 처리하지 않는다
- 2. EvictionRequested와 EvacuationNodeName은 운영자가 꼭 봐야 한다
- 3. live migration 불가 사유를 미리 reason으로 남긴다
- 4. MigrationState는 실패 분석의 중심축이다
- 5. pre-copy는 실패해도 복구 여지가 있지만, post-copy는 더 위험하다
- 6. abort도 하나의 상태 머신이다
- 7. migration failure는 control plane과 data plane 둘 다에서 생긴다
- 8. secure feature는 종종 migration flexibility와 충돌한다
- 9. migration 중 다중 Pod 존재는 실패 분석을 더 어렵게 만든다
- 10. drain 운영 전략은 워크로드 특성에 따라 달라져야 한다
- 운영자가 기억해야 할 핵심
- 마무리
들어가며
운영 관점에서 KubeVirt의 진짜 난도는 VM을 띄우는 순간보다, 실패를 다루는 순간에 드러난다. Pod는 다시 스케줄링하면 끝나는 일이 많지만, VM은 메모리 상태와 디스크, 네트워크 세션, guest 실행 문맥까지 함께 고려해야 한다. 그래서 drain과 eviction, migration 실패는 KubeVirt 내부 설계를 가장 잘 드러내는 장면이다.
이번 글에서는 "무엇이 실패라고 간주되는가"와 "실패를 KubeVirt가 어떻게 표준화해서 드러내는가"를 본다.
1. KubeVirt는 drain을 곧바로 kill로 처리하지 않는다
API 타입의 EvictionStrategy 주석을 보면 node drain 상황에서 어떤 전략을 쓸지 정의돼 있다. 즉 KubeVirt는 drain을 단순 Kubernetes eviction 이벤트로 보지 않고, VM 전용 정책 판단이 필요한 사건으로 취급한다.
그 이유는 명확하다.
- migratable이면 먼저 옮기는 편이 낫다.
- non-migratable이면 중단이나 보류가 필요할 수 있다.
- 외부 컨트롤러가 소유한 VM이면 다른 처리 모델이 필요할 수 있다.
즉 KubeVirt에서 drain은 "Pod 하나 비우기"가 아니라 "이 VM을 어느 방식으로 대피시킬 것인가"라는 질문이다.
2. EvictionRequested와 EvacuationNodeName은 운영자가 꼭 봐야 한다
VirtualMachineInstanceStatus에는 EvacuationNodeName이 있고, condition 타입에는 EvictionRequested가 정의돼 있다. 이는 eviction이 단순 이벤트 로그에만 남는 것이 아니라, VMI status에 구조화된 신호로 남는다는 뜻이다.
운영자가 이 값을 봐야 하는 이유는 다음과 같다.
- drain이 시작됐는지
- 어떤 node에서 evacuate 하려는지
- 이후 migration이 붙어야 하는지
- 외부 컨트롤러가 후속 조치를 해야 하는지
즉 KubeVirt는 drain을 status-first 방식으로 드러낸다.
3. live migration 불가 사유를 미리 reason으로 남긴다
KubeVirt API 타입에는 non-migratable reason이 매우 많이 정의돼 있다.
DisksNotLiveMigratableInterfaceNotLiveMigratableHotplugNotLiveMigratableVirtIOFSNotLiveMigratableHostDeviceNotLiveMigratableSEVNotLiveMigratableSecureExecutionNotLiveMigratableTDXNotLiveMigratableHypervPassthroughNotLiveMigratablePersistentReservationNotLiveMigratable
이 설계가 좋은 이유는 실패를 뒤늦게 runtime error로만 보지 않기 때문이다. KubeVirt는 미리 condition reason으로 "왜 이 VM은 옮길 수 없는가"를 말해 준다.
즉 운영자는 migration을 걸고 실패 로그를 기다리기 전에, API 상태만 보고도 대략적인 한계를 읽을 수 있다.
4. MigrationState는 실패 분석의 중심축이다
VirtualMachineInstanceMigrationState에는 실패 분석에 필요한 정보가 많이 들어 있다.
- source node와 source pod
- target node와 target pod
- sync address
- direct migration ports
- completed 여부
- failed 여부
- abort requested 여부
- abort status
- failure reason
- 현재 migration mode
이 구조를 보면 KubeVirt가 migration을 단순 boolean 상태로 보지 않는다는 점이 드러난다. migration은 시간에 따라 source와 target이 바뀌는 분산 프로토콜이고, 실패도 여러 단계에서 발생한다.
5. pre-copy는 실패해도 복구 여지가 있지만, post-copy는 더 위험하다
앞선 글에서 봤듯 pre-copy는 source에 원본 메모리가 남아 있는 상태에서 점진적으로 전송한다. 반면 post-copy는 target이 먼저 실행을 시작하고, 필요한 페이지를 뒤늦게 source에서 받아 온다.
그래서 post-copy 실패는 훨씬 위험하다. pkg/virt-handler/vm.go에는 formatIrrecoverableErrorMessage가 있고, post-copy 실패로 domain이 paused 상태가 되면 "VMI is irrecoverable due to failed post-copy migration" 메시지를 만든다.
이건 매우 강한 신호다. 단순히 migration job이 실패한 것이 아니라, 실행 중이던 VM 상태 자체가 복구 불가능한 쪽으로 무너질 수 있음을 뜻한다.
즉 post-copy는 바쁜 워크로드를 옮기기 위한 강력한 도구지만, 실패 비용도 더 크다.
6. abort도 하나의 상태 머신이다
VirtualMachineInstanceMigrationState에는 AbortRequested와 AbortStatus가 있고, abort 상태도 Succeeded, Failed, Aborting으로 따로 모델링된다.
이 설계는 현실적이다. migration 중단은 버튼 하나 누른다고 즉시 끝나는 일이 아니다.
- 아직 중단 가능한 단계인지
- 이미 target이 handoff를 받았는지
- storage나 network side effect가 얼마나 진행됐는지
에 따라 결과가 달라진다. 즉 KubeVirt는 abort도 일반 API 취소가 아니라, 별도 상태 머신으로 본다.
7. migration failure는 control plane과 data plane 둘 다에서 생긴다
실패 원인을 크게 나누면 두 가지다.
control plane 쪽 실패
- target Pod가 스케줄되지 않음
- 적절한 node selector를 만족하지 못함
- quota나 policy에 걸림
- utility volume이나 backup 때문에 block됨
data plane 쪽 실패
- dirty page 비율이 너무 높아 pre-copy가 수렴하지 않음
- post-copy 전환 이후 source와 target 동기화가 깨짐
- migration socket 또는 proxy 경로 문제
- target에서 domain 준비가 늦음
즉 "migration failed" 한 줄만으로는 부족하고, 어느 plane에서 실패했는지 나눠 봐야 한다.
8. secure feature는 종종 migration flexibility와 충돌한다
API 수준에서 이미 드러나듯 SEV, Secure Execution, TDX, host device passthrough 같은 기능은 migration 제약과 자주 충돌한다.
이는 우연이 아니다. 이런 기능은 대체로 다음 중 하나를 요구한다.
- 특정 host 하드웨어와 강하게 결합
- guest 메모리를 특수 방식으로 보호
- 외부에서 재현하기 어려운 장치 상태 사용
즉 보안을 강화하거나 하드웨어 성능을 극대화할수록, "아무 node로나 무중단 이동"이라는 특성과 충돌하기 쉬워진다.
9. migration 중 다중 Pod 존재는 실패 분석을 더 어렵게 만든다
ActivePods가 왜 중요한지 실패 모드에서 더 잘 드러난다. migration 중에는 source와 target launcher Pod가 잠깐 공존하므로, 로그와 상태를 볼 때 어떤 Pod가 진짜 현재 source인지 헷갈리기 쉽다.
실패를 볼 때는 최소한 다음을 같이 봐야 한다.
- VMI의
activePods - migration CR phase
- target pod 이름
- source pod 이름
- VMI
migrationState
이 정보를 섞지 않으면, 이미 정리된 Pod 로그를 보고 현재 문제라고 오해하기 쉽다.
10. drain 운영 전략은 워크로드 특성에 따라 달라져야 한다
모든 VM에 같은 eviction strategy를 적용하면 안 된다. 예를 들어:
- stateless에 가까운 테스트 VM
- SR-IOV와 host device를 쓰는 성능 민감 VM
- RWX 볼륨과 라이브 마이그레이션이 가능한 일반 업무 VM
- post-copy 허용 여부가 중요한 메모리 write-intensive VM
은 실패 비용과 허용 가능한 조치가 전혀 다르다.
즉 drain 전략은 infra 기본값이 아니라, VM 특성에 맞는 운영 정책이어야 한다.
운영자가 기억해야 할 핵심
- drain은 Pod 제거가 아니라 VM 대피 전략 문제다.
EvictionRequested,EvacuationNodeName,MigrationState를 같이 봐야 한다.- non-migratable reason은 실패 후 로그가 아니라, 사전 판단 신호다.
- post-copy 실패는 irrecoverable 상태로 이어질 수 있으므로 훨씬 조심해야 한다.
마무리
KubeVirt는 실패를 숨기지 않고 상태 머신으로 구조화한다. drain은 eviction 전략과 연결되고, live migration 가능 여부는 condition reason으로 미리 드러나며, 실제 migration 진행 상황과 실패 사유는 MigrationState에 축적된다. 특히 post-copy 실패를 irrecoverable로 분리한 점은, KubeVirt가 VM 실패를 단순 Pod 재시작 문제와 다르게 본다는 사실을 잘 보여 준다.
다음 글에서는 시리즈를 마무리하면서, KubeVirt 소스코드를 어떤 순서로 읽으면 이 전체 구조를 가장 빠르게 이해할 수 있는지 소스 읽기 지도를 정리하겠다.