0. 结论和边界#
这次配置的目标很直接:只在打了标签的节点上部署 Multus,并让指定 Pod 通过 NetworkAttachmentDefinition 接入 VLAN macvlan 网络。
当前路径分成四步:
- 交换机侧把目标端口加入 VLAN。
- 节点侧先用 Linux VLAN 子接口验证二层连通。
- Kubernetes 里部署 Multus DaemonSet,并用 node label 限制节点范围。
- 创建
NetworkAttachmentDefinition,Pod 通过注解挂载第二张网卡。
边界也要先讲清楚:
- macvlan 不是 Kubernetes Service 网络,不会自动接入 kube-proxy 负载均衡。
- 同一 macvlan 网络里,宿主机默认不一定能直接访问 Pod IP。
host-localIPAM 在多节点 Deployment 场景容易产生地址管理问题,需要提前规划。- DHCP 模式需要 CNI DHCP daemon 常驻运行,否则 Pod 无法拿地址。
上线前先把变更分成两个阶段:先用单 Pod 验证 VLAN 和 NAD,再决定是否放开到 Deployment。不要在静态 IP 示例还没验证时直接创建多副本工作负载。
1. 先在节点验证 VLAN#
不要直接上 Kubernetes。先在目标节点用系统命令验证 VLAN 是否通。
ip link add link enp10s0 name enp10s0.1111 type vlan id 1111
ip link set enp10s0.1111 up
ip -d link show enp10s0.1111
ip addr add 198.51.100.201/24 dev enp10s0.1111
ping 198.51.100.1
如果这一步不通,先查交换机端口、VLAN member、上联 trunk、网关和 ACL。Multus 不能修复底层二层网络问题。
测试完成后清理临时地址:
ip addr del 198.51.100.201/24 dev enp10s0.1111
ip link del enp10s0.1111
Review Gate:
| 检查项 | 命令 | 继续条件 | 停止条件 |
|---|---|---|---|
| VLAN 子接口 | ip -d link show enp10s0.1111 | 子接口存在且 UP | 子接口创建失败 |
| 网关连通 | ping -c 3 198.51.100.1 | 丢包为 0 或符合现场基线 | 网关不可达 |
| 节点标签范围 | kubectl get node --show-labels | 只给目标节点打标签 | 标签范围不清楚 |
| CNI 目录 | ls /etc/cni/net.d /opt/cni/bin | 目录存在 | 节点 CNI 路径异常 |
2. 部署 Multus#
Multus 的上游 quickstart 清单适合快速验证。生产环境建议固定镜像版本,并把配置纳入 GitOps。
核心配置有两点:
- CRD:
NetworkAttachmentDefinition。 - DaemonSet:把 Multus binary 和 CNI 配置写入每个目标节点。
示例里保留 node selector,只让有标签的节点运行 Multus:
spec:
template:
spec:
hostNetwork: true
nodeSelector:
network: multus-enabled
serviceAccountName: multus
给目标节点打标签:
kubectl label node cpdevice-amd1 network=multus-enabled
kubectl label node cpdevice-amd2 network=multus-enabled
部署后检查:
kubectl get pods -n kube-system -l app=multus -o wide
现场验证里,两个目标节点上的 Multus Pod 都已经进入 Running:

