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)
This commit is contained in:
kaffa
2026-04-19 13:39:34 +09:00
parent 354b2bb9d6
commit afd2935ea4
2 changed files with 201 additions and 1 deletions

View File

@@ -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 리버스 프록시 |

199
infra/network/multus.md Normal file
View File

@@ -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 현황