LabHub

블로그

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

한국어English日本語

들어가며

운영 관점에서 KubeVirt의 진짜 난도는 VM을 띄우는 순간보다, 실패를 다루는 순간에 드러난다. Pod는 다시 스케줄링하면 끝나는 일이 많지만, VM은 메모리 상태와 디스크, 네트워크 세션, guest 실행 문맥까지 함께 고려해야 한다. 그래서 drain과 eviction, migration 실패는 KubeVirt 내부 설계를 가장 잘 드러내는 장면이다.

이번 글에서는 "무엇이 실패라고 간주되는가"와 "실패를 KubeVirt가 어떻게 표준화해서 드러내는가"를 본다.

1. KubeVirt는 drain을 곧바로 kill로 처리하지 않는다

API 타입의 EvictionStrategy 주석을 보면 node drain 상황에서 어떤 전략을 쓸지 정의돼 있다. 즉 KubeVirt는 drain을 단순 Kubernetes eviction 이벤트로 보지 않고, VM 전용 정책 판단이 필요한 사건으로 취급한다.

그 이유는 명확하다.

즉 KubeVirt에서 drain은 "Pod 하나 비우기"가 아니라 "이 VM을 어느 방식으로 대피시킬 것인가"라는 질문이다.

2. EvictionRequestedEvacuationNodeName은 운영자가 꼭 봐야 한다

VirtualMachineInstanceStatus에는 EvacuationNodeName이 있고, condition 타입에는 EvictionRequested가 정의돼 있다. 이는 eviction이 단순 이벤트 로그에만 남는 것이 아니라, VMI status에 구조화된 신호로 남는다는 뜻이다.

운영자가 이 값을 봐야 하는 이유는 다음과 같다.

즉 KubeVirt는 drain을 status-first 방식으로 드러낸다.

3. live migration 불가 사유를 미리 reason으로 남긴다

KubeVirt API 타입에는 non-migratable reason이 매우 많이 정의돼 있다.

이 설계가 좋은 이유는 실패를 뒤늦게 runtime error로만 보지 않기 때문이다. KubeVirt는 미리 condition reason으로 "왜 이 VM은 옮길 수 없는가"를 말해 준다.

즉 운영자는 migration을 걸고 실패 로그를 기다리기 전에, API 상태만 보고도 대략적인 한계를 읽을 수 있다.

4. MigrationState는 실패 분석의 중심축이다

VirtualMachineInstanceMigrationState에는 실패 분석에 필요한 정보가 많이 들어 있다.

이 구조를 보면 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에는 AbortRequestedAbortStatus가 있고, abort 상태도 Succeeded, Failed, Aborting으로 따로 모델링된다.

이 설계는 현실적이다. migration 중단은 버튼 하나 누른다고 즉시 끝나는 일이 아니다.

에 따라 결과가 달라진다. 즉 KubeVirt는 abort도 일반 API 취소가 아니라, 별도 상태 머신으로 본다.

7. migration failure는 control plane과 data plane 둘 다에서 생긴다

실패 원인을 크게 나누면 두 가지다.

control plane 쪽 실패

data plane 쪽 실패

즉 "migration failed" 한 줄만으로는 부족하고, 어느 plane에서 실패했는지 나눠 봐야 한다.

8. secure feature는 종종 migration flexibility와 충돌한다

API 수준에서 이미 드러나듯 SEV, Secure Execution, TDX, host device passthrough 같은 기능은 migration 제약과 자주 충돌한다.

이는 우연이 아니다. 이런 기능은 대체로 다음 중 하나를 요구한다.

즉 보안을 강화하거나 하드웨어 성능을 극대화할수록, "아무 node로나 무중단 이동"이라는 특성과 충돌하기 쉬워진다.

9. migration 중 다중 Pod 존재는 실패 분석을 더 어렵게 만든다

ActivePods가 왜 중요한지 실패 모드에서 더 잘 드러난다. migration 중에는 source와 target launcher Pod가 잠깐 공존하므로, 로그와 상태를 볼 때 어떤 Pod가 진짜 현재 source인지 헷갈리기 쉽다.

실패를 볼 때는 최소한 다음을 같이 봐야 한다.

이 정보를 섞지 않으면, 이미 정리된 Pod 로그를 보고 현재 문제라고 오해하기 쉽다.

10. drain 운영 전략은 워크로드 특성에 따라 달라져야 한다

모든 VM에 같은 eviction strategy를 적용하면 안 된다. 예를 들어:

은 실패 비용과 허용 가능한 조치가 전혀 다르다.

즉 drain 전략은 infra 기본값이 아니라, VM 특성에 맞는 운영 정책이어야 한다.

운영자가 기억해야 할 핵심

마무리

KubeVirt는 실패를 숨기지 않고 상태 머신으로 구조화한다. drain은 eviction 전략과 연결되고, live migration 가능 여부는 condition reason으로 미리 드러나며, 실제 migration 진행 상황과 실패 사유는 MigrationState에 축적된다. 특히 post-copy 실패를 irrecoverable로 분리한 점은, KubeVirt가 VM 실패를 단순 Pod 재시작 문제와 다르게 본다는 사실을 잘 보여 준다.

다음 글에서는 시리즈를 마무리하면서, KubeVirt 소스코드를 어떤 순서로 읽으면 이 전체 구조를 가장 빠르게 이해할 수 있는지 소스 읽기 지도를 정리하겠다.

댓글

아직 댓글이 없습니다.

로그인하면 댓글을 쓸 수 있습니다