Flannel 跨主机容器网络完全指南:从 ETCD 到 VXLAN 的生产级实践

作者:云原生架构师
技术栈:Flannel, ETCD, VXLAN, Kubernetes CNI, Linux Network
难度等级:★★★★★(专家级)
预计阅读时间:100 分钟


目录

  1. [引言:Flannel 项目概述](#1-引言 flannel-项目概述)
  2. Flannel 架构深度解析
  3. ETCD 分布式数据库详解
  4. 主机环境准备
  5. ETCD 集群部署
  6. Flannel 部署与配置
  7. Docker 网络集成
  8. 跨主机通信验证
  9. Flannel 后端详解
  10. Kubernetes CNI 集成
  11. 故障排查实战
  12. 性能优化与最佳实践

1. 引言:Flannel 项目概述

1.1 Flannel 项目背景

什么是 Flannel?

Flannel = 简单的虚拟网络覆盖层

由 CoreOS 开发(2015 年)
现属 CNCF 项目

目标:
- 为容器提供简单的 Layer 3 网络
- 支持多种后端(VXLAN, UDP, AWS VPC 等)
- 易于部署和管理
- 与 Kubernetes 深度集成

Flannel vs Docker Overlay

┌─────────────────────────────────────────────────────┐
│  Flannel vs Docker Overlay 对比                      │
├─────────────────────────────────────────────────────┤
│  特性            Flannel        Docker Overlay      │
├─────────────────────────────────────────────────────┤
│  复杂度          简单           中等                │
│  依赖            ETCD           Swarm               │
│  后端支持        多种           VXLAN only          │
│  Kubernetes 集成  CNI 插件       需要额外配置         │
│  性能            优秀           优秀                │
│  加密            不支持         IPsec 支持           │
│  适用场景        K8s 集群       Swarm 集群           │
└─────────────────────────────────────────────────────┘

1.2 Flannel 应用场景

场景 1:Kubernetes 集群网络

K8s 集群:
┌──────────┐    ┌──────────┐    ┌──────────
│  Master  │    │  Node1   │    │  Node2   │
│          │    │ Pod:10.1 │    │ Pod:10.2 │
└──────────┘    └──────────    └──────────┘
       │               │               │
       └───────────────┼───────────────┘
                       │
              ┌────────▼────────┐
              │    Flannel      │
              │  VXLAN Backend  │
              └─────────────────┘

所有 Pod 可以直接通信
无需 NAT,无需端口映射

场景 2:多主机 Docker 容器

传统 Docker:
- 单机部署
- Bridge 网络

Flannel:
- 多机部署
- 统一网络
- 容器跨主机通信

2. Flannel 架构深度解析

2.1 Flannel 核心组件

架构图

Host B

Host A

ETCD Cluster

VXLAN 隧道

ETCD Server 1

ETCD Server 2

ETCD Server 3

flanneld

flannel.1
VXLAN 接口

cni0 网桥

Container 1
10.1.1.2

flanneld

flannel.1
VXLAN 接口

cni0 网桥

Container 2
10.1.2.2

核心组件说明

1. ETCD 集群
   - 存储网络配置
   - 存储子网分配
   - 存储 VTEP 信息

2. flanneld(每个主机)
   - 监听 ETCD 配置变化
   - 分配本地子网
   - 配置网络接口
   - 设置路由表

3. 网络接口
   - flannel.1: VXLAN 接口
   - cni0: 容器网桥
   - docker0: Docker 网桥(可选)

4. 后端(Backend)
   - VXLAN(默认)
   - UDP(已废弃)
   - AWS VPC
   - GCE
   - Alibaba Cloud

2.2 Flannel 工作流程

初始化流程

flanneld (Host2) flanneld (Host1) ETCD 集群 管理员 flanneld (Host2) flanneld (Host1) ETCD 集群 管理员 Network: 10.0.0.0/8 SubnetLen: /24 分配 10.1.1.0/24 分配 10.1.2.0/24 Host2: 10.1.2.0/24 Host1: 10.1.1.0/24 10.1.2.0/24 via 192.168.1.20 10.1.1.0/24 via 192.168.1.10 1. 注册网络配置 2. 监听网络配置 返回配置 3. 注册本地子网 4. 监听网络配置 返回配置 5. 注册本地子网 6. 通知新子网 7. 通知新子网 8. 配置路由 9. 配置路由

详细步骤

步骤 1:注册网络配置

# 在 ETCD 中注册
etcdctl mk /coreos.com/network/config '{
  "Network": "10.0.0.0/8",
  "SubnetLen": 24,
  "Backend": {
    "Type": "vxlan"
  }
}'

