Files
obsidian/infra/network/multus.md
kaffa afd2935ea4 infra/network: add multus.md (Multus CNI + storage-205 NAD)
Document Multus CNI + Whereabouts IPAM deployment on k3s, including:
- k3s path peculiarities (symlink-based multicall binary vs thick daemonset chroot)
- /opt/cni/bin real-directory workaround with all plugin binaries
- multus-shim/passthru symlinks to k3s CNI dir
- storage-205 NAD for Longhorn 2.5G storage network (ens2, MTU 9000, whereabouts .240-.254)
2026-04-19 13:39:34 +09:00

6.9 KiB

title, updated, tags
title updated tags
Multus CNI + NetworkAttachmentDefinition 2026-04-19
infra
k3s
multus
cni
networking
longhorn

개요

K3s 클러스터에 2차 네트워크 인터페이스를 Pod에 붙여줄 수 있게 해주는 meta-CNI. Flannel(기본 eth0)은 그대로 두고 k8s.v1.cni.cncf.io/networks 어노테이션으로 추가 인터페이스(net1, net2, ...) 연결.

주 용도: Longhorn storage network 분리 (192.168.205.0/24 2.5G 전용망). longhorn-storage-network도 참고.

아키텍처

Pod
├── eth0 (10.42.x.x, Flannel, 1GbE via br-uplink)
└── net1 (192.168.205.240-254, macvlan via ens2, 2.5GbE, MTU 9000)
  • Multus CNI (thick daemonset): Pod 생성 시 Flannel 기본 네트워크에 추가로 NAD 기반 네트워크를 붙임
  • Whereabouts: 범위 기반 IPAM (클러스터 전역 IP 충돌 방지, CRD 기반 추적)
  • macvlan CNI: Pod에 ens2 부모 인터페이스의 MAC 기반 가상 인터페이스 생성

K3s 경로 특이점

K3s CNI 구조가 표준 /opt/cni/bin과 다르고 대부분 심볼릭 링크가 multicall 바이너리를 가리키는 형태라 Multus thick chroot과 충돌함. 아래 방식으로 해결:

경로 역할
/var/lib/rancher/k3s/agent/etc/cni/net.d/ k3s CNI conf dir (kubelet이 여기서 NetConf 읽음)
/var/lib/rancher/k3s/data/cni/ k3s CNI bin dir (flannel/bridge/host-local이 multicall cni 바이너리 심볼릭)
/var/lib/rancher/k3s/data/current/bin/cni 실제 k3s multicall CNI 바이너리 (이름에 따라 flannel/bridge/호출 분기)
/opt/cni/bin/ (신규, 실제 디렉토리) Multus/Whereabouts가 사용하는 CNI 바이너리 저장소. 모두 real binary

/opt/cni/bin/ 내용 (각 노드 kr1/kr2/hp1/hp2):

  • containernetworking/plugins v1.6.2 풀 셋: bandwidth, bridge, dhcp, dummy, firewall, host-device, host-local, ipvlan, loopback, macvlan, portmap, ptp, sbr, static, tap, tuning, vlan, vrf
  • flannel ← k3s multicall 바이너리 복사본 (cp /var/lib/rancher/k3s/data/current/bin/cni /opt/cni/bin/flannel)
  • multus-shim, passthru ← Multus DS init container가 배포
  • whereabouts ← Whereabouts DS가 배포

심볼릭 링크 (노드별)

K3s 기본 CNI dir과 표준 경로 브리지:

# kubelet이 k3s CNI dir에서 multus-shim 찾을 수 있게
/var/lib/rancher/k3s/data/cni/multus-shim → /opt/cni/bin/multus-shim
/var/lib/rancher/k3s/data/cni/passthru    → /opt/cni/bin/passthru

# whereabouts 바이너리가 /etc/cni/net.d/whereabouts.d 기본 경로를 기대함
/etc/cni/net.d/whereabouts.d → /var/lib/rancher/k3s/agent/etc/cni/net.d/whereabouts.d

배포 정보

컴포넌트 Kind 위치
kube-multus-ds DaemonSet kube-system
whereabouts DaemonSet kube-system
NetworkAttachmentDefinition CRD CRD cluster-scope
ippools, overlappingrangeipreservations, nodeslicepools CRDs CRD cluster-scope (whereabouts.cni.cncf.io)

버전:

  • Multus CNI: v4.2.2 (thick daemonset)
  • Whereabouts: v0.9.1
  • containernetworking/plugins: v1.6.2

매니페스트 커스터마이징: 상류 manifest에서 hostPath 2개만 k3s 경로로 sed 치환:

