容器网络-4
系列前言
目前有三篇文章关于容器网络 , 分别是 :
- 容器网络-1 : 主要内容介绍 Network Namespace 和 Veth 设备对 , 也就是普通的 linux 的网络是如何通信的 .
- 容器网络-2 : 主要内容介绍 linux 的 iptable 和 路由是如何工作的 , 后半节介绍了大概 docker 和 k8s 的通信原理, 使用了什么网络技术
- 容器网络-3 : 主要内容介绍 容器用到的网络技术 .
概述
了解了前面的文章后, 我自己搭建了一个 K8S 集群 , 分别有 master-1 和 worker-2 , 在这个集群了我安装了 argoCD 用于发版我的应用 , argoCD 里面有个 repo-server , 启动以后会注册了一个 health check (调用自身的一个接口, 假如调用不通就会该 container 没启动 ,就会重新拉起一个新的 container ) , 问题就出在每次我挂起两台 VMware VM 再启动 , repo-server 就会一直重启 ,原因是 health check 一直不通 ,调用如下 :
Liveness probe failed: Get "http://10.244.254.159:8084/healthz?full=true": context deadline exceeded (Client.Timeout exceeded while awaiting headers)
为了验证这个是什么原因, 我在集群里起了一个 container 进行测试 :
kubectl run netshoot --rm -it --image=swr.cn-north-4.myhuaweicloud.com/ddn-k8s/docker.io/nicolaka/netshoot
发现 ping 都 ping 不通 , 检查路由 :
traceroute 10.244.254.159
traceroute也一直 pending , 我开始使用的是 calico 的 ipip 模式 ,后面又改到用 VXLAN , 按照 deepseek 的提示我查看了网络接口
[root@k8s-master ~]# ip link show vxlan.calico
36: vxlan.calico: <BROADCAST,MULTICAST> mtu 1450 qdisc noqueue state DOWN mode DEFAULT group default qlen 1000
link/ether 66:d5:cf:d3:6b:7e brd ff:ff:ff:ff:ff:ff
vxlan.calico 这个是个网络接口 , 可以看到 DOWN ,按照 deepseek 的教程 ,最后是把 calico 的网络模式改成了 :
ipipMode: Never
vxlanMode: Never
才可以的, 于是我开始学习相关的知识点.
网卡、网口
Ethernet n. 以太网
eth0 - 传统命名方式 , 传统命名方式,在较老的 Linux 系统中常见,命名不可预测:哪个物理网卡先被内核发现,谁就是 eth0,重启后可能改变 , 例如 eth0 ,eth2 ...
ens33 - 现代命名方式 , 现代 Linux 发行版(如 Ubuntu 16.04+、CentOS 7+)默认使用可预测命名,所以你看到的是 ens33
问 : 使用一种新的接口 , 一般都会有新的网络接口吗
是的,你的理解非常到位。
一般情况下,引入一种新的网络虚拟化技术或新的网络模式,通常都会在系统中创建一个(或多个)对应的虚拟网络接口。
我们可以把这个问题展开来看,这其实是 Linux 网络虚拟化中的一个核心概念。
1. 核心原理:虚拟网络接口是“操作入口”
在 Linux 中,无论是物理网卡(如 eth0)还是虚拟设备,都需要通过一个网络接口来被内核和用户空间程序(如 ip、iptables、route)管理。
当你启用某种新的网络功能时(比如创建 VXLAN 隧道、创建 Docker 网桥、创建容器虚拟网卡),系统会调用内核模块,实例化出一个具体的接口对象。这个接口就是你后续进行配置(IP 地址、状态、路由、防火墙规则)的唯一“把手”。
2. 典型例子对比
| 技术/场景 | 创建的新接口类型 | 接口名示例 | 说明 |
|---|---|---|---|
| VXLAN 隧道 | VXLAN 类型 | vxlan.calico, vxlan0 |
由 Calico 或用户手动创建,用于跨主机容器通信 |
| Bridge 桥接 | Bridge 类型 | docker0, br0, cni0 |
Docker 或 Kubernetes 创建,连接同一主机内的容器 |
| MACVLAN | MACVLAN 类型 | macvlan0 |
为容器分配独立 MAC 地址,直接暴露于物理网络 |
| 虚拟以太网对 | veth 类型 | veth1234@if5 |
容器启动时创建,一端在容器内(eth0),一端在宿主机(如 veth...) |
| Open vSwitch | OVS Bridge/Port | ovs-system, br-int |
OVS 创建的虚拟交换机接口 |
| IPIP 隧道 | tunnel 类型 | tunl0 |
Calico 默认的 IPIP 模式也会创建 tunl0 接口 |
可以看到,几乎每一种虚拟化或封装技术,都会在宿主机上体现为一个或多个网络接口。
3. 为什么一定需要这个接口?
这个接口的存在有几个关键作用:
-
配置挂载点
你需要通过这个接口来设置 IP 地址、MTU、状态(up/down)等。比如ip addr add 10.244.0.1/24 dev vxlan.calico。 -
数据路径节点
数据包在协议栈中的流转依赖接口。当容器发出的包需要经过 VXLAN 封装时,内核的路由表会指向vxlan.calico接口,然后该接口的驱动(VXLAN 模块)负责进行 UDP 封装。 -
状态和统计
你可以通过ifconfig或ip -s link查看该接口的收发包数量、错误计数等,用于监控和排错。 -
属于命名空间
接口属于某个网络命名空间(network namespace)。默认在根命名空间(宿主机),但也可以被移动到容器命名空间。没有接口对象,就无法实现命名空间之间的隔离与通信。
4. 特殊情况:接口是“隐式”的吗?
在一些高级场景中,你可能不直接看到传统意义上的接口,但本质仍然是接口:
- IPVS 或 iptables 的 DNAT:这些不创建新接口,但它们作用于现有接口或路由规则,本身不引入新设备。
- eBPF 直接挂载:在某些 eBPF 高级用法中,可能直接拦截网卡驱动层的报文,不创建显式虚拟接口,但这属于底层 bypass 场景,较少用于通用容器网络。
对于 Calico、Flannel、Cilium 这些主流容器网络方案,都会显式创建虚拟网络接口。即使 Cilium 默认使用 eBPF 加速,它也会创建 cilium_host、cilium_net 等接口作为锚点。
5. 回到你的例子
当你运行 Calico 并开启 VXLAN 模式时:
- Calico 会调用 Linux 内核的 VXLAN 模块
- 在内核中注册并创建一个名为
vxlan.calico的接口 - 这个接口的 type 是
vxlan - 之后,所有需要跨节点通信的 Pod 流量,经过路由规则匹配后,都会从
vxlan.calico出去,被封装成外层 UDP 包发送到对端节点
所以,是的,使用 VXLAN 这个协议时,一定会有一个对应的网络接口。 vxlan.calico 不是协议本身,而是该协议在系统中的具体实例。
ip 命令
[root@k8s-master ~]# ip link show vxlan.calico
36: vxlan.calico: <BROADCAST,MULTICAST> mtu 1450 qdisc noqueue state DOWN mode DEFAULT group default qlen 1000
link/ether 66:d5:cf:d3:6b:7e brd ff:ff:ff:ff:ff:ff
ip link 表示通过 man ip 命令可以查询到 link - network device. 也就是显示网络设备 , 几个常用的 :
EXAMPLES
ip addr
Shows addresses assigned to all network interfaces.
ip neigh
Shows the current neighbour table in kernel.
ip link set x up
Bring up interface x.
ip link set x down
Bring down interface x.
ip route
Show table routes.
例如 :
[root@k8s-master ~]# ip addr
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default 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: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
link/ether 00:0c:29:60:bb:24 brd ff:ff:ff:ff:ff:ff
inet 192.168.1.200/24 brd 192.168.1.255 scope global noprefixroute ens33
valid_lft forever preferred_lft forever
inet6 2409:8a55:a38:a790:9f9e:e797:8ed:c8c1/64 scope global noprefixroute dynamic
valid_lft 86388sec preferred_lft 86388sec
inet6 fe80::d17e:ea2c:f343:d6a0/64 scope link noprefixroute
valid_lft forever preferred_lft forever
3: br-67045ec19c43: <BROADCAST,MULTICAST> mtu 1500 qdisc noqueue state DOWN group default
link/ether 02:42:99:fd:eb:3b brd ff:ff:ff:ff:ff:ff
4: br-811e8d474e16: <BROADCAST,MULTICAST> mtu 1500 qdisc noqueue state DOWN group default
link/ether 02:42:9f:dc:92:60 brd ff:ff:ff:ff:ff:ff
...
7: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default
link/ether 02:42:8c:18:3c:28 brd ff:ff:ff:ff:ff:ff
inet 172.17.0.1/16 brd 172.17.255.255 scope global docker0
valid_lft forever preferred_lft forever
inet6 fe80::42:8cff:fe18:3c28/64 scope link
valid_lft forever preferred_lft forever
9: vetha95b644@if8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master br-811e8d474e16 state UP group default
link/ether 56:63:d3:63:7c:b4 brd ff:ff:ff:ff:ff:ff link-netnsid 4
inet6 fe80::5463:d3ff:fe63:7cb4/64 scope link
valid_lft forever preferred_lft forever
11: vetheeee8b5@if10: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master br-12802d2b30ed state UP group default
link/ether 6e:b7:43:87:79:3c brd ff:ff:ff:ff:ff:ff link-netnsid 1
inet6 fe80::6cb7:43ff:fe87:793c/64 scope link
valid_lft forever preferred_lft forever
...
194: calie77b911b10e@if3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
link/ether ee:ee:ee:ee:ee:ee brd ff:ff:ff:ff:ff:ff link-netnsid 6
inet6 fe80::ecee:eeff:feee:eeee/64 scope link
valid_lft forever preferred_lft forever
195: calie3c96318036@if3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default qlen 1000
link/ether ee:ee:ee:ee:ee:ee brd ff:ff:ff:ff:ff:ff link-netnsid 7
inet6 fe80::ecee:eeff:feee:eeee/64 scope link
valid_lft forever preferred_lft forever
[root@k8s-master ~]# ip link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1000
link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
link/ether 00:0c:29:60:bb:24 brd ff:ff:ff:ff:ff:ff
3: br-67045ec19c43: <BROADCAST,MULTICAST> mtu 1500 qdisc noqueue state DOWN mode DEFAULT group default
link/ether 02:42:99:fd:eb:3b brd ff:ff:ff:ff:ff:ff
4: br-811e8d474e16: <BROADCAST,MULTICAST> mtu 1500 qdisc noqueue state DOWN mode DEFAULT group default
link/ether 02:42:9f:dc:92:60 brd ff:ff:ff:ff:ff:ff
...
7: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default
link/ether 02:42:8c:18:3c:28 brd ff:ff:ff:ff:ff:ff
9: vetha95b644@if8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master br-811e8d474e16 state UP mode DEFAULT group default
link/ether 56:63:d3:63:7c:b4 brd ff:ff:ff:ff:ff:ff link-netnsid 4
11: vetheeee8b5@if10: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master br-12802d2b30ed state UP mode DEFAULT group default
link/ether 6e:b7:43:87:79:3c brd ff:ff:ff:ff:ff:ff link-netnsid 1
...
194: calie77b911b10e@if3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
link/ether ee:ee:ee:ee:ee:ee brd ff:ff:ff:ff:ff:ff link-netnsid 6
195: calie3c96318036@if3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP mode DEFAULT group default qlen 1000
link/ether ee:ee:ee:ee:ee:ee brd ff:ff:ff:ff:ff:ff link-netnsid 7
ip addr add 192.168.1.201/24 dev ens33
ip route add default via 192.168.1.1 dev ens33
什么时候用 IPIP / VXLAN (VXLAN/IPIP 模式的实际应用场景)
让我用几个真实的企业级例子来说明什么时候需要用到 VXLAN/IPIP 隧道模式。
📋 场景1:混合云架构(AWS + 阿里云)
网络拓扑:
┌─────────────────────────────────────────────────────────────┐
│ 互联网/VPN │
└─────────────────────────────────────────────────────────────┘
│ │
┌────┴────┐ ┌───┴────┐
│ AWS VPC │ │阿里云 VPC│
│10.0.0.0/16│ │172.16.0.0/12│
└─────────┘ └─────────┘
│ │
┌────┴────┐ ┌───┴────┐
│Master节点│ │Worker节点│
│10.0.1.10│ │172.16.1.20│
└─────────┘ └─────────┘
│ │
Pod CIDR: 10.244.1.0/24 Pod CIDR: 10.244.2.0/24
为什么需要隧道?
- Master 在 AWS(10.0.x.x),Worker 在阿里云(172.16.x.x)
- 不同云厂商,IP 段完全不同
- 中间经过 VPN/专线,不能直接路由
- VXLAN 封装后,底层走 VPN,上层是统一的 Pod 网络
📋 场景2:混合云(IDC + 公有云)
网络拓扑:
┌──────────────────────────┐ ┌─────────────────────────┐
│ 自建 IDC 机房 │ │ 华为云 VPC │
│ 192.168.1.0/24 │ │ 10.0.1.0/24 │
│ ┌──────────────────┐ │ │ ┌──────────────────┐ │
│ │ Master + Worker1 │ │ VPN │ │ Worker2 + Worker3│ │
│ │ 192.168.1.10/24 │ │◄────►│ │ 10.0.1.20/24 │ │
│ └──────────────────┘ │ │ └──────────────────┘ │
│ Pod CIDR: 10.244.1.0/24│ │ Pod CIDR: 10.244.2.0/24│
└──────────────────────────┘ └─────────────────────────┘
为什么需要隧道?
- IDC 使用 192.168.x.x,云上使用 10.0.x.x
- 通过 VPN 连接,但 IP 段不连续
- 需要 VXLAN 创建 Overlay 网络,让 Pod 无视底层网络差异
📋 场景3:多机房分布式集群
网络拓扑:
┌───────────────────┐ ┌───────────────────┐
│ 北京机房 │ │ 上海机房 │
│ 10.1.0.0/16 │ │ 10.2.0.0/16 │
│ ┌─────────────┐ │ MPLS│ ┌─────────────┐ │
│ │ Master节点 │ │◄────►│ │ Worker节点 │ │
│ │ 10.1.1.10 │ │专线 │ │ 10.2.1.20 │ │
│ └─────────────┘ │ │ └─────────────┘ │
│ Pod CIDR: │ │ Pod CIDR: │
│ 10.244.1.0/24 │ │ 10.244.2.0/24 │
└───────────────────┘ └───────────────────┘
为什么需要隧道?
- 跨机房,物理网络隔离
- 虽然有 MPLS 专线,但两个机房的 IP 段不同
- 需要隧道实现跨机房 Pod 通信
📋 场景4:租户隔离的多集群
网络拓扑:
┌─────────────────────────────────────────────┐
│ 总公司网络 172.16.0.0/16 │
│ ┌──────────────┐ ┌──────────────┐ │
│ │ 业务A集群 │ │ 业务B集群 │ │
│ │ 172.16.1.0/24│ │ 172.16.2.0/24│ │
│ │ Pod: │ │ Pod: │ │
│ │ 10.244.1.0/24│ │ 10.244.2.0/24│ │
│ └──────────────┘ └──────────────┘ │
│ │ │ │
│ ┌────┴────┐ ┌───┴────┐ │
│ │ 防火墙 │ │ 防火墙 │ │
│ └─────────┘ └─────────┘ │
└─────────────────────────────────────────────┘
为什么需要隧道?
- 不同业务集群虽然在同一总公司网络,但通过防火墙隔离
- 防火墙策略只允许特定协议(如 UDP 4789)通过
- 需要 VXLAN 封装来穿透防火墙
🔧 实际配置示例
场景1的 Calico 配置:
# 跨云集群的 IP Pool 配置
apiVersion: projectcalico.org/v3
kind: IPPool
metadata:
name: cross-cloud-pool
spec:
cidr: 10.244.0.0/16
ipipMode: Always # 或 CrossSubnet
vxlanMode: Never # 或 Always
natOutgoing: true
nodeSelector: all()
跨云场景的 BGP 配置:
# 在 Calico 配置中设置 AS Number
cat > calico-config.yaml << EOF
apiVersion: projectcalico.org/v3
kind: BGPConfiguration
metadata:
name: default
spec:
logSeverityScreen: Info
nodeToNodeMeshEnabled: true
asNumber: 64512
serviceClusterIPs:
- cidr: 10.96.0.0/12
serviceExternalIPs:
- cidr: 0.0.0.0/0
EOF
kubectl apply -f calico-config.yaml
📊 不同模式的适用场景对比
| 场景 | 网络环境 | 推荐模式 | 原因 |
|---|---|---|---|
| 开发测试 | 单机房,同网段 | host-local | 简单,性能好 |
| 生产环境 | 单机房,多网段 | VXLAN | 隔离性好,易扩展 |
| 混合云 | 跨云厂商 | VXLAN/IPIP | 必须用隧道 |
| 多机房 | 跨地域 | VXLAN | 封装后便于管理 |
| 多租户 | 隔离网络 | VXLAN | 安全隔离 |
| 边缘计算 | 网络复杂 | IPIP | 轻量级封装 |
🎯 真实企业案例
案例1:某电商公司混合云架构
- 核心业务:自建机房(192.168.0.0/16)
- 弹性计算:阿里云(10.0.0.0/8)
- 灾备:AWS(172.31.0.0/16)
- 网络方案:Calico VXLAN
- 结果:统一的 Pod 网络,业务可跨云调度
案例2:某金融机构多机房部署
- 北京主数据中心:10.1.0.0/16
- 上海灾备中心:10.2.0.0/16
- 深圳研发中心:10.3.0.0/16
- 网络方案:Calico IPIP + BGP
- 结果:三地 K8s 集群统一管理
案例3:某 SaaS 服务商混合云
- 生产环境:AWS(多个 VPC)
- 测试环境:本地 IDC
- 开发环境:个人电脑(Docker Desktop)
- 网络方案:Calico VXLAN
- 结果:开发-测试-生产环境网络一致
💡 如何判断是否需要隧道模式
问自己几个问题:
-
所有节点 IP 在同一网段吗?
- 是 → 可以用 host-local
- 否 → 需要隧道
-
节点之间有防火墙隔离吗?
- 是 → 隧道可穿透防火墙
- 否 → host-local 够用
-
未来会跨云/跨机房扩展吗?
- 是 → 提前用隧道模式,方便扩展
- 否 → host-local 更简单
-
对网络性能要求极高吗?
- 是 → host-local(避免封装开销)
- 否 → 隧道模式可接受
🎉 总结
- host-local:适合同网段、简单网络、追求性能的场景
- VXLAN/IPIP:适合跨网段、混合云、需要网络隔离的场景
你的三节点集群在同一网段(192.168.1.x),使用 host-local 模式完全正确!如果未来要扩展到云上或跨机房,再切换到 VXLAN 模式也不迟。

浙公网安备 33010602011771号