步骤 2-3:Host1 加入网络

# flanneld 启动
flanneld \
  --etcd-endpoints=http://192.168.1.10:2379 \
  --public-ip=192.168.1.10 \
  --iface=eth0

# flanneld 行为:
1. 从 ETCD 获取网络配置
2. 检查可用子网
3. 分配 10.1.1.0/24
4. 在 ETCD 注册:
   /coreos.com/network/subnets/10.1.1.0-24
   {
     "PublicIP": "192.168.1.10",
     "BackendType": "vxlan",
     "BackendData": {
       "VtepMAC": "aa:bb:cc:dd:ee:01"
     }
   }

步骤 4-5:Host2 加入网络

# 类似 Host1
# 分配 10.1.2.0/24
# 在 ETCD 注册

步骤 6-7:ETCD 通知

# ETCD Watch 机制
# 当新子网注册时
# 通知所有已注册的 flanneld

# Host1 flanneld 收到通知:
# "新子网 10.1.2.0/24 在 192.168.1.20"

# Host2 flanneld 收到通知:
# "新子网 10.1.1.0/24 在 192.168.1.10"

步骤 8-9:配置路由

# Host1 配置路由
ip route add 10.1.2.0/24 via 192.168.1.20 dev flannel.1

# Host2 配置路由
ip route add 10.1.1.0/24 via 192.168.1.10 dev flannel.1

# 查看路由表
ip route show

# 输出:
# 10.1.1.0/24 dev cni0 proto kernel scope link src 10.1.1.1
# 10.1.2.0/24 via 192.168.1.20 dev flannel.1

3. ETCD 分布式数据库详解

3.1 ETCD 基础架构

什么是 ETCD?

ETCD = 分布式键值存储

特点:
- 强一致性(Raft 协议)
- 高可用(多节点集群)
- 高性能(万级 QPS)
- Watch 机制(实时通知)

用途:
- 服务发现
- 配置管理
- 分布式锁
- 网络状态存储(Flannel)

Raft 共识算法

┌─────────────────────────────────────────────────────┐
│  ETCD Raft 集群                                      │
├─────────────────────────────────────────────────────┤
│  ┌──────────┐  ┌──────────  ┌──────────┐         │
│  │ Leader   │  │ Follower │  │ Follower │         │
│  │ Node1    │  │ Node2    │  │ Node3    │         │
│  └──────────┘  └──────────  └──────────┘         │
│       │                                              │
│       │ 1. Client Write                             │
│       ▼                                              │
│  追加日志                                            │
│       │                                              │
│       │ 2. Replicate to Followers                   │
│       ▼                                              │
│  ┌──────────┐  ┌──────────                        │
│  │ Append   │  │ Append   │                        │
│  └──────────┘  └──────────┘                        │
│       │                                              │
│       │ 3. Commit when majority                     │
│       ▼                                              │
│  应用到状态机                                        │
│       │                                              │
│       │ 4. Response to Client                       │
└─────────────────────────────────────────────────────┘

最少节点数:
- 生产:3 节点(容忍 1 故障)
- 高可用:5 节点(容忍 2 故障)

3.2 ETCD 集群部署

单节点部署(测试)

# 使用 Docker 运行 ETCD
docker run -d \
  --name etcd \
  -p 2379:2379 \
  -p 2380:2380 \
  -v /opt/etcd/data:/etcd-data \
  -e ETCD_DATA_DIR=/etcd-data \
  quay.io/coreos/etcd:v3.5.9 \
  etcd \
  --name etcd-single \
  --data-dir /etcd-data \
  --listen-client-urls http://0.0.0.0:2379 \
  --advertise-client-urls http://localhost:2379 \
  --listen-peer-urls http://0.0.0.0:2380 \
  --initial-advertise-peer-urls http://localhost:2380 \
  --initial-cluster etcd-single=http://localhost:2380 \
  --initial-cluster-token my-etcd-token \
  --initial-cluster-state new \
  --auto-compaction-retention=1