sed -e 's|path: /etc/cni/net.d$|path: /var/lib/rancher/k3s/agent/etc/cni/net.d|g' \
    -e 's|path: /etc/cni/multus/net.d$|path: /var/lib/rancher/k3s/agent/etc/cni/multus/net.d|g' \
    multus-daemonset-thick.yml > multus-k3s.yml

Whereabouts도 동일(conf dir만 패치, /opt/cni/bin은 실제 디렉토리라 default 유지).

NetworkAttachmentDefinition

longhorn-system/storage-205

Longhorn 전용 2.5G 스토리지 네트워크.

apiVersion: k8s.cni.cncf.io/v1
kind: NetworkAttachmentDefinition
metadata:
  name: storage-205
  namespace: longhorn-system
spec:
  config: |
    {
      "cniVersion": "0.3.1",
      "type": "macvlan",
      "master": "ens2",
      "mode": "bridge",
      "mtu": 9000,
      "ipam": {
        "type": "whereabouts",
        "range": "192.168.205.0/24",
        "range_start": "192.168.205.240",
        "range_end": "192.168.205.254"
      }
    }
항목
부모 인터페이스 ens2 (각 노드 2.5G NIC, 192.168.205.x/24)
모드 bridge (macvlan)
MTU 9000 (jumbo frames)
IP 풀 192.168.205.240 - 192.168.205.254 (15개)
IPAM whereabouts (클러스터 전역 IP 중복 체크)

192.168.205.0/24 점유 현황 (이 NAD 도입 시점):

  • .100 NAS (Synology) — 2.5G 스토리지 세그먼트
  • .134 hp2 / .135 kr2 / .214 kr1 / .227 hp1 — 각 노드 ens2
  • .240 ~ .254 NAD 풀 (Longhorn instance-manager 등)

사용 방법

Pod 정의에 어노테이션 추가:

metadata:
  annotations:
    k8s.v1.cni.cncf.io/networks: storage-205
    # 다른 네임스페이스면: k8s.v1.cni.cncf.io/networks: longhorn-system/storage-205

Pod 안에 net1 인터페이스가 whereabouts가 할당한 IP(.240-.254)로 붙음. eth0(Flannel)은 그대로.

업그레이드 시 주의

K3s 업그레이드 시 /var/lib/rancher/k3s/data/cni/ 심볼릭이 재생성될 수 있음. 아래 심볼릭 링크가 살아있는지 확인:

ls -la /var/lib/rancher/k3s/data/cni/multus-shim
ls -la /var/lib/rancher/k3s/data/cni/passthru

끊어졌으면 재생성:

sudo ln -sfn /opt/cni/bin/multus-shim /var/lib/rancher/k3s/data/cni/multus-shim
sudo ln -sfn /opt/cni/bin/passthru /var/lib/rancher/k3s/data/cni/passthru

/opt/cni/bin/는 k3s와 무관한 경로라 업그레이드 영향 없음.

트러블슈팅

failed to find plugin "X" in path [/opt/cni/bin]

Multus thick의 chroot가 /hostroot로 들어간 뒤 /opt/cni/bin/X 찾음. 원인:

  • /opt/cni/bin이 심볼릭이면 대상 디렉토리의 binary가 pod에 마운트 안 돼 실행 불가
  • 해결: /opt/cni/bin을 real directory로 만들고 모든 플러그인을 real binary로 배치 (이 구성이 그렇게 해결됨)

config file not found (macvlan + whereabouts)

whereabouts 바이너리가 /host/etc/cni/net.d/whereabouts.d/whereabouts.conf를 찾지만 k3s는 conf를 /var/lib/rancher/k3s/agent/etc/cni/net.d/에 둠.

  • 해결: /etc/cni/net.d/whereabouts.d 심볼릭 링크 생성

Multus DS pod 로그 확인

sudo kubectl -n kube-system logs -l app=multus --tail=50

테스트 Pod 예시

apiVersion: v1
kind: Pod
metadata:
  name: nad-test
  namespace: longhorn-system
  annotations:
    k8s.v1.cni.cncf.io/networks: storage-205
spec:
  containers:
  - name: probe
    image: alpine:3.20
    command: ["sh","-c","sleep 600"]
sudo kubectl -n longhorn-system exec nad-test -- ip -br addr
# eth0=10.42.x.x, net1=192.168.205.24X (whereabouts 할당)

관련 문서

  • openwrt — 192.168.9.0/24 라우터
  • metallb — k3s LoadBalancer (별개, service IP용)
  • infra-hosts — 각 노드 ens2 IP 현황