flannel 通过 kubectl apply 部署 daemonset 等资源实现,而非传统安装;需准备镜像、cni 二进制和配置文件;vxlan 模式须检查 mtu、vxlan 模块及 udp 8472 端口;host-gw 模式仅适用于同二层网络;子网分配依赖 etcd 或 kubernetes api 兼容性。

Flannel 不是“安装”出来的,而是通过 kubectl apply 部署一个 DaemonSet 和配套 ConfigMap、RBAC 等资源对象;直接运行二进制或 yum 安装 flanneld 在现代 Kubernetes(1.19+)中基本失效,因为 CNI 插件必须由 kubelet 调用,而非独立守护进程管理。
为什么 kubectl apply -f kube-flannel.yml 是主流方式
从 kubeadm 初始化的集群开始,Kubernetes 就默认要求 CNI 插件以标准 CNI 规范注入:插件配置写入 /etc/cni/net.d/,二进制放在 /opt/cni/bin/,所有动作由 kubelet 触发。flannel 的官方 YAML(如 kube-flannel.yml)正是按此结构组织:
- 自动创建
ConfigMap存储网络配置(如NetworkCIDR、Backend 类型) - 通过
DaemonSet在每个 Node 上部署容器化flanneld,并挂载宿主机的/run/flannel、/etc/cni/net.d等路径 - 容器内执行
mk-docker-opts.sh或直接写入cni-conf.json,确保后续 Pod 启动时能被正确分配 IP
离线环境必须提前准备的三类文件
离线部署失败 90% 出在镜像和配置缺失。你不能只下载 YAML 文件就跑 kubectl apply:
-
flannel镜像:例如quay.io/coreos/flannel:v0.24.2(注意版本需匹配 Kubernetes 版本,1.23+ 推荐 v0.22.0+) -
pause镜像:Pod 的 infra 容器,必须与 kubelet 的--pod-infra-container-image参数一致,常见如k8s.gcr.io/pause:3.9 - CNI 二进制:YAML 中默认不带,需手动放入每个节点的
/opt/cni/bin/,至少包含flannel和bridge(loopback可选)
漏掉任意一项,kube-flannel Pod 就会卡在 ContainerCreating 或 CrashLoopBackOff,kubectl describe pod -n kube-flannel 里能看到 Failed to create pod sandbox 或 cni plugin not initialized。
VXLAN 模式下必须检查的两个关键点
默认 VXLAN 模式看似开箱即用,但实际常因底层网络参数不匹配导致跨节点不通:
-
flannel.1设备的 MTU 必须 ≤ 宿主机物理网卡 MTU − 50(VXLAN 封装开销),否则大包被静默丢弃;常见做法是统一设为1450,并在 YAML 的net-conf.json段显式指定"MTU": 1450 - 确认内核已加载
vxlan模块:lsmod | grep vxlan,若为空需modprobe vxlan并写入/etc/modules持久化 - 防火墙必须放行 UDP 8472 端口(VXLAN 默认端口),
iptables -I INPUT -p udp --dport 8472 -j ACCEPT
host-gw 模式适用但限制极严
如果你追求零封装性能,且所有 Node 确实处于同一二层网络(比如同个交换机下的物理机),可改用 host-gw:
- 修改 YAML 中
net-conf.json的"Backend": {"Type": "host-gw"} - 无需
vxlan模块,也不用开 UDP 8472 - 但一旦节点跨子网(哪怕只是不同 VLAN),路由条目无法生效,
ip route里看不到对应 Pod CIDR 的下一跳 - 错误现象:同节点 Pod 通,跨节点完全不通,
tcpdump -i eth0 icmp抓不到任何目标 IP 的包
真正容易被忽略的是:flannel 的子网分配依赖 etcd 或 Kubernetes API —— 如果你用的是 kubeadm 且未关闭 etcd 的 v2 API(ETCD_ENABLE_V2=true),而 flannel YAML 默认用 v1 API 写子网,就会静默失败。此时必须核对 etcd 版本与 YAML 中的 etcd-endpoints 协议是否匹配,或直接切到基于 Kubernetes API 的后端("Backend": {"Type": "vxlan", "DirectRouting": true})。











