搜索中...
🔍

未找到相关结果

Akemi

K8s多网络Multus+whereabouts+macvlan

字数统计: 2.4k阅读时长: 12 min
2026/10/29

背景

macvlan核心是在主机网卡上克隆出带不同mac和ip的mac网卡,交换机可以直接访问mac网卡,不需要通过宿主机转发(类似于esxi VCSA的vm的访问方式)
在中国xx这种规模的企业中,我们的k8s集群的业务pod使用macvlan网络,其目的一方面是降低封装与转发的性能开销,一方面方便CMDB管理、方便防火墙做ACL规则。我们分配给业务可以直接分配管理网段,然后通过macvlan进行ip的分配

1
2
3
4
5
6
7
8
9
10
11
12
13
K8s macvlan CNI 插件
↓ 调用
Linux 内核的 macvlan 特性
↓ 操作
宿主机的物理网卡

Linux版本(手动):
ip link add mac0 link eth0 type macvlan mode bridge
K8s 版本(CNI 插件自动做):
Pod 创建
→ CNI 插件收到调用
→ 在宿主机上执行同样的操作
→ 把 macvlan 接口放进 Pod 的网络 namespace

Linux版本单机macvlan

核心特点:macvlan 让一个物理网卡”分裂”出多个虚拟网卡,但宿主机自己反而看不见它们。

VLAN 子接口(eth0.10) macvlan 子接口(mac0)
隔离依据 VLAN ID(802.1Q tag) MAC 地址
子接口有自己的 MAC 不一定(通常共享) 一定有,独立 MAC
交换机看到什么 同一个 MAC,不同 VLAN tag 多个不同 MAC,同一个口
需要交换机配置 端口配 trunk,允许 VLAN 通过 混杂模式或 MAC 白名单
目的 广播域隔离(安全/多租户) 一个口”假装”多台机器
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
物理网卡 eth0(MAC: aa:aa:aa:aa:aa:aa)
│
├── mac0(MAC: aa:aa:aa:aa:aa:01)──→ 192.168.1.100
├── mac1(MAC: aa:aa:aa:aa:aa:02)──→ 192.168.1.101
└── mac2(MAC: aa:aa:aa:aa:aa:03)──→ 192.168.1.102


# 单机使用macvlan
# 网段10.163.2.200/24
ip link add mac0 link eth0 type macvlan mode bridge
ip addr add 10.163.2.199/24 dev mac0
ip link set mac0 up
ip link add mac1 link eth0 type macvlan mode bridge
ip addr add 10.163.2.198/24 dev mac1
ip link set mac1 up


