From afd2935ea4a6772f0da55ada8d40bd0dcb291fc8 Mon Sep 17 00:00:00 2001 From: kaffa Date: Sun, 19 Apr 2026 13:39:34 +0900 Subject: [PATCH] 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) --- infra/network/_index.md | 3 +- infra/network/multus.md | 199 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 201 insertions(+), 1 deletion(-) create mode 100644 infra/network/multus.md diff --git a/infra/network/_index.md b/infra/network/_index.md index 766fd4e..b592d89 100644 --- a/infra/network/_index.md +++ b/infra/network/_index.md @@ -1,6 +1,6 @@ --- title: network 인덱스 -updated: 2026-04-16 +updated: 2026-04-19 tags: [moc, network] --- @@ -13,6 +13,7 @@ tags: [moc, network] | [[gateway-api]] | K3s Gateway API (Traefik 메인 라우팅) | | [[k3s-ingress-architecture]] | K3s 인그레스 아키텍처 (Traefik + APISIX 병렬) | | [[metallb]] | MetalLB K3s LoadBalancer | +| [[multus]] | Multus CNI + NAD (Pod 2차 인터페이스, storage-205 NAD) | | [[openwrt]] | OpenWrt 라우터 (서울, HAProxy/nftables) | | [[smtp-relay]] | smtp-relay K3s 내부 SMTP 게이트웨이 (Mailgun) | | [[sshpiper]] | sshpiper SSH 리버스 프록시 | diff --git a/infra/network/multus.md b/infra/network/multus.md new file mode 100644 index 0000000..21bfb59 --- /dev/null +++ b/infra/network/multus.md @@ -0,0 +1,199 @@ +--- +title: Multus CNI + NetworkAttachmentDefinition +updated: 2026-04-19 +tags: [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과 표준 경로 브리지: + +```sh +# 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 치환: + +```sh +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 스토리지 네트워크. + +```yaml +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 정의에 어노테이션 추가: + +```yaml +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/` 심볼릭이 재생성될 수 있음. 아래 심볼릭 링크가 살아있는지 확인: + +```sh +ls -la /var/lib/rancher/k3s/data/cni/multus-shim +ls -la /var/lib/rancher/k3s/data/cni/passthru +``` + +끊어졌으면 재생성: + +```sh +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 로그 확인 + +```sh +sudo kubectl -n kube-system logs -l app=multus --tail=50 +``` + +### 테스트 Pod 예시 + +```yaml +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"] +``` + +```sh +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 현황