# 验证
docker exec etcd etcdctl endpoint health
# 输出:http://localhost:2379: is healthy

三节点集群部署(生产)

# 节点 1 (192.168.1.10)
docker run -d \
  --name etcd \
  -p 2379:2379 \
  -p 2380:2380 \
  -v /opt/etcd/data:/etcd-data \
  quay.io/coreos/etcd:v3.5.9 \
  etcd \
  --name etcd-node1 \
  --data-dir /etcd-data \
  --listen-client-urls http://0.0.0.0:2379 \
  --advertise-client-urls http://192.168.1.10:2379 \
  --listen-peer-urls http://0.0.0.0:2380 \
  --initial-advertise-peer-urls http://192.168.1.10:2380 \
  --initial-cluster etcd-node1=http://192.168.1.10:2380,etcd-node2=http://192.168.1.20:2380,etcd-node3=http://192.168.1.30:2380 \
  --initial-cluster-token my-etcd-token \
  --initial-cluster-state new \
  --auto-compaction-retention=1 \
  --quota-backend-bytes=8589934592 \
  --heartbeat-interval=100 \
  --election-timeout=1000

# 节点 2 (192.168.1.20)
# 修改 --name, --advertise-client-urls, --initial-advertise-peer-urls

# 节点 3 (192.168.1.30)
# 修改 --name, --advertise-client-urls, --initial-advertise-peer-urls

验证集群状态

# 检查成员
docker exec etcd etcdctl member list

# 输出:
# 422a74f03b622b7d, started, etcd-node1, http://192.168.1.10:2380, http://192.168.1.10:2379
# 8a3f5e9c1d2b4a6f, started, etcd-node2, http://192.168.1.20:2380, http://192.168.1.20:2379
# c5d7e9f1a3b5c7d9, started, etcd-node3, http://192.168.1.30:2380, http://192.168.1.30:2379

# 检查健康
docker exec etcd etcdctl endpoint health

# 输出:
# http://192.168.1.10:2379: is healthy
# http://192.168.1.20:2379: is healthy
# http://192.168.1.30:2379: is healthy

# 检查 Leader
docker exec etcd etcdctl endpoint status --write-out=table

# 输出:
# +--------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
# |      ENDPOINT      |        ID        | VERSION | DB SIZE | IS LEADER | IS LEARNER | RAFT TERM | RAFT INDEX | RAFT APPLIED INDEX | ERRORS |
# +--------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+
# | 192.168.1.10:2379  | 422a74f03b622b7d |   3.5.9 |  20 kB  |     true  |      false |         2 |         11 |                 11 |        |
# | 192.168.1.20:2379  | 8a3f5e9c1d2b4a6f |   3.5.9 |  20 kB  |     false |      false |         2 |         11 |                 11 |        |
# | 192.168.1.30:2379  | c5d7e9f1a3b5c7d9 |   3.5.9 |  20 kB |     false |      false |         2 |         11 |                 11 |        |
# +--------------------+------------------+---------+---------+-----------+------------+-----------+------------+--------------------+--------+

3.3 ETCD 操作详解

基本操作

# 写入数据
etcdctl put /key "value"

# 读取数据
etcdctl get /key

# 删除数据
etcdctl del /key

# 列出所有键
etcdctl get / --prefix --keys-only

Flannel 相关操作

# 注册网络配置
etcdctl put /coreos.com/network/config '{
  "Network": "10.0.0.0/8",
  "SubnetLen": 24,
  "SubnetMin": "10.0.1.0",
  "SubnetMax": "10.255.255.0",
  "Backend": {
    "Type": "vxlan",
    "VNI": 1,
    "Port": 8472
  }
}'

# 查看网络配置
etcdctl get /coreos.com/network/config

# 查看已分配子网
etcdctl get /coreos.com/network/subnets --prefix --keys-only

# 查看子网详情
etcdctl get /coreos.com/network/subnets/10.0.1.0-24

# 输出:
# {"PublicIP":"192.168.1.10","BackendType":"vxlan","BackendData":{"VtepMAC":"aa:bb:cc:dd:ee:01"}}