测试1:mac0连网关(通
ping -c 2 -I mac0 10.163.2.200
PING 10.163.2.200 (10.163.2.200) from 10.163.2.199 mac0: 56(84) bytes of data.
64 bytes from 10.163.2.200: icmp_seq=1 ttl=64 time=0.217 ms
64 bytes from 10.163.2.200: icmp_seq=2 ttl=64 time=0.297 ms

--- 10.163.2.200 ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1032ms
rtt min/avg/max/mdev = 0.217/0.257/0.297/0.040 ms


测试2:mac0连本机eth0(不通
ping -c 2 -I mac0 10.163.2.100
PING 10.163.2.100 (10.163.2.100) from 10.163.2.199 mac0: 56(84) bytes of data.
From 10.163.2.199 icmp_seq=1 Destination Host Unreachable
From 10.163.2.199 icmp_seq=2 Destination Host Unreachable

--- 10.163.2.100 ping statistics ---
2 packets transmitted, 0 received, +2 errors, 100% packet loss, time 1063ms
pipe 2

测试3:mac1 → mac0(通
ping -c 2 -I mac1 10.163.2.199
PING 10.163.2.199 (10.163.2.199) from 10.163.2.198 mac1: 56(84) bytes of data.

From 10.163.2.198 icmp_seq=1 Destination Host Unreachable
From 10.163.2.198 icmp_seq=2 Destination Host Unreachable

--- 10.163.2.199 ping statistics ---
2 packets transmitted, 0 received, +2 errors, 100% packet loss, time 1007ms
pipe 2

Multus概述

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
Multus(元 CNI,开源框架)
│
│ 读 Pod 注解,决定调用哪些 CNI 插件
│
├── 默认网络:Calico / Flannel / 任何 CNI
└── 附加网络:macvlan / ipvlan / sriov / 任何 CNI

单网络:
Pod 创建
↓
kubelet 调用默认 CNI(如 Calico)
↓
Calico 创建 veth pair,分配 IP
↓
Pod 有一张网卡 eth0

多网络:
Pod 创建
↓
kubelet 调用 Multus(元 CNI,排在第一位)
↓
Multus 读 Pod 注解,发现要挂 macvlan
↓
Multus 按顺序执行 CNI 链:
① 默认网络(Calico)→ 创建 eth0
② 附加网络(macvlan)→ 创建 net1
↓
Pod 有两张网卡

Multus三种网络模式

Pod 注解 效果 实际效果
不带注解 走默认 CNI(Calico) 普通业务 Pod
k8s.v1.cni.cncf.io/networks: xxx 默认 CNI + 附加网络 双网卡 Pod
v1.multus-cni.io/default-network: xxx 替换默认网络 macvlan Pod(eth0 直接是 macvlan)

Multus专属CRD NAD

1
2
3
4
5
NAD(NetworkAttachmentDefinition)
- 是 Multus 的 CRD,相当于"网络说明书"
- Pod 注解里的名字指向 NAD
- Multus 读 NAD 的 config 字段,拿到 CNI 插件列表和参数
- 没有 NAD,Multus 不知道该调用哪些插件

whereabouts概述

host-local dhcp whereabouts
IP 记录在哪 节点本地文件 DHCP 服务器 K8s CRD(全局)
跨节点冲突 ❌ 会撞 ✅ 不撞(DHCP 管) ✅ 不撞(CRD 管)
外部依赖 无 DHCP 服务器 无(用 K8s API)
适用场景 单节点/测试 物理网络有 DHCP 多网络 + 跨节点

一个开源的 CNI IPAM 插件,专门为多网络场景设计。它解决的问题就一个:跨节点分配IP不冲突

1
2
3
macvlan Pod 的 IP 是物理网络的真实 IP(188.108.x.x),这个池子是所有节点共享的。假设节点 A 和节点 B 同时给 Pod 分 IP:
节点 A 的 host-local:分了 188.108.38.160
节点 B 的 host-local:也分了 188.108.38.160 ← 撞了!

工作原理

1
2
3
4
5
6
7
Pod 需要 IP
↓
whereabouts(跑在节点上)→ 去 K8s API 查 IP 池
↓
找一个没被占用的 IP → 写入 CRD 记录("188.108.38.160 分给 Pod X 了")
↓
返回 IP

Multus+whereabouts部署

环境3master 3worker 1controller-node

Calico/Flannel macvlan
流量路径 Pod → veth → 宿主机网络栈 → NAT/隧道 → 物理网卡 Pod → macvlan → 物理网卡(直接出去)
宿主机做啥 转发、NAT、封装(CPU 开销) 不做任何处理(零开销)
交换机看到 一个 MAC(宿主机) 多个 MAC(宿主机 + 每个 Pod)

部署 Multus

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
没有提供helm部署方式,直接使用manifests部署,
有两种部署模式,轻量版和完整版

轻量版
kubectl apply -f https://raw.githubusercontent.com/k8snetworkplumbingwg/multus-cni/master/deployments/multus-daemonset.yml

完整版
kubectl apply -f https://raw.githubusercontent.com/k8snetworkplumbingwg/multus-cni/master/deployments/multus-daemonset-thick.yml

kubectl get pods -n kube-system -w| grep multus
kube-multus-ds-22r25 1/1 Running 0 4m34s
kube-multus-ds-2bs22 1/1 Running 0 4m34s
kube-multus-ds-5cd2m 1/1 Running 0 4m34s
kube-multus-ds-gpc7l 1/1 Running 0 4m34s
kube-multus-ds-smwvs 1/1 Running 0 4m34s
kube-multus-ds-sn6wx 1/1 Running 0 4m34s

ls /etc/cni/net.d/ | grep multus
00-multus.conf
cat /etc/cni/net.d/00-multus.conf
{"capabilities":{"bandwidth":true,"portMappings":true},"cniVersion":"0.3.1","logLevel":"verbose","logToStderr":true,"name":"multus-cni-network","clusterNetwork":"/host/etc/cni/net.d/10-calico.conflist","type":"multus-shim"}

部署macvlan CNI 二进制

macvlan本质上也是二进制部署

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
每个节点都需要安装
CNI_VERSION=v1.5.1
wget https://github.com/containernetworking/plugins/releases/download/${CNI_VERSION}/cni-plugins-linux-amd64-${CNI_VERSION}.tgz

# 解压出 macvlan 到 /opt/cni/bin/
tar -xzf cni-plugins-linux-amd64-${CNI_VERSION}.tgz ./macvlan
cp macvlan /opt/cni/bin/
chmod +x /opt/cni/bin/macvlan

# 验证
ls /opt/cni/bin/ | grep macvlan


我直接用Ansible装了
# 1. 创建 /opt/cni/bin 目录
ansible -i inventory/sample/inventory.ini all -b -m file \
-a "path=/opt/cni/bin state=directory owner=root group=root mode=0755"

# 2. 下载 CNI tgz
ansible -i inventory/sample/inventory.ini all -b -m get_url \
-a "url=https://github.com/containernetworking/plugins/releases/download/v1.5.1/cni-plugins-linux-amd64-v1.5.1.tgz dest=/tmp/cni-plugins-linux-amd64-v1.5.1.tgz mode=0644 timeout=120"

# 3. 只解压 macvlan(creates 保证幂等)
ansible -i inventory/sample/inventory.ini all -b -m command \
-a "tar -xzf /tmp/cni-plugins-linux-amd64-v1.5.1.tgz -C /opt/cni/bin ./macvlan creates=/opt/cni/bin/macvlan"

# 4. 加可执行权限
ansible -i inventory/sample/inventory.ini all -b -m file \
-a "path=/opt/cni/bin/macvlan state=file owner=root group=root mode=0755"

# 5. 验证
ansible -i inventory/sample/inventory.ini all -m stat \
-a "path=/opt/cni/bin/macvlan get_checksum=false"

部署whereabouts

1
2
3
4
5
6
7
8
# CRD(IPPool 等自定义资源定义)
kubectl apply -f https://raw.githubusercontent.com/k8snetworkplumbingwg/whereabouts/master/doc/crds/whereabouts.cni.cncf.io_ippools.yaml

# 安装overlappingrangeipreservations
kubectl apply -f https://raw.githubusercontent.com/k8snetworkplumbingwg/whereabouts/master/doc/crds/whereabouts.cni.cncf.io_overlappingrangeipreservations.yaml

# DaemonSet(节点上运行的 whereabouts 二进制)
kubectl apply -f https://raw.githubusercontent.com/k8snetworkplumbingwg/whereabouts/master/doc/crds/daemonset-install.yaml

创建 macvlan NAD

https://www.cni.dev/plugins/current/main/macvlan/
把macvlan+whereabouts关联起来

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
节点网卡: eth0
节点网卡网段: 10.163.2.1-10.163.2.199

# macvlan-nad.yaml
apiVersion: k8s.cni.cncf.io/v1
kind: NetworkAttachmentDefinition
metadata:
name: macvlan-net
namespace: default
spec:
config: '{
"cniVersion": "0.3.1",
"name": "macvlan-net",
"type": "macvlan",
"master": "eth0",
"mode": "bridge",
"ipam": {
"type": "whereabouts",
"range": "192.168.1.0/24",
"range_start": "192.168.1.200",
"range_end": "192.168.1.250"
}
}'

kubectl apply -f macvlan-nad.yaml

kubectl get network-attachment-definitions -n default
NAME AGE
macvlan-net 10s

测试:附加网卡(双网卡)模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# pod-attach.yaml
apiVersion: v1
kind: Pod
metadata:
name: macvlan-attach
annotations:
k8s.v1.cni.cncf.io/networks: macvlan-net
spec:
containers:
- name: nginx
image: nginx:1.25
ports:
- containerPort: 80

kubectl apply -f pod-attach.yaml

kubectl get pod macvlan-attach -oyaml
...
k8s.v1.cni.cncf.io/network-status: |-
[{
"name": "k8s-pod-network",
"ips": [
"10.233.83.5"
],
"default": true,
"dns": {}
},{
"name": "default/macvlan-net",
"interface": "net1",
"ips": [
"192.168.1.200"
],
"mac": "72:9c:18:29:c2:6e",
"dns": {}
}]
...


可以看到获取到了第二个网卡

测试:替换默认网络模式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
# pod-default.yaml
apiVersion: v1
kind: Pod
metadata:
name: macvlan-default
annotations:
v1.multus-cni.io/default-network: default/macvlan-net
spec:
containers:
- name: busybox
image: busybox:1.36
command: ["sleep", "3600"]

kubectl apply -f pod-default.yaml

kubectl exec -it macvlan-default -- ip a
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
inet 127.0.0.1/8 scope host lo
valid_lft forever preferred_lft forever
inet6 ::1/128 scope host
valid_lft forever preferred_lft forever
2: eth0@eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue
link/ether ee:52:f9:65:42:ed brd ff:ff:ff:ff:ff:ff
inet 192.168.1.201/24 brd 192.168.1.255 scope global eth0
valid_lft forever preferred_lft forever
inet6 fe80::ec52:f9ff:fe65:42ed/64 scope link
valid_lft forever preferred_lft forever

可以看到这里只有一张网卡了

kubectl exec -it macvlan-default -- ping -c 2 192.168.1.200
PING 192.168.1.200 (192.168.1.200): 56 data bytes
64 bytes from 192.168.1.200: seq=0 ttl=64 time=0.800 ms
64 bytes from 192.168.1.200: seq=1 ttl=64 time=0.505 ms

--- 192.168.1.200 ping statistics ---
2 packets transmitted, 2 packets received, 0% packet loss
round-trip min/avg/max = 0.505/0.652/0.800 ms

测试上一个IP ping通

测试:查看分配记录

1
2
3
4
5
6
7
8
kubectl get ippools.whereabouts.cni.cncf.io -A
NAMESPACE NAME AGE
kube-system 192.168.1.0-24 14m

kubectl get overlappingrangeipreservations.whereabouts.cni.cncf.io -A
NAMESPACE NAME AGE
kube-system 192.168.1.200 12m
kube-system 192.168.1.201 7m39s
CATALOG
  1. 1. 背景
  2. 2. Linux版本单机macvlan
  3. 3. Multus概述
    1. 3.1. Multus三种网络模式
    2. 3.2. Multus专属CRD NAD
  4. 4. whereabouts概述
  5. 5. Multus+whereabouts部署
    1. 5.1. 部署 Multus
    2. 5.2. 部署macvlan CNI 二进制
    3. 5.3. 部署whereabouts
    4. 5.4. 创建 macvlan NAD
    5. 5.5. 测试:附加网卡(双网卡)模式
    6. 5.6. 测试:替换默认网络模式
    7. 5.7. 测试:查看分配记录