- Authors

- Name
- Youngju Kim
- @fjvbn20031
- 들어가며
- 기본 아이디어
- 핵심 코드: pkg/network/multus/annotation.go
- interface 이름 계산이 왜 중요한가
- annotation에는 무엇이 들어가는가
- Pod가 secondary network를 받은 뒤에는 무엇이 일어나는가
- InfoSource가 왜 중요한가
- secondary network 변경이 migration을 유발할 수도 있다
- Multus와 binding plugin의 관계
- 실무에서 자주 생기는 문제
- 자주 하는 오해
- 마무리
들어가며
primary Pod network만으로는 부족한 경우가 많다. 데이터 plane, 스토리지 plane, 관리망, NFV 용도처럼 VM에 여러 NIC가 필요할 수 있다. KubeVirt는 이 문제를 자체 multi-network 시스템으로 풀지 않고, Multus와 NetworkAttachmentDefinition 생태계를 재사용한다.
이번 글은 secondary network가 VMI spec에서 Pod annotation, Pod interface, VMI status로 이어지는 경로를 정리한다.
기본 아이디어
primary network는 보통 Pod 기본 CNI가 제공한다. secondary network는 Multus가 추가로 붙인다. KubeVirt는 VMI spec를 읽고 필요한 Multus annotation을 생성해 launcher Pod에 싣는다.
즉 흐름은 다음과 같다.
- 사용자가 VMI spec에 secondary network를 적는다.
- KubeVirt가 Pod annotation을 생성한다.
- Multus가 annotation을 읽고 해당 NAD에 따라 추가 인터페이스를 붙인다.
- KubeVirt가 Pod network status를 읽어 VMI status를 갱신한다.
이 구조 덕분에 KubeVirt는 multi-network 기능을 core에서 다시 만들지 않는다.
핵심 코드: pkg/network/multus/annotation.go
이 파일의 GenerateCNIAnnotation과 GenerateCNIAnnotationFromNameScheme이 핵심이다. 역할은 아주 명확하다.
- secondary Multus network를 찾는다
- Pod interface 이름을 계산한다
NetworkSelectionElement목록을 만든다- 이를 JSON annotation 문자열로 직렬화한다
즉 controller는 단순히 "NAD 이름이 있다"에서 끝나지 않고, Pod 안에서 어떤 이름의 인터페이스로 붙어야 하는지까지 계산한다.
interface 이름 계산이 왜 중요한가
KubeVirt는 logical network 이름과 Pod interface 이름을 동일하게 쓰지 않는다. namescheme 계층을 통해 hashed name을 만든다. 이 방식의 목적은:
- 인터페이스 이름 길이 제한 대응
- 예측 가능한 naming
- secondary network가 많아져도 충돌 최소화
network-binding-plugin.md도 secondary network 쪽에서 pod<hash>나 tap<hash> 같은 이름 규칙을 설명한다.
즉 이름 규칙은 단순 미관 문제가 아니라, launcher Pod와 CNI plugin, libvirt domain이 서로 같은 인터페이스를 가리키게 만드는 계약이다.
annotation에는 무엇이 들어가는가
Multus용 NetworkSelectionElement에는 보통 다음 정보가 들어간다.
- namespace
- NAD name
- interface request
- 필요 시 MAC request
binding plugin이 붙는 경우에는 CNIArgs도 들어갈 수 있다. annotation.go는 plugin binding의 경우 logical network name을 CNI arg로 넣는다.
이 말은 plugin binding과 secondary network 모델이 단순 병렬 관계가 아니라, annotation 단계에서 서로 결합될 수 있다는 뜻이다.
Pod가 secondary network를 받은 뒤에는 무엇이 일어나는가
KubeVirt는 Pod annotation만 쓰고 끝내지 않는다. Pod가 실제로 secondary network를 받은 후, 그 결과를 다시 VMI status에 반영해야 한다.
이 역할을 하는 코드가 pkg/network/controllers/vmi.go다.
여기서는:
- Pod의 Multus network status annotation을 읽고
- primary interface status를 계산하고
- secondary interface status를 계산하고
- VMI status의
Interfaces에 반영한다
즉 VMI status는 "guest가 네트워크를 어떻게 봐야 하는가"뿐 아니라, "Pod가 실제로 어떤 secondary interface를 받았는가"도 담는다.
InfoSource가 왜 중요한가
vmi.go를 보면 interface status에 InfoSource 개념이 있다. 이는 정보가 어디서 왔는지 구분하기 위한 장치다.
- Pod의 Multus network status에서 왔는가
- libvirt domain에서 왔는가
- guest agent에서 왔는가
이 구분은 매우 중요하다. 예를 들어 interface가 Pod 쪽에는 있는데 domain에는 아직 반영되지 않았으면, 네트워크 hotplug가 진행 중이거나 미완료일 수 있다.
즉 InfoSource는 단순 메타데이터가 아니라 reconciliation 판단 재료다.
secondary network 변경이 migration을 유발할 수도 있다
pkg/network/migration/evaluator.go는 흥미로운 사실을 보여준다. secondary interface hotplug나 unplug, NAD 참조 변경은 경우에 따라 VMI를 migration-required 상태로 만들 수 있다.
이건 왜 중요할까?
network 구성이 바뀌면 현재 launcher Pod 위에서 안전하게 반영하기 어려운 경우가 있다. 이때 KubeVirt는:
- 즉시 migration 필요
- 잠시 pending 후 migration 필요
같은 판단을 내려 새로운 target Pod에서 network 구성을 정리해 반영하려고 한다.
즉 secondary network는 단순 CNI attach 문제가 아니라, VM 재배치 전략과도 연결되는 동적 상태다.
Multus와 binding plugin의 관계
많은 사람이 Multus와 binding plugin을 별개로 생각하지만, 실제로는 꽤 자주 함께 등장한다.
- Multus는 secondary network attach 메커니즘
- binding plugin은 guest wiring 방법
즉 하나는 Pod에 네트워크 endpoint를 들여오는 역할이고, 다른 하나는 그 endpoint를 guest NIC와 어떻게 묶을지 정하는 역할이다.
이 둘이 만나야 "secondary network가 guest에서 어떤 장치로 보이는가"가 완성된다.
실무에서 자주 생기는 문제
1. NAD는 맞는데 interface status가 비어 있다
Pod annotation은 생성되었지만 Multus attach 결과가 기대대로 안 들어왔을 수 있다.
2. Pod에는 interface가 있는데 guest에는 안 보인다
Pod 단계와 domain 단계가 어긋난 것이다. InfoSource를 봐야 한다.
3. hotplug 후 migration required가 붙는다
dynamic network update가 현재 Pod에서 안전하게 마무리되지 않아 재배치가 필요하다는 뜻일 수 있다.
자주 하는 오해
오해 1: secondary network는 Pod에 붙기만 하면 guest에도 자동이다
아니다. Pod attach와 guest wiring은 다른 단계다.
오해 2: Multus가 guest 네트워크까지 모두 책임진다
아니다. Multus는 Pod에 네트워크를 붙이고, guest wiring은 KubeVirt binding과 domain 설정이 책임진다.
오해 3: interface status는 보기 좋은 출력용이다
아니다. source별 상태를 합쳐 reconcile 판단에 쓰이는 중요한 데이터다.
마무리
KubeVirt에서 secondary network는 Multus와 NAD를 통해 Pod에 들어오고, KubeVirt가 그 결과를 annotation, naming scheme, interface status, guest wiring으로 이어서 완성한다. 즉 Multus는 endpoint provisioning, KubeVirt는 guest integration을 맡는 분업 구조다. 이 구조를 이해하면 여러 NIC를 가진 VM의 문제를 훨씬 체계적으로 디버깅할 수 있다.
다음 글에서는 네트워크에서 migration으로 넘어가서, migration CR이 생긴 뒤 target Pod가 어떤 control plane 과정을 거쳐 준비되는지 살펴보겠다.