跳过正文
  1. 博客文章/

K8S 使用 Multus 接入 Macvlan

·802 字·4 分钟·
DevOps Kubernetes Kubernetes Multus Macvlan CNI VLAN DevOps
Zayn
作者
Zayn
专注 Kubernetes、CI/CD、可观测性等云原生技术栈,记录生产环境中的实战经验与踩坑复盘。
目录
生产变更复盘 - 这篇文章属于一个选集。
7: 本文
Kubernetes 默认 CNI 只解决集群内网络。遇到需要让 Pod 直接接入某个 VLAN、拿到独立二层地址的场景,可以用 Multus 给 Pod 追加一块 macvlan 网卡。
文中保留了节点标签和 Multus 启动截图的现场信息。命令里的网段、网关、DNS 和镜像仓库按示例值处理,落地时替换为自己的 VLAN 规划。

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-local IPAM 在多节点 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

Multus DaemonSet 在目标节点运行

继续条件:

检查项命令通过标准
CRDkubectl get crd network-attachment-definitions.k8s.cni.cncf.ioCRD 存在
DaemonSetkubectl get ds -n kube-system kube-multus-dsDesired 和 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 容易踩地址分配边界
dhcpVLAN 内已有 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-deploymentREADY 等于期望副本
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. 参考
#

生产变更复盘 - 这篇文章属于一个选集。
7: 本文

相关文章

使用 Kaniko 在 Kubernetes 中构建 Docker 镜像
·468 字·3 分钟
CI/CD Kubernetes DevOps Kaniko Docker Kubernetes
使用 helm 在 Kubernetes 中部署 Nexus 私服
·1047 字·5 分钟
Helm Kubernetes DevOps Nexus3 Kubernetes
Restic 备份实践
·1188 字·6 分钟
SRE DevOps Restic Backup DevOps +2