Watch 机制

# 监听子网变化
etcdctl watch /coreos.com/network/subnets --prefix

# 当新子网注册时
# 输出:
# PUT
# /coreos.com/network/subnets/10.0.2.0-24
# {"PublicIP":"192.168.1.20","BackendType":"vxlan","BackendData":{"VtepMAC":"aa:bb:cc:dd:ee:02"}}

4. 主机环境准备

4.1 系统要求

硬件配置

最低配置:
- CPU: 2 核
- 内存:4GB
- 磁盘:20GB
- 网络:1GbE

推荐配置:
- CPU: 4 核+
- 内存:8GB+
- 磁盘:50GB+ SSD
- 网络:10GbE

软件要求

操作系统:
- Ubuntu 20.04/22.04 LTS
- CentOS 7/8
- Debian 10/11

内核版本:
- Linux 4.14+
- 推荐 5.10+

Docker 版本:
- Docker 20.10+

4.2 网络配置

禁用防火墙(测试)

# Ubuntu (ufw)
ufw disable

# CentOS (firewalld)
systemctl stop firewalld
systemctl disable firewalld

# 或者开放必要端口
# Ubuntu
ufw allow 2379/tcp
ufw allow 2380/tcp
ufw allow 8472/udp
ufw allow 4789/udp

# CentOS
firewall-cmd --permanent --add-port=2379/tcp
firewall-cmd --permanent --add-port=2380/tcp
firewall-cmd --permanent --add-port=8472/udp
firewall-cmd --permanent --add-port=4789/udp
firewall-cmd --reload

禁用 SELinux

# 临时禁用
setenforce 0

# 永久禁用
sed -i 's/SELINUX=enforcing/SELINUX=permissive/g' /etc/selinux/config

配置网络接口

# 查看网络接口
ip addr show

# 确保 eth0 有正确 IP
# eth0: 192.168.1.10/24

# 测试连通性
ping 192.168.1.20
ping 192.168.1.30

4.3 安装必要工具

安装 Docker

# Ubuntu/Debian
apt-get update
apt-get install -y docker.io docker-compose

# CentOS
yum install -y docker docker-compose

# 启动 Docker
systemctl start docker
systemctl enable docker

安装 ETCD 客户端

# 下载 etcdctl
wget https://github.com/etcd-io/etcd/releases/download/v3.5.9/etcd-v3.5.9-linux-amd64.tar.gz
tar xzvf etcd-v3.5.9-linux-amd64.tar.gz
cp etcd-v3.5.9-linux-amd64/etcdctl /usr/local/bin/
chmod +x /usr/local/bin/etcdctl

安装 Flannel

# 下载 flanneld
wget https://github.com/flannel-io/flannel/releases/download/v0.22.0/flannel-v0.22.0-linux-amd64.tar.gz
tar xzvf flannel-v0.22.0-linux-amd64.tar.gz
cp flanneld /usr/local/bin/
chmod +x /usr/local/bin/flanneld

5. ETCD 集群部署

5.1 单节点部署(快速测试)

使用 Docker 部署

docker run -d \
  --name etcd \
  -p 2379:2379 \
  -p 2380:2380 \
  -v /opt/etcd/data:/etcd-data \
  -e ETCD_DATA_DIR=/etcd-data \
  quay.io/coreos/etcd:v3.5.9 \
  etcd \
  --name etcd-single \
  --data-dir /etcd-data \
  --listen-client-urls http://0.0.0.0:2379 \
  --advertise-client-urls http://192.168.1.10:2379 \
  --listen-peer-urls http://0.0.0.0:2380 \
  --initial-advertise-peer-urls http://192.168.1.10:2380 \
  --initial-cluster etcd-single=http://192.168.1.10:2380 \
  --initial-cluster-token my-etcd-token \
  --initial-cluster-state new \
  --auto-compaction-retention=1

# 验证
etcdctl --endpoints=http://192.168.1.10:2379 endpoint health

5.2 三节点部署(生产)

节点 1 配置

docker run -d \
  --name etcd \
  --restart=always \
  -p 2379:2379 \
  -p 2380:2380 \
  -v /opt/etcd/data:/etcd-data \
  -v /etc/localtime:/etc/localtime:ro \
  quay.io/coreos/etcd:v3.5.9 \
  etcd \
  --name etcd-node1 \
  --data-dir /etcd-data \
  --listen-client-urls http://0.0.0.0:2379 \
  --advertise-client-urls http://192.168.1.10:2379 \
  --listen-peer-urls http://0.0.0.0:2380 \
  --initial-advertise-peer-urls http://192.168.1.10:2380 \
  --initial-cluster etcd-node1=http://192.168.1.10:2380,etcd-node2=http://192.168.1.20:2380,etcd-node3=http://192.168.1.30:2380 \
  --initial-cluster-token my-etcd-token \
  --initial-cluster-state new \
  --auto-compaction-retention=1 \
  --quota-backend-bytes=8589934592 \
  --heartbeat-interval=100 \
  --election-timeout=1000 \
  --enable-v2=false

节点 2 配置

docker run -d \
  --name etcd \
  --restart=always \
  -p 2379:2379 \
  -p 2380:2380 \
  -v /opt/etcd/data:/etcd-data \
  quay.io/coreos/etcd:v3.5.9 \
  etcd \
  --name etcd-node2 \
  --data-dir /etcd-data \
  --listen-client-urls http://0.0.0.0:2379 \
  --advertise-client-urls http://192.168.1.20:2379 \
  --listen-peer-urls http://0.0.0.0:2380 \
  --initial-advertise-peer-urls http://192.168.1.20:2380 \
  --initial-cluster etcd-node1=http://192.168.1.10:2380,etcd-node2=http://192.168.1.20:2380,etcd-node3=http://192.168.1.30:2380 \
  --initial-cluster-token my-etcd-token \
  --initial-cluster-state new \
  --auto-compaction-retention=1 \
  --quota-backend-bytes=8589934592 \
  --heartbeat-interval=100 \
  --election-timeout=1000

节点 3 配置

# 类似节点 2,修改 IP 和名称

5.3 验证 ETCD 集群

检查集群健康

# 设置 ETCDCTL_ENDPOINTS
export ETCDCTL_ENDPOINTS=http://192.168.1.10:2379,http://192.168.1.20:2379,http://192.168.1.30:2379

# 检查健康
etcdctl endpoint health

# 输出:
# http://192.168.1.10:2379: is healthy
# http://192.168.1.20:2379: is healthy
# http://192.168.1.30:2379: is healthy

检查集群状态

# 检查成员
etcdctl member list

# 检查 Leader
etcdctl endpoint status --write-out=table

# 检查性能
etcdctl check perf

6. Flannel 部署与配置

6.1 在 ETCD 中注册网络

注册 Flannel 网络配置

# 在所有节点执行
etcdctl --endpoints=http://192.168.1.10:2379 put /coreos.com/network/config '{
  "Network": "10.0.0.0/8",
  "SubnetLen": 24,
  "SubnetMin": "10.0.1.0",
  "SubnetMax": "10.255.255.0",
  "Backend": {
    "Type": "vxlan",
    "VNI": 1,
    "Port": 8472
  }
}'

# 验证配置
etcdctl --endpoints=http://192.168.1.10:2379 get /coreos.com/network/config

# 输出:
# /coreos.com/network/config
# {"Network":"10.0.0.0/8","SubnetLen":24,"Backend":{"Type":"vxlan","VNI":1,"Port":8472}}

参数说明

Network: 10.0.0.0/8
- Flannel 使用的全局网络
- 必须足够大以容纳所有容器

SubnetLen: 24
- 每个主机的子网掩码
- /24 = 256 个 IP(254 个可用)

SubnetMin/SubnetMax: 子网范围
- 限制子网分配范围
- 避免与其他网络冲突

Backend.Type: vxlan
- 使用 VXLAN 后端
- 其他选项:udp, host-gw, aws-vpc, gce

Backend.VNI: 1
- VXLAN 网络标识符
- 范围:0-16777215

Backend.Port: 8472
- VXLAN UDP 端口
- 默认 8472

6.2 部署 Flannel

使用 Systemd 部署

# 创建 systemd 服务文件
cat > /etc/systemd/system/flanneld.service << EOF
[Unit]
Description=Flannel
Documentation=https://github.com/flannel-io/flannel
After=network.target
After=etcd.service
Wants=etcd.service

[Service]
Type=notify
ExecStart=/usr/local/bin/flanneld \\
  --etcd-endpoints=http://192.168.1.10:2379 \\
  --public-ip=192.168.1.10 \\
  --iface=eth0 \\
  --ip-masq=true \\
  --subnet-file=/run/flannel/subnet.env
ExecReload=/bin/kill -HUP $MAINPID
Restart=on-failure
RestartSec=5
LimitNOFILE=65536

[Install]
WantedBy=multi-user.target
EOF

# 重新加载 systemd
systemctl daemon-reload

# 启动 flanneld
systemctl start flanneld
systemctl enable flanneld

# 查看状态
systemctl status flanneld

使用 Docker 部署

docker run -d \
  --name flanneld \
  --net=host \
  --privileged \
  -v /run/flannel:/run/flannel \
  -v /var/run/docker.sock:/var/run/docker.sock \
  quay.io/coreos/flannel:v0.22.0 \
  /opt/bin/flanneld \
  --etcd-endpoints=http://192.168.1.10:2379 \
  --public-ip=192.168.1.10 \
  --iface=eth0 \
  --ip-masq=true

# 查看日志
docker logs flanneld

6.3 验证 Flannel 部署

检查子网分配

# 查看 ETCD 中的子网
etcdctl --endpoints=http://192.168.1.10:2379 get /coreos.com/network/subnets --prefix --keys-only

# 输出:
# /coreos.com/network/subnets/10.0.1.0-24
# /coreos.com/network/subnets/10.0.2.0-24
# /coreos.com/network/subnets/10.0.3.0-24

# 查看子网详情
etcdctl --endpoints=http://192.168.1.10:2379 get /coreos.com/network/subnets/10.0.1.0-24

# 输出:
# {"PublicIP":"192.168.1.10","BackendType":"vxlan","BackendData":{"VtepMAC":"aa:bb:cc:dd:ee:01"}}

检查网络接口

# 查看 flannel.1 接口
ip -d link show flannel.1

# 输出:
# 3: flannel.1@NONE: <BROADCAST,MULTICAST,UP,LOWER_UP> ...
#     link/ether aa:bb:cc:dd:ee:01
#     promiscuity 0
#     vxlan id 1 remote 0.0.0.0 port 8472 \
#     learn ageing 300 limit 1000 \
#     srcport 0 0 dstport 0 \
#     ttl 64 portrange [32768, 61000]

# 查看 cni0 网桥
ip addr show cni0

# 输出:
# 4: cni0: <BROADCAST,MULTICAST,UP,LOWER_UP> ...
#     link/ether 0a:58:0a:01:01:01
#     inet 10.0.1.1/24 scope global cni0

检查路由表

# 查看路由
ip route show

# 输出:
# 10.0.1.0/24 dev cni0 proto kernel scope link src 10.0.1.1
# 10.0.2.0/24 via 192.168.1.20 dev flannel.1
# 10.0.3.0/24 via 192.168.1.30 dev flannel.1

7. Docker 网络集成

7.1 配置 Docker 使用 Flannel

修改 Docker 配置

# 加载 Flannel 环境变量
cat /run/flannel/subnet.env

# 输出:
# FLANNEL_NETWORK=10.0.0.0/8
# FLANNEL_SUBNET=10.0.1.1/24
# FLANNEL_MTU=1450
# FLANNEL_IPMASQ=true

# 修改 Docker daemon.json
cat > /etc/docker/daemon.json << EOF
{
  "bip": "10.0.1.1/24",
  "mtu": 1450,
  "ip-masq": true
}
EOF

# 重启 Docker
systemctl daemon-reload
systemctl restart docker

验证 Docker 网络

# 查看 docker0
ip addr show docker0

# 输出:
# 5: docker0: <BROADCAST,MULTICAST,UP,LOWER_UP> ...
#     link/ether 02:42:ac:11:00:01
#     inet 10.0.1.1/24 brd 10.0.1.255

7.2 运行容器测试

启动容器

# 在 Host1 启动容器
docker run -d \
  --name test1 \
  --network bridge \
  alpine sleep 3600

# 在 Host2 启动容器
docker run -d \
  --name test2 \
  --network bridge \
  alpine sleep 3600

# 查看容器 IP
docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' test1
# 输出:10.0.1.2

docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' test2
# 输出:10.0.2.2

测试跨主机通信

# Host1 容器 ping Host2 容器
docker exec test1 ping -c 3 10.0.2.2

# 输出:
# 64 bytes from 10.0.2.2: icmp_seq=1 ttl=64 time=0.5 ms
# 64 bytes from 10.0.2.2: icmp_seq=2 ttl=64 time=0.4 ms
# 64 bytes from 10.0.2.2: icmp_seq=3 ttl=64 time=0.4 ms

# 成功!跨主机通信正常

8. 跨主机通信验证

8.1 基础连通性测试

Ping 测试

# 获取容器 IP
IP1=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' test1)
IP2=$(docker inspect -f '{{range .NetworkSettings.Networks}}{{.IPAddress}}{{end}}' test2)

echo "Container 1: $IP1 (Host1)"
echo "Container 2: $IP2 (Host2)"

# Ping 测试
docker exec test1 ping -c 10 $IP2

# 输出:
# 10 packets transmitted, 10 received, 0% packet loss
# rtt min/avg/max/mdev = 0.4/0.5/0.6/0.1 ms

TCP 连接测试

# 在容器 1 启动 TCP 服务器
docker exec -d test1 nc -l -p 8080

# 在容器 2 连接
docker exec test2 nc -vz $IP1 8080

# 输出:
# Connection to 10.0.1.2 8080 port [tcp/*] succeeded!

8.2 数据包路径验证

使用 tcpdump 抓包

# 在 Host1 抓包
tcpdump -i eth0 -n udp port 8472

# 在 Host2 抓包
tcpdump -i eth0 -n udp port 8472

# 在容器 1 ping 容器 2
docker exec test1 ping $IP2

# 应该看到 VXLAN 封装的数据包
# 192.168.1.10:8472 > 192.168.1.20:8472

使用 tcptrace 分析

# 安装 tcptrace
apt-get install tcptrace

# 抓包并分析
tcpdump -i any -s 0 -w flannel.pcap

# 使用 Wireshark 分析
wireshark flannel.pcap

9. Flannel 后端详解

9.1 VXLAN 后端(默认)

配置

{
  "Network": "10.0.0.0/8",
  "Backend": {
    "Type": "vxlan",
    "VNI": 1,
    "Port": 8472
  }
}

特点

优势:
- 性能好(内核级 VXLAN)
- 支持多播
- 广泛支持

劣势:
- 需要内核支持(3.12+)
- 50 字节开销

9.2 Host-GW 后端

配置

{
  "Network": "10.0.0.0/8",
  "Backend": {
    "Type": "host-gw"
  }
}

特点

优势:
- 无封装开销
- 性能最优
- 配置简单

劣势:
- 需要 Layer 2 连通性
- 不支持跨路由

9.3 UDP 后端(已废弃)

配置

{
  "Network": "10.0.0.0/8",
  "Backend": {
    "Type": "udp",
    "Port": 8285
  }
}

特点

已废弃(v0.11.0)
性能差(用户空间封装)
仅用于测试

10. Kubernetes CNI 集成

10.1 CNI 插件安装

下载 CNI 插件

# 下载 Flannel CNI
wget https://github.com/flannel-io/cni-plugin/releases/download/v1.2.0/flannel-cni-plugin-linux-amd64
mv flannel-cni-plugin-linux-amd64 /opt/cni/bin/flannel
chmod +x /opt/cni/bin/flannel

# 下载 CNI 配置工具
wget https://github.com/containernetworking/plugins/releases/download/v1.2.0/cni-plugins-linux-amd64-v1.2.0.tgz
tar xzvf cni-plugins-linux-amd64-v1.2.0.tgz -C /opt/cni/bin/

配置 CNI