继续条件:
| 检查项 | 命令 | 通过标准 |
|---|---|---|
| CRD | kubectl get crd network-attachment-definitions.k8s.cni.cncf.io | CRD 存在 |
| DaemonSet | kubectl get ds -n kube-system kube-multus-ds | Desired 和 Ready 一致 |
| 节点范围 | kubectl get pod -n kube-system -l app=multus -o wide | 只出现在目标节点 |
| CNI 文件 | ls /etc/cni/net.d/ | 能看到 Multus 配置 |
3. 创建 NetworkAttachmentDefinition#
静态地址适合少量固定 Pod,配置最直观:
kubectl apply -f - <<'EOF'
apiVersion: k8s.cni.cncf.io/v1
kind: NetworkAttachmentDefinition
metadata:
name: vlan1111-net
spec:
config: '{
"cniVersion": "0.3.1",
"type": "macvlan",
"master": "enp10s0.1111",
"mode": "bridge",
"ipam": {
"type": "static",
"addresses": [
{
"address": "198.51.100.50/24",
"gateway": "198.51.100.1"
}
],
"routes": [
{ "dst": "0.0.0.0/0", "gw": "198.51.100.1" }
],
"dns": {
"nameservers": ["198.51.100.1"]
}
}
}'
EOF
如果要接入另一个 VLAN,只改 master、网段、网关和 DNS:
{
"master": "enp10s0.310",
"ipam": {
"type": "static",
"addresses": [
{
"address": "203.0.113.50/24",
"gateway": "203.0.113.1"
}
]
}
}
4. IPAM 方式选择#
这次材料里涉及三种方式。不要混用,先按场景选一个。
| IPAM | 适用场景 | 注意点 |
|---|---|---|
static | 少量固定 Pod、临时验证 | 每个 Pod 地址要人工避免冲突 |
host-local | 单节点或地址池清晰的场景 | 多节点 Deployment 容易踩地址分配边界 |
dhcp | VLAN 内已有 DHCP 服务 | 需要 CNI DHCP daemon 常驻 |
host-local 示例:
kubectl apply -f - <<'EOF'
apiVersion: k8s.cni.cncf.io/v1
kind: NetworkAttachmentDefinition
metadata:
name: vlan310-net
spec:
config: '{
"cniVersion": "0.3.1",
"type": "macvlan",
"master": "enp10s0.310",
"mode": "bridge",
"ipam": {
"type": "host-local",
"ranges": [
[
{
"subnet": "203.0.113.0/24",
"rangeStart": "203.0.113.40",
"rangeEnd": "203.0.113.50",
"gateway": "203.0.113.1"
}
]
],
"routes": [
{ "dst": "0.0.0.0/0", "gw": "203.0.113.1" }
],
"dns": {
"nameservers": ["203.0.113.1"]
}
}
}'
EOF
DHCP 模式配置更短:
kubectl apply -f - <<'EOF'
apiVersion: k8s.cni.cncf.io/v1
kind: NetworkAttachmentDefinition
metadata:
name: vlan1111-net
spec:
config: '{
"cniVersion": "0.3.1",
"type": "macvlan",
"master": "enp10s0.1111",
"mode": "bridge",
"ipam": {
"type": "dhcp"
}
}'
EOF
但每个目标节点都要启动 DHCP daemon:
cd /opt/cni/bin/
./dhcp daemon -hostprefix /host
这一步建议改成 systemd 或 DaemonSet 托管,不要靠人工会话长期运行。
5. Pod 验证#
先做单 Pod 验证。这个示例可以配合 static IPAM 使用,因为只有一个 Pod 会拿到固定地址。
kubectl apply -f - <<'EOF'
apiVersion: v1
kind: Pod
metadata:
name: vlan-pod
annotations:
k8s.v1.cni.cncf.io/networks: vlan1111-net
spec:
nodeSelector:
network: multus-enabled
containers:
- name: network-multitool
image: registry.example.internal/praqma/network-multitool
command: ["sh", "-c", "ip addr; sleep 3600"]
EOF
查看附加网卡:
kubectl exec -it vlan-pod -- ip addr
kubectl exec -it vlan-pod -- ip route
kubectl exec -it vlan-pod -- ping -c 3 198.51.100.1
如果单 Pod 验证通过,再考虑 Deployment。这里不要继续使用 static 的单地址配置;多副本至少要换成 host-local 地址池或 DHCP。下面的 Deployment 示例假设 vlan1111-net 已经改成可分配多个地址的 IPAM。
kubectl apply -f - <<'EOF'
apiVersion: apps/v1
kind: Deployment
metadata:
name: vlan-pod-deployment
spec:
replicas: 2
selector:
matchLabels:
app: vlan-pod-deployment
template:
metadata:
labels:
app: vlan-pod-deployment
annotations:
k8s.v1.cni.cncf.io/networks: vlan1111-net
spec:
nodeSelector:
network: multus-enabled
containers:
- name: network-multitool
image: registry.example.internal/praqma/network-multitool
command: ["sh", "-c", "ip addr; sleep 3600"]
EOF
Deployment 验证标准:
| 检查项 | 命令 | 通过标准 |
|---|---|---|
| 副本就绪 | kubectl get deploy vlan-pod-deployment | READY 等于期望副本 |
| Pod 分布 | kubectl get pod -o wide -l app=vlan-pod-deployment | 调度到带标签节点 |
| 附加网卡 | kubectl exec <pod> -- ip addr | 出现 macvlan 网卡和独立地址 |
| 地址唯一 | kubectl exec <pod> -- ip -o -4 addr | 多副本地址不重复 |
| 网关连通 | kubectl exec <pod> -- ping -c 3 198.51.100.1 | 能 ping 通 |
6. 回滚#
先删除测试负载:
kubectl delete pod vlan-pod --ignore-not-found
kubectl delete deploy vlan-pod-deployment --ignore-not-found
再删除网络定义:
kubectl delete network-attachment-definition vlan1111-net --ignore-not-found
kubectl delete network-attachment-definition vlan310-net --ignore-not-found
最后按需移除 Multus 和节点标签:
kubectl label node cpdevice-amd1 network-
kubectl label node cpdevice-amd2 network-
kubectl delete -f multus.yaml
不要先删 Multus 再删业务 Pod,否则 Pod 删除和重建时可能卡在 CNI 清理阶段。
如果回滚后节点上仍残留 VLAN 子接口或 DHCP daemon,按节点逐台清理:
ip link show enp10s0.1111 && ip link del enp10s0.1111
pkill -f "/opt/cni/bin/dhcp daemon" || true
7. 常见问题#
Pod 创建失败,事件里提示找不到网络
先确认 NetworkAttachmentDefinition 和 Pod 在同一个 namespace。NAD 是 namespaced 资源。
Multus Pod 没有调度到目标节点
检查节点标签:
kubectl get node --show-labels | grep multus-enabled
Pod 有第二张网卡,但外部 ping 不通
按顺序查 VLAN 子接口、交换机 VLAN member、网关 ACL、Pod 路由和上游防火墙。macvlan 已经把 Pod 接到二层网络,后续问题通常在网络侧。
Deployment 多副本地址冲突
如果使用 static,每个 Pod 都会拿同一个地址;如果使用 host-local,多节点下地址池状态由节点本地维护。多副本场景要重新设计 IPAM。
8. 参考#
- CNI plugins releases:https://github.com/containernetworking/plugins/releases
- Multus CNI:https://github.com/k8snetworkplumbingwg/multus-cni
- Network Plumbing Working Group:https://github.com/k8snetworkplumbingwg
