容器网络-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)还是虚拟设备,都需要通过一个网络接口来被内核和用户空间程序(如 ipiptablesroute)管理。

当你启用某种新的网络功能时(比如创建 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. 为什么一定需要这个接口?

这个接口的存在有几个关键作用:

  1. 配置挂载点
    你需要通过这个接口来设置 IP 地址、MTU、状态(up/down)等。比如 ip addr add 10.244.0.1/24 dev vxlan.calico

  2. 数据路径节点
    数据包在协议栈中的流转依赖接口。当容器发出的包需要经过 VXLAN 封装时,内核的路由表会指向 vxlan.calico 接口,然后该接口的驱动(VXLAN 模块)负责进行 UDP 封装。

  3. 状态和统计
    你可以通过 ifconfigip -s link 查看该接口的收发包数量、错误计数等,用于监控和排错。

  4. 属于命名空间
    接口属于某个网络命名空间(network namespace)。默认在根命名空间(宿主机),但也可以被移动到容器命名空间。没有接口对象,就无法实现命名空间之间的隔离与通信。


4. 特殊情况:接口是“隐式”的吗?

在一些高级场景中,你可能不直接看到传统意义上的接口,但本质仍然是接口:

  • IPVS 或 iptables 的 DNAT:这些不创建新接口,但它们作用于现有接口或路由规则,本身不引入新设备。
  • eBPF 直接挂载:在某些 eBPF 高级用法中,可能直接拦截网卡驱动层的报文,不创建显式虚拟接口,但这属于底层 bypass 场景,较少用于通用容器网络。

对于 Calico、Flannel、Cilium 这些主流容器网络方案,都会显式创建虚拟网络接口。即使 Cilium 默认使用 eBPF 加速,它也会创建 cilium_hostcilium_net 等接口作为锚点。


5. 回到你的例子

当你运行 Calico 并开启 VXLAN 模式时:

  • Calico 会调用 Linux 内核的 VXLAN 模块
  • 在内核中注册并创建一个名为 vxlan.calico 的接口
  • 这个接口的 typevxlan
  • 之后,所有需要跨节点通信的 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
- 结果:开发-测试-生产环境网络一致

💡 如何判断是否需要隧道模式

问自己几个问题:

  1. 所有节点 IP 在同一网段吗?

    • 是 → 可以用 host-local
    • 否 → 需要隧道
  2. 节点之间有防火墙隔离吗?

    • 是 → 隧道可穿透防火墙
    • 否 → host-local 够用
  3. 未来会跨云/跨机房扩展吗?

    • 是 → 提前用隧道模式,方便扩展
    • 否 → host-local 更简单
  4. 对网络性能要求极高吗?

    • 是 → host-local(避免封装开销)
    • 否 → 隧道模式可接受

🎉 总结

  • host-local:适合同网段、简单网络、追求性能的场景
  • VXLAN/IPIP:适合跨网段、混合云、需要网络隔离的场景

你的三节点集群在同一网段(192.168.1.x),使用 host-local 模式完全正确!如果未来要扩展到云上或跨机房,再切换到 VXLAN 模式也不迟。

posted @ 2026-03-26 13:28  float123  阅读(2)  评论(0)    收藏  举报