# 创建 CNI 配置
cat > /etc/cni/net.d/10-flannel.conflist << EOF
{
  "name": "cbr0",
  "cniVersion": "1.0.0",
  "plugins": [
    {
      "type": "flannel",
      "delegate": {
        "hairpinMode": true,
        "isDefaultGateway": true
      }
    },
    {
      "type": "portmap",
      "capabilities": {
        "portMappings": true
      }
    }
  ]
}
EOF

10.2 Kubernetes 集成

部署 Flannel DaemonSet

# kube-flannel.yml
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: kube-flannel-ds
  namespace: kube-system
spec:
  selector:
    matchLabels:
      app: flannel
  template:
    metadata:
      labels:
        app: flannel
    spec:
      containers:
      - name: kube-flannel
        image: quay.io/coreos/flannel:v0.22.0
        command:
        - /opt/bin/flanneld
        args:
        - --ip-masq
        - --kube-subnet-mgr
        resources:
          requests:
            cpu: "100m"
            memory: "50Mi"
        securityContext:
          privileged: true
        env:
        - name: POD_NAME
          valueFrom:
            fieldRef:
              fieldPath: metadata.name
        - name: POD_NAMESPACE
          valueFrom:
            fieldRef:
              fieldPath: metadata.namespace
        volumeMounts:
        - name: run
          mountPath: /run/flannel
        - name: flannel-cfg
          mountPath: /etc/kube-flannel/
      volumes:
      - name: run
        hostPath:
          path: /run/flannel
      - name: flannel-cfg
        configMap:
          name: kube-flannel-cfg
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: kube-flannel-cfg
  namespace: kube-system
data:
  net-conf.json: |
    {
      "Network": "10.244.0.0/16",
      "Backend": {
        "Type": "vxlan"
      }
    }

应用配置

kubectl apply -f kube-flannel.yml

11. 故障排查实战

11.1 常见问题

问题 1:子网分配失败

# 检查 ETCD 连接
etcdctl --endpoints=http://192.168.1.10:2379 endpoint health

# 检查网络配置
etcdctl --endpoints=http://192.168.1.10:2379 get /coreos.com/network/config

# 检查 flanneld 日志
journalctl -u flanneld -f

# 重启 flanneld
systemctl restart flanneld

问题 2:容器无法跨主机通信

# 检查 VXLAN 接口
ip -d link show flannel.1

# 检查路由表
ip route show

# 检查防火墙
iptables -L -n -v

# 抓包分析
tcpdump -i eth0 -n udp port 8472

问题 3:性能问题

# 检查 MTU
ip link show flannel.1

# 检查网络拥塞
ethtool -S eth0

# 检查 CPU 使用
top

12. 性能优化与最佳实践

12.1 MTU 优化

设置 MTU

# Flannel 配置
{
  "Network": "10.0.0.0/8",
  "Backend": {
    "Type": "vxlan"
  }
}

# Docker 配置
{
  "mtu": 1450
}

12.2 监控告警

Prometheus 监控

# flannel-metrics.yaml
apiVersion: v1
kind: ServiceMonitor
metadata:
  name: flannel
  namespace: monitoring
spec:
  selector:
    matchLabels:
      app: flannel
  endpoints:
  - port: metrics
    interval: 30s

Grafana 仪表盘

Flannel Dashboard:
- 网络流量(接收/发送)
- 数据包数量
- 错误包统计
- 延迟统计

12.3 最佳实践清单

ETCD 集群

  • 生产环境使用 3 节点或 5 节点
  • 使用 SSD 存储
  • 定期备份

Flannel 配置

  • 使用 VXLAN 后端(默认)
  • 设置合理 MTU(1450)
  • 启用 ip-masq(NAT)

网络规划

  • 使用私有地址(10.0.0.0/8)
  • 预留足够地址空间
  • 避免与其他网络冲突

监控告警

  • 监控 ETCD 健康状态
  • 监控 Flannel 网络流量
  • 设置告警阈值

版权声明:本文原创,转载请注明出处
参考资料

  • Flannel 官方文档
  • ETCD 官方文档
  • Kubernetes CNI 文档
  • Linux 网络内核文档

如果本文对您有帮助,欢迎点赞、收藏、转发!

Logo

开源鸿蒙跨平台开发社区汇聚开发者与厂商,共建“一次开发,多端部署”的开源生态,致力于降低跨端开发门槛,推动万物智联创新。

更多推荐