在 Kubernetes 中安装与配置 Flannel 网络插件:从 vxlan 到 host-gw 的完整实践
【免费下载链接】kubernetes-handbookKubernetes 架构与生态:从云原生到 AI 原生基础设施的构建指南项目地址: https://gitcode.com/gh_mirrors/ku/kubernetes-handbook
Flannel 是 Kubernetes 中最常用的容器网络插件之一,它以 etcd 为存储后端为每个 Node 分配独立的 Pod 子网,并通过 vxlan 或 host-gw 等后端实现跨主机 Pod 互通。本文基于 kubernetes-handbook 的 安装 flannel 网络插件 一文,完整讲解在所有 Node 节点上通过 yum 安装、配置、启动并验证 flannel 的每一步操作,同时结合仓库中的 flanneld.service、flanneld 环境变量配置、docker.service 等真实配置文件,深入剖析 flannel 与 etcd、Docker 之间的协作机制,帮助你一次上手即可部署出可用的扁平化 Pod 网络。
为什么每个 Node 节点都需要网络插件
Kubernetes 集群中运行着三类 IP,理解它们之间的区别是配置网络插件的前提:
- Node IP:宿主机的物理 IP 地址;
- Pod IP:由网络插件(如 flannel)分配的虚拟 IP,用于让跨主机的 Pod 相互连通;
- Cluster IP:Service 的虚拟 IP,通过 kube-proxy 注入的 iptables 规则访问。
Kubernetes 本身并不实现网络方案,而是通过 CNI(Container Network Interface)规范对接各类插件(详见 容器网络接口(CNI))。只有所有 Node 节点都安装了网络插件,集群中的所有 Pod 才能加入同一个局域网,这也是安装 flannel 的出发点。按照本手册的部署顺序,Node 节点上的进程遵循flannel -> docker -> kubelet -> kube-proxy的启动次序,flannel 是整个链路的第一环。
从架构上看,运行在每个 Node 上的 flanneld 进程承担两个核心职责:
- 为每个 Node 分配独立的 subnet:容器启动后自动从该子网中获取 IP;
- 维护跨节点路由:当有新的 Node 加入网络时,为每个 Node 增加指向远端子网的路由条目。
安装前准备:etcd 集群与 TLS 证书
flannel 以 etcd 作为配置和租约存储后端,因此安装前必须保证:
- 有一个可访问的 etcd 集群(本文示例为三节点
172.20.0.113/114/115:2379,TLS 加密通信); - 每个 Node 上已准备好与 etcd 通信所需的证书文件:
ca.pem、kubernetes.pem、kubernetes-key.pem(位于/etc/kubernetes/ssl/目录,与 kube-apiserver 使用的证书一致,etcd 集群安装可参考 etcd 集群安装)。
使用 yum 安装 flanneld
建议直接使用 yum 安装 flanneld,除非对版本有特殊需求:
yum install -y flannel在本文写作时默认安装的是0.7.1 版本的 flannel。安装完成后会在系统内生成两个关键文件:
| 文件 | 作用 |
|---|---|
/usr/lib/systemd/system/flanneld.service | flanneld 的 systemd 单元文件,定义了启动参数与依赖关系 |
/etc/sysconfig/flanneld | flanneld 的环境变量配置文件(endpoints、prefix、TLS 等) |
配置 flanneld:service 单元文件解析
仓库中完整保存了该单元文件,见 systemd/flanneld.service,内容与安装后生成的文件一致:
[Unit] Description=Flanneld overlay address etcd agent After=network.target After=network-online.target Wants=network-online.target After=etcd.service Before=docker.service [Service] Type=notify EnvironmentFile=/etc/sysconfig/flanneld EnvironmentFile=-/etc/sysconfig/docker-network ExecStart=/usr/bin/flanneld-start \ -etcd-endpoints=${FLANNEL_ETCD_ENDPOINTS} \ -etcd-prefix=${FLANNEL_ETCD_PREFIX} \ $FLANNEL_OPTIONS ExecStartPost=/usr/libexec/flannel/mk-docker-opts.sh -k DOCKER_NETWORK_OPTIONS -d /run/flannel/docker Restart=on-failure [Install] WantedBy=multi-user.target RequiredBy=docker.service逐项拆解这个单元文件,可以理解 flannel 与系统各组件的关系:
After=etcd.service/Before=docker.service:声明 flanneld 必须在 etcd 之后启动、在 docker 之前启动。这正是"先有子网分配、后有 Docker 接入"的编排保证;RequiredBy=docker.service:将 docker 反向依赖 flannel,确保 docker 启动前 flanneld 已经就绪;Type=notify:flanneld 启动完成后会主动向 systemd 发送通知,避免过早认为服务就绪;EnvironmentFile:/etc/sysconfig/flanneld提供核心变量;-/etc/sysconfig/docker-network前面的-表示该文件允许不存在;ExecStart:flanneld-start从环境变量中读取 etcd endpoints 与配置前缀(key),$FLANNEL_OPTIONS用于透传额外的命令行参数(如 TLS 证书、指定网卡);ExecStartPost:flanneld 启动后立即执行/usr/libexec/flannel/mk-docker-opts.sh,它基于 flannel 生成的子网信息生成 Docker 所需的启动参数文件,这是 flannel 与 Docker 协作的关键一环,下文会展开说明;Restart=on-failure:进程异常退出时自动拉起。
配置 /etc/sysconfig/flanneld 环境变量
仓库中的 etc/sysconfig/flanneld 完整呈现了该配置文件的典型内容:
# Flanneld configuration options # etcd url location. Point this to the server where etcd runs FLANNEL_ETCD_ENDPOINTS="https://172.20.0.113:2379,https://172.20.0.114:2379,https://172.20.0.115:2379" # etcd config key. This is the configuration key that flannel queries # For address range assignment FLANNEL_ETCD_PREFIX="/kube-centos/network" # Any additional options that you want to pass FLANNEL_OPTIONS="-etcd-cafile=/etc/kubernetes/ssl/ca.pem -etcd-certfile=/etc/kubernetes/ssl/kubernetes.pem -etcd-keyfile=/etc/kubernetes/ssl/kubernetes-key.pem"三个变量的含义如下:
| 变量 | 说明 |
|---|---|
FLANNEL_ETCD_ENDPOINTS | etcd 集群地址列表,多个地址用逗号分隔;此处使用 https 表明开启 TLS |
FLANNEL_ETCD_PREFIX | flannel 在 etcd 中使用的配置键前缀,本文统一使用/kube-centos/network |
FLANNEL_OPTIONS | 追加的 flanneld 命令行参数。本示例为与启用 TLS 的 etcd 通信指定 CA、客户端证书与私钥 |
多网卡场景:如果宿主机有多个网卡(例如 vagrant 环境),flannel 可能选错出口网卡导致子网无法互通,此时需要在
FLANNEL_OPTIONS中显式指定对外网卡,例如-iface=eth2。
注意:FLANNEL_ETCD_ENDPOINTS、FLANNEL_ETCD_PREFIX这两个变量仅供 flanneld 使用,而 flannel 生成的 Docker 参数会单独落到/run/flannel/目录(见下文)。
在 etcd 中初始化网络配置
flannel 从 etcd 中的配置键读取整个集群的网络规划(大网段、子网掩码、后端类型)。首先创建配置目录,然后写入网络配置:
etcdctl --endpoints=https://172.20.0.113:2379,https://172.20.0.114:2379,https://172.20.0.115:2379 \ --ca-file=/etc/kubernetes/ssl/ca.pem \ --cert-file=/etc/kubernetes/ssl/kubernetes.pem \ --key-file=/etc/kubernetes/ssl/kubernetes-key.pem \ mkdir /kube-centos/network etcdctl --endpoints=https://172.20.0.113:2379,https://172.20.0.114:2379,https://172.20.0.115:2379 \ --ca-file=/etc/kubernetes/ssl/ca.pem \ --cert-file=/etc/kubernetes/ssl/kubernetes.pem \ --key-file=/etc/kubernetes/ssl/kubernetes-key.pem \ mk /kube-centos/network/config '{"Network":"172.30.0.0/16","SubnetLen":24,"Backend":{"Type":"vxlan"}}'该 JSON 配置中的三个字段共同决定了整个集群的 Pod 网络形态:
Network:整个集群的 Pod 大网段(CIDR),所有 Node 的子网都从该网段中划分;SubnetLen:每个 Node 获得的子网掩码长度,示例为24,即每个 Node 最多可容纳 254 个 Pod(172.30.0.0/16可划分出 256 个/24子网);Backend.Type:数据面封装/转发模式。示例为vxlan(Overlay 隧道);如果希望改用host-gw模式,直接将vxlan改为host-gw即可,例如:
etcdctl --endpoints=${ETCD_ENDPOINTS} \ --ca-file=/etc/kubernetes/ssl/ca.pem \ --cert-file=/etc/kubernetes/ssl/kubernetes.pem \ --key-file=/etc/kubernetes/ssl/kubernetes-key.pem \ mk /kube-centos/network/config '{"Network":"172.30.0.0/16","SubnetLen":24,"Backend":{"Type":"host-gw"}}'关于 vxlan 与 host-gw 的取舍,可参考 网络和集群性能测试 一节,该节最终采用了host-gw 模式,两者差异详见本文后面的"模式选择"部分。
启动 flannel 并验证
配置完成后即可启动 flanneld:
systemctl daemon-reload systemctl enable flanneld systemctl start flanneld systemctl status flanneld启动成功后,每个 Node 的 flanneld 会向 etcd 注册自己分配到的子网。查询 etcd 可以看到类似如下的内容:
$etcdctl --endpoints=${ETCD_ENDPOINTS} \ --ca-file=/etc/kubernetes/ssl/ca.pem \ --cert-file=/etc/kubernetes/ssl/kubernetes.pem \ --key-file=/etc/kubernetes/ssl/kubernetes-key.pem \ ls /kube-centos/network/subnets /kube-centos/network/subnets/172.30.14.0-24 /kube-centos/network/subnets/172.30.38.0-24 /kube-centos/network/subnets/172.30.46.0-24 $etcdctl --endpoints=${ETCD_ENDPOINTS} \ --ca-file=/etc/kubernetes/ssl/ca.pem \ --cert-file=/etc/kubernetes/ssl/kubernetes.pem \ --key-file=/etc/kubernetes/ssl/kubernetes-key.pem \ get /kube-centos/network/config { "Network": "172.30.0.0/16", "SubnetLen": 24, "Backend": { "Type": "vxlan" } } $etcdctl --endpoints=${ETCD_ENDPOINTS} \ --ca-file=/etc/kubernetes/ssl/ca.pem \ --cert-file=/etc/kubernetes/ssl/kubernetes.pem \ --key-file=/etc/kubernetes/ssl/kubernetes-key.pem \ get /kube-centos/network/subnets/172.30.14.0-24 {"PublicIP":"172.20.0.114","BackendType":"vxlan","BackendData":{"VtepMAC":"56:27:7d:1c:08:22"}} $etcdctl --endpoints=${ETCD_ENDPOINTS} \ --ca-file=/etc/kubernetes/ssl/ca.pem \ --cert-file=/etc/kubernetes/ssl/kubernetes.pem \ --key-file=/etc/kubernetes/ssl/kubernetes-key.pem \ get /kube-centos/network/subnets/172.30.38.0-24 {"PublicIP":"172.20.0.115","BackendType":"vxlan","BackendData":{"VtepMAC":"12:82:83:59:cf:b8"}} $etcdctl --endpoints=${ETCD_ENDPOINTS} \ --ca-file=/etc/kubernetes/ssl/ca.pem \ --cert-file=/etc/kubernetes/ssl/kubernetes.pem \ --key-file=/etc/kubernetes/ssl/kubernetes-key.pem \ get /kube-centos/network/subnets/172.30.46.0-24 {"PublicIP":"172.20.0.113","BackendType":"vxlan","BackendData":{"VtepMAC":"e6:b2:fd:f6:66:96"}}以上输出中的每一条 subnet 记录都是一个 Node 的"租约":
PublicIP:该 Node 对外的物理 IP(示例中 3 个 Node 分别为 114、115、113);BackendType:当前使用 vxlan 后端;BackendData.VtepMAC:该 Node 上创建的 VTEP(虚拟隧道端点)网卡的 MAC 地址,vxlan 模式下正是通过这张网卡完成跨主机封包转发。
如果能够查询到上述内容,说明 flannel 已经安装并运行成功。下一步就可以在该 Node 上安装和配置 docker、kubelet、kube-proxy 等组件,完整流程参见 部署 node 节点。
深入理解:flannel 如何与 Docker 协同工作
flannel 安装完成的标志不只是 flanneld 进程运行,更关键的是它能否把 Pod 子网信息"传导"给 Docker。这一过程由单元文件中的ExecStartPost完成:
ExecStartPost=/usr/libexec/flannel/mk-docker-opts.sh -k DOCKER_NETWORK_OPTIONS -d /run/flannel/dockermk-docker-opts.sh的作用是Generate Docker daemon options based on flannel env file(根据 flannel 环境文件生成 Docker 守护进程参数)。flanneld 启动后它会自动生成两个文件:
1./run/flannel/docker—— 给 Docker 的启动参数
DOCKER_OPT_BIP="--bip=172.33.68.1/24" DOCKER_OPT_IPMASQ="--ip-masq=true" DOCKER_OPT_MTU="--mtu=1500" DOCKER_NETWORK_OPTIONS="--bip=172.33.68.1/24 --ip-masq=true --mtu=1500"2./run/flannel/subnet.env—— flannel 向 etcd 注册的子网信息
FLANNEL_NETWORK=172.33.0.0/16 FLANNEL_SUBNET=172.33.68.1/24 FLANNEL_MTU=1500 FLANNEL_IPMASQ=false其中--bip=172.33.68.1/24指定了该 Node 上 docker0 网桥的地址(也就是 Pod 子网的网关),--mtu与 vxlan 隧道 MTU 相匹配,--ip-masq=true则允许容器访问外部网络时进行地址伪装。
为了让 Docker 读取这些参数,需要修改/usr/lib/systemd/system/docker.service,加入环境变量引用。仓库中的 systemd/docker.service 完整保留了推荐配置(兼容 yum 与二进制两种安装方式):
EnvironmentFile=-/run/flannel/docker EnvironmentFile=-/run/docker_opts.env EnvironmentFile=-/run/flannel/subnet.env EnvironmentFile=-/etc/sysconfig/docker EnvironmentFile=-/etc/sysconfig/docker-storage EnvironmentFile=-/etc/sysconfig/docker-network EnvironmentFile=-/run/docker_opts.env并且ExecStart中显式拼接了 flannel 生成的三个变量:
ExecStart=/usr/bin/dockerd \ --exec-opt native.cgroupdriver=systemd \ $DOCKER_OPT_BIP \ $DOCKER_OPT_IPMASQ \ $DOCKER_OPT_MTU \ -s=overlay \ --log-driver=json-file \ ...这样一来,只要通过 systemctl 先启动 flannel 再启动 docker,docker0 就会自动落在 flannel 分配的子网内。实际启动后的 docker 进程参数会呈现为:
--bip=172.33.68.1/24 --ip-masq=true --mtu=1500用ip addr查看宿主机网卡即可印证:docker0的地址正是172.33.68.1/24,同时存在veth设备将 Pod 容器与 docker0 相连;用docker network inspect也能看到 bridge 网络的Subnet/Gateway与 flannel 分配的子网完全一致。这些都是 flannel 与 Docker 成功协同的直接证据。
注意:无论使用 yum 还是二进制方式安装 flannel,向 docker.service 注入上述
EnvironmentFile都是必不可少的步骤,否则 Docker 无法加入 flannel 创建的虚拟网络。若二进制方式安装(tar 包方式),还需从 flannel release 中取出mk-docker-opts.sh脚本并执行./mk-docker-opts.sh -i生成环境文件。
验证跨节点 Pod 互通
flannel 的另一项核心工作是维护宿主机的路由表。Node 节点启动 flannel 后,路由表中会出现类似下面的条目(示例来自 扁平网络 Flannel):
172.33.68.0 0.0.0.0 255.255.255.0 U 0 0 0 docker0 172.33.96.0 172.30.118.65 255.255.255.0 UG 0 0 0 eth2- 第一条是本机子网路由,指向 docker0;
- 第二条是 flannel 自动添加的远端 Node 子网路由——当有新的 Node 加入集群后,每个 Node 的路由表都会同步增加对应条目,这也是"新增节点即插即用"的原因。
使用traceroute访问另一台 Node 上的 Pod(如172.33.96.3),可以看到流量先到达对端 Node 的物理 IP,再一跳进入目标 Pod:
1 172.30.118.65 (172.30.118.65) 0.518 ms 0.367 ms 0.398 ms 2 172.33.96.3 (172.33.96.3) 0.451 ms 0.352 ms 0.223 ms在iptables -L中也能看到 kube-proxy 注入的KUBE-SERVICES、KUBE-FORWARD等 Service 转发规则链,说明 Pod 网络与 Service 网络已协同工作。
vxlan 与 host-gw 模式如何选择
flannel 支持的两种主流后端在数据面实现上差异显著,直接决定集群网络的性能上限:
- vxlan 模式:Overlay 隧道方案,跨主机流量通过 VTEP 封包/解包转发,与底层物理网络解耦,部署最省心,但封装/解封装过程带来明显性能损耗;
- host-gw 模式:纯路由方案,flannel 直接在宿主机路由表中写入"远端 Pod 子网 -> 对端 Node IP"的路由,跨节点流量直接走物理网络转发,没有封包开销。
两种模式的架构可分别参考下图理解(左为 host-gw 路由模型,右为 flannel 总体架构):
仓库中的 网络和集群性能测试 使用 iperf 对同一集群做过对比测试(测试命令:服务端iperf -s -p 12345 -i 1 -M,客户端iperf -c ${server-ip} -p 12345 -i 1 -t 10 -w 20K),结果如下:
| 场景 | vxlan 带宽 | host-gw 带宽 |
|---|---|---|
| 宿主机之间(基准) | 5.37 Gbits/sec | 5.37 Gbits/sec |
| 不同主机的 Pod 之间 | 3.30 Gbits/sec | 4.88 Gbits/sec |
| Node 与跨主机 Pod 之间 | 3.42 Gbits/sec | 4.94 Gbits/sec |
结论是:vxlan 模式相对宿主机直连约有 30%~40% 的性能损耗,而 host-gw 模式损耗仅约 10%。因此,如果你的集群位于二层可达的同一网段(host-gw 依赖 Node 间三层路由可达且无需跨子网隔离),优先选择host-gw模式;如果 Node 分布跨网段、物理网络不可直连,再退而使用 vxlan。更多关于 Kubernetes 网络模型与 flannel 模式的讨论可参考 Kubernetes 中的网络模式解析 与 CNI 接口说明。
常见问题排查
- etcd 中没有 subnets 租约:检查
FLANNEL_ETCD_ENDPOINTS与 TLS 证书(-etcd-cafile/-etcd-certfile/-etcd-keyfile)是否正确,并用etcdctl手工读取/kube-centos/network/config确认配置键已写入; - Pod 子网与外网网段冲突:
Network字段务必选择不与任何 Node 物理网段重叠的私有网段; - 多网卡选错出口导致跨 Node 不通:在
FLANNEL_OPTIONS中追加-iface=<对外网卡名>(如 vagrant 环境中的eth2); - Docker 未使用 flannel 子网:确认
docker.service已包含EnvironmentFile=-/run/flannel/docker等环境变量引用,并检查systemctl status -l docker中是否出现--bip=... --ip-masq=true --mtu=...参数; - 更换后端模式:只需更新 etcd 中
/kube-centos/network/config的Backend.Type为vxlan或host-gw,然后依次重启各 Node 的 flanneld 与 docker。
完成 flannel 安装后,请继续按照 部署 node 节点 安装 Docker、kubelet 与 kube-proxy,使 Node 正式加入 Kubernetes 集群。
【免费下载链接】kubernetes-handbookKubernetes 架构与生态:从云原生到 AI 原生基础设施的构建指南项目地址: https://gitcode.com/gh_mirrors/ku/kubernetes-handbook
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考