ARM64环境部署flannel v0.11.0:VXLAN配置与排错实战
简介面向使用ARM64架构服务器搭建Kubernetes集群的运维与开发人员这是一份flannel网络插件的v0.11.0版本离线安装包。flannel作为K8s常用的CNI网络方案用于解决跨节点容器通信与Overlay网络配置问题适合内网环境或需要固定版本组件的生产部署场景。压缩包整体约8.03MB共3个文件包含flanneld主程序、Markdown说明文档和Shell辅助脚本主程序负责实际网络配置Shell脚本可辅助生成Docker环境变量便于接入systemd或自定义启动流程。资源已吸引453人学习浏览对于希望避开联网拉取镜像、快速获取指定版本编译产物的使用者而言可直接下载解压并按官方文档部署节省排查兼容性与下载失败的时间。同时文档与脚本一并打包也有助于二次开发或整合到现有自动化运维体系中。1. 一个藏在 tar.gz 里的关键组件flannel v0.11.0 到底给 ARM64 集群解决了什么如果你自己动手在 ARM64 机器上搭过 Kubernetes大概率会碰到 flannel。kubeadm 把 etcd、kube-apiserver、controller-manager 都拉起来之后第一个拦路虎就是容器网络Pod 调度到不同节点之后IP 之间通不了服务发现、DNS、Ingress 全都没有意义。flannel v0.11.0 是 2018 年前后很主流的网络插件版本到现在依然有人下载它的 linux-arm64 压缩包不是为了追新而是为了离线内网维稳——包小、依赖少、在飞腾、鲲鹏、树莓派这种 ARM64 平台上表现很稳。它解决的问题很具体让节点 A 上的 Pod 能直接用容器 IP 访问节点 B 上的 Pod不需要用户自己做 NAT也不需要外部负载均衡器介入。flanneld 进程从 etcd 或者 Kubernetes API 拿一段子网租约再把 VXLAN 隧道或主机路由规则写进内核集群里每个 Pod 因此都拥有一个全局可路由的地址。适合谁适合手动维护 CNI、不想引入 Calico 那套 BGP 和 Felix 组件、或者手头正好只有这个 tar.gz 包的工程师。下文按部署顺序写从原理到命令再到排错卡在哪一章直接跳过去看。2. 先拆数据面VXLAN 封包、etcd 租约与 CNI 插件各管哪一段2.1 flanneld 是租约管理器也是内核路由的写入者很多人以为 flannel 只是一个“转发流量”的进程其实 flanneld 在节点启动后的第一件正事是去 etcd 或 Kubernetes API 申请一个子网。默认全局网段是 10.244.0.0/16--subnet-len默认 24意味着整个集群最多分成 256 个节点子网每个节点拿到一个 /24。这个设计决定了 flannel 的整体模型它不是给每个 Pod 独立分配 IP而是“先给节点分一段再把段里的 IP 分给 Pod”。节点拿到租约之后flanneld 会做三件事把子网路由写进系统路由表、创建并维护 flannel.1 虚拟网卡、在需要时注册 VXLAN 的 FDB 表项。流量经过时真正干活的是内核路由和网卡flanneld 本身不碰数据包。这也是它比用户态代理方案轻量的核心原因。进程崩溃时已经写入内核的路由并不会立刻消失但租约续期和 FDB 维护会中断所以实际表现往往是“Ping 能通一会儿然后开始丢包”。日志怎么看journalctl -u flanneld是手动部署时最主要的排错入口。为什么在这个场景下选 flannel 而不是 CalicoCalico 走 BGP 分发路由每个节点上要跑 BIRD 和 Felix对内存和 CPU 都有要求ARM64 单板机上资源本来就紧Calico 那套在低配节点上偶尔会把 CPU 打满。flannel 的 host-gw 模式只是写静态路由vxlan 模式也只是内核模块拆包封包几乎没有常驻开销所以旧版本 flannel 在 ARM 设备上口碑一直不错。2.2 VXLAN 封包链路与 host-gw 的取舍VXLAN backend 下flannel.1 是一张 VTEP 网卡。Pod A 发出的原始 IP 包先经过 veth 进入 CNI 创建的网桥路由查表命中 flannel.1 之后被封装成 VXLAN 报文。结构上分两层内层是 Pod 的原始 IP 报文外层是宿主机 IP 和 UDP 头目的端口 4789。对端节点收到 UDP 包后解封装把原始包投递到 cni0 网桥再转给目标 Pod。这条链路要求所有节点之间能走通 UDP 4789防火墙和云安全组里必须放行。VNI 默认是 1同一 flannel 网络里所有节点共享这个 VNI。排查的时候不要只在 Pod 里 ping还要在宿主机上分别抓 flannel.1 和物理网卡两个位置才能看出包到底卡在封装前还是封装后。另一个 backend 是 host-gw。它不封包flanneld 直接在节点路由表里写“去对端 Pod 网段走对端节点 IPdev eth0”。这样性能最接近裸机但有一个硬前提所有节点必须在同一个二层网络里。ARM64 集群如果都堆在同一台交换机下面host-gw 是性能最优解如果节点分布在多个 VLAN 或者云上不同 VPCVXLAN 才有意义。第 5 章会给具体对比参数。2.3 etcd 模式和 Kubernetes API 模式怎么选v0.11.0 是个比较特殊的版本它同时支持老式 etcd 存储和--kube-subnet-mgr新方式。区别在于子网租约放哪里。etcd 模式下网络配置和节点租约全部放在/coreos.com/network前缀下面flanneld 只依赖 etcd 一个外部服务kube-subnet-mgr 模式下flanneld 通过 Kubernetes API 读写节点注解来分配子网不再直接连 etcd。我的建议是离线内网、systemd 手动管理进程的场景走 etcd 模式少一层 apiserver 依赖排错路径更直白如果你的集群已经用官方 kube-flannel.yml 这种 DaemonSet 方式托管那自然走 kube-subnet-mgrcni 配置也由 DaemonSet 里的 initContainer 自动生成。需要注意的是v0.11.0 那个年代的 CNI conflist 写法和今天稍有差别后面 3.4 会专门说明。2.4 v0.11.0 的老版本边界不是所有 K8s 都兼容这里要泼一盆冷水flannel v0.11.0 对应的是 Kubernetes 1.9 到 1.16 那个阶段Pod CIDR、Node 注解格式、CNI 版本都跟现在有差异。如果你手里的集群是 1.20 之后的版本建议直接上 flannel v0.22 以上的新版v0.11.0 更适合老版本集群、离线内网迁移、或者你手头就只有这个 ARM64 包的目标环境。这个边界必须提前说清楚否则你照着老文档装完apiserver 那边node.Spec.PodCIDR一直为空你会以为 flannel 装错了实际上是版本代差。Kubernetes 从 1.17 开始对 Node 注解和 CNI 规范做了不少收紧v0.11.0 的 flanneld 在识别新版 Node 对象时可能拿不到预期的字段。所以本资源定位是“特定历史版本”不是通用最新方案。3. 从 tar.gz 到跨节点通网v0.11.0 的完整部署流水线3.1 解压前先确认三件事架构、内核模块、etcd 状态拿到flannel-v0.11.0-linux-arm64.tar.gz别急着tar -xzf。先核对环境否则解压完跑起来才发现二进制根本执行不了。uname -m cat /proc/cpuinfo | grep -i architectureuname -m必须返回aarch64。有些 ARM 板子的系统是 32 位用户态即使 CPU 是 64 位也跑不了 ARM64 二进制这是第一个坎。接着确认内核模块modprobe vxlan modprobe br_netfilter lsmod | grep -E vxlan|br_netfilterVXLAN backend 依赖内核的 vxlan 模块cni0 网桥依赖 br_netfilter。如果modprobe报错说明内核里没有编入这个模块常见于极度精简的 ARM 内核要么换内核要么改用 host-gw backend。这个决策影响后续配置建议在一开始就定下来。最后确认 etcd 或 Kubernetes 集群的健康状态。走 etcd 模式就etcdctl --endpointshttp://127.0.0.1:2379 endpoint health走 kube-subnet-mgr 模式就确认 kubeconfig 文件可读。不要跳过这步后面大部分启动报错都源自 etcd 不可达或 v2 API 未开启。提示flannel v0.11.0 年代的主流部署是 etcd v2 API。如果你的 etcd 是 3.4 以后版本且没有开放 v2 接口建议直接用 kube-subnet-mgr 模式省得跟接口版本纠缠。3.2 解压 tar.gz 并确认 flanneld 二进制可用mkdir -p /tmp/flannel-pkg tar -xzf flannel-v0.11.0-linux-arm64.tar.gz -C /tmp/flannel-pkg ls -l /tmp/flannel-pkg先解压到临时目录看清楚里面到底有哪些文件。常见的 flannel 发布包解压出来是 flanneld 主程序有些附带 README 和 systemd 样例。我不建议直接解压到/usr/local/bin因为有些包解压出来是普通目录结构直接覆盖容易把别的文件搞乱。看清楚了再拷贝cp /tmp/flannel-pkg/flanneld /usr/local/bin/flanneld chmod x /usr/local/bin/flanneld /usr/local/bin/flanneld --version--version能正常打印版本号说明二进制在当前内核下可执行。如果这里直接报Illegal instruction说明二进制指令集和系统不匹配已经不用往下走了。3.3 写入 etcd 网络配置并启动 flanneldetcd 模式的第一个关键动作是把整个集群的网络配置文件写进 etcd。这里用 v2 API 的写法ETCDCTL_API2 etcdctl set /coreos.com/network/config \ {Network:10.244.0.0/16,Backend:{Type:vxlan}}这个 JSON 决定 flannel 使用哪个网段、多少位子网掩码、什么 backend。Network是整个集群的 Pod CIDR必须与其他 CNI 预留网段错开Backend.Type选vxlan还是host-gw决定了后面所有节点的转发行为。然后写 systemd 服务cat /etc/systemd/system/flanneld.service EOF [Unit] Descriptionflanneld Afternetwork-online.target etcd.service Wantsnetwork-online.target [Service] ExecStart/usr/local/bin/flanneld \ --etcd-endpointshttp://127.0.0.1:2379 \ --ifaceeth0 \ --ip-masq Restarton-failure RestartSec5 [Install] WantedBymulti-user.target EOF systemctl daemon-reload systemctl enable --now flanneld systemctl status flanneld几个参数值得展开说。--etcd-endpoints指向你的 etcd 地址多台 etcd 用逗号分隔--ifaceeth0指宿主机物理网卡名ARM64 板卡上常见eth0、enp1s0、end0这类名字必须先ip link看清楚flannel 会自动选择默认路由网卡但这在 ARM 设备上经常选错--ip-masq开启 SNATPod 访问集群外部网络时会把源地址伪装成节点 IP内网互通如果不做对外访问可以不开但建议默认开着。启动后观察日志journalctl -u flanneld -f正常日志里能看到它从 etcd 拉到网络配置、申请到子网、写入路由表。如果卡住不动基本就是第 4 章要讲的那些问题。3.4 补上 CNI 插件和 conflisttar.gz 里未必全包归档包里通常是 flanneld 这个 daemon而 kubelet 真正调用的是/opt/cni/bin下的 CNI 插件。如果你解压后发现目录里没有名为flannel或bridge的可执行文件需要从 cni-plugins 的 linux-arm64 包或 flannel-cni-plugin 里补。这一步很多人会忽略结果是 flanneld 状态正常但 Pod 一直ContainerCreating。CNI 插件就位后写/etc/cni/net.d/10-flannel.conflist{ name: flannel, cniVersion: 0.3.1, plugins: [ { type: flannel, delegate: { isDefaultGateway: true, hairpinMode: true } }, { type: portmap, capabilities: { portMappings: true } } ] }type: flannel表示 kubelet 会去/opt/cni/bin找名为flannel的可执行文件这个插件负责读取 flanneld 生成的/run/flannel/subnet.env并调用 bridge 插件完成 veth 对创建和 IP 分配。cniVersion用 0.3.1和 v0.11.0 的年代匹配太新的 CNI 协议格式反而不适合老 flannel 插件。如果你的集群节点上有 Docker 创建的 docker0 网桥注意避免网段冲突。flannel 默认网段是 10.244.0.0/16Docker 默认 172.17.0.0/16一般不冲突但如果你之前手动改过 Docker 网段必须先确认两边没有重叠。3.5 验证部署结果网卡、路由、Pod 三层确认ip addr show flannel.1 ip route | grep 10.244 cat /run/flannel/subnet.envflannel.1有 inet 地址说明 flanneld 已把节点子网挂到虚拟网卡上路由表里能看到10.244.2.0/24 dev flannel.1这类记录说明跨节点路由已生效/run/flannel/subnet.env里包含FLANNEL_SUBNET和FLANNEL_MTU是 CNI 插件分配 IP 的依据。接着在集群里创建两个跨节点的测试 Pod看它们是否Runningkubectl get pods -o wide kubectl exec -it pod-a -- ping pod-b-ip能 ping 通部署就算成功ping 不通或者第一个 Pod 起不来看第 4 章。4. 避坑记录ARM64 环境下 flannel v0.11.0 的五个失败现场4.1 启动报错找不到网络配置etcd 数据没写对现象flanneld 启动后日志里出现network config not found或者failed to fetch network config之类的字眼进程退出。原因多数情况是/coreos.com/network/config这个 key 没写进去或者 etcd 版本与 API 不匹配。v0.11.0 时代用 etcd v2 API 写是常态如果你用的是 etcd 3.x 的命令行工具默认写入的是 v3 的 key 空间flanneld 读 v2 前缀两边根本对不上。解决先检查 etcd 里到底有没有数据ETCDCTL_API2 etcdctl get /coreos.com/network/config返回为空就重新写配置然后重启 flanneld。如果 etcd 版本太新v2 API 可能已经关闭可以看 etcd 启动参数里有没有--enable-v2true。更省事的方案是改用 kube-subnet-mgr 模式彻底绕开 etcd key 空间的坑。4.2 Pod 跨节点 ping 不通FORWARD 链丢包现象flanneld 日志正常flannel.1地址和路由表都在但 Pod 之间 ping 不通在宿主机上 ping 对端 Pod IP 也不通。原因这不是 flannel 的问题是 Linux 主机的 iptables FORWARD 链默认策略。装了 Docker 的机器经常会把 FORWARD 策略改成DROPflannel 创建的转发流量走到这里直接被丢弃。解决sysctl -w net.ipv4.ip_forward1 iptables -P FORWARD ACCEPT如果前面值非常重要再把规则持久化到/etc/sysctl.d/里。还需要确认rp_filter没有误伤到 VXLAN 解封装后的数据包cat /proc/sys/net/ipv4/conf/all/rp_filter返回非 0 时建议在/etc/sysctl.conf里显式设 0尤其是多网卡 ARM 设备。这个项目我从一开始就是先查 FORWARD 链少走很多弯路。4.3 小包通大包不通MTU 被 VXLAN 头吃掉 50 字节现象ping 默认大小能通传大文件一直卡住ping -s 1472通ping -s 1500不通。原因VXLAN 封装在原始 IP 包外面增加了外层 UDP 和 IP 头系统默认 MTU 1500 的物理网卡实际可用载荷变成了 1450。如果 flanneld 没有正确下发改后的 MTU 给 CNI 插件容器网卡还是会用 1500大包到物理网卡后直接超限丢弃。解决检查/run/flannel/subnet.env里的FLANNEL_MTU正常应该是1450。如果不对手动在 etcd 网络配置里指定 MTUETCDCTL_API2 etcdctl set /coreos.com/network/config \ {Network:10.244.0.0/16,Backend:{Type:vxlan},MTU:1450}写完后每个节点要重启 flanneld并且重启 kubelet 让已存在 Pod 重新走一遍 CNI 配置流程。只改 flanneld 不重启 Pod容器网卡 MTU 不会自动刷新。4.4 多网卡环境选错出口--iface和--public-ip必须显式指定现象flanneld 启动后日志显示的 Public IP 是192.168.1.5可集群里其他节点根本访问不到这个地址或者同节点上另一块物理网卡才是真正的业务网段。原因ARM64 板卡上经常同时存在板载网卡和 USB 网卡、PCIe 网卡、管理口等多块网卡。flannel 默认选默认路由网卡这个过程在特殊路由表下可能选到管理口或虚拟网桥数据面就断了。解决启动参数里显式写好ExecStart/usr/local/bin/flanneld \ --etcd-endpointshttp://127.0.0.1:2379 \ --ifaceeth1 \ --public-ip192.168.2.10--iface决定 VXLAN 走哪块物理网卡--public-ip决定其他节点向哪个 IP 封装流量。多网卡环境下我一般两个参数都写只写其中一个都不保险。改完再逐节点核对ip route和journalctl -u flanneld里的 Public IP。4.5 旧租约残留导致新节点子网冲突需要手动清 etcd现象新节点加入集群flanneld 日志显示申请到的子网跟已有节点完全一样节点间路由互相覆盖Pod 访问有一部分通有一部分 500。原因节点异常下线、etcd 数据没清理时旧租约不会自动立刻释放。flanneld 从 etcd 拿到一个已被别的节点占用的子网两个节点都往路由表里写同一个网段内核路由只能保留一条。解决在 etcd 里查看当前租约列表ETCDCTL_API2 etcdctl ls /coreos.com/network/subnets找到不属于在线节点的 key直接删掉后重启 flanneld。那句老话“不能解决问题就删掉重来”在子网冲突场景下特别好用。生产环境里我后来都用 kube-subnet-mgr 模式租约跟着 Node 生命周期走省了手动清 etcd 的麻烦。5. 参数调优backend、MTU、Public IP 三个影响 ARM64 集群速率的关键选择5.1 backend 选型VXLAN 还是 host-gw很多 ARM64 集群规模不大节点全部在同一个二层网络里这个时候默认的 VXLAN 其实不是最优解。用 host-gw 可以让跨节点 Pod 访问不经过封包拆包性能更接近物理机。对比项VXLANhost-gw跨二层网络支持物理网络只需放行 UDP 4789不支持要求三层可达、二层互通报文开销每包增加约 50 字节外层 UDPIP无额外头性能表现有一定 CPU 开销ARM 单板机上更明显接近裸路由配置复杂度需要关注 MTU 和 UDP 放行只需要路由互通适合场景云 VPC、混合网段同交换机下的自建 ARM64 集群切换 backend 只需改 etcd 配置里的Backend.TypeETCDCTL_API2 etcdctl set /coreos.com/network/config \ {Network:10.244.0.0/16,Backend:{Type:host-gw}}改完后每个节点重启 flanneld。注意 host-gw 需要所有节点之间已经能直接互 ping否则路由写下去也是黑匣子。如果节点跨网段千万别硬上 host-gw。5.2 MTU 计算公式不要让大包卡在物理网卡VXLAN 的 MTU 计算很简单容器网卡 MTU 物理网卡 MTU - 50。这是最基本的封装开销。物理网卡 MTUVXLAN 推荐容器 MTUhost-gw 推荐容器 MTU1500145015009000jumbo frame895090001450特殊内网14001450flanneld 通常会自动探测主网卡 MTU 并写入/run/flannel/subnet.env但它探测的是--iface指定的网卡。如果你的 ARM64 节点上存在多块不同 MTU 的网卡自动探测不一定准。建议在 etcd 网络配置里显式写MTU字段让所有节点保持一致。检查命令还是那句cat /run/flannel/subnet.env5.3 Public IP 与多网卡跨网段集群最容易翻车的地方ARM64 板卡的网络拓扑经常不规整管理口eth0、业务口eth1、USB 网卡eth2。flannel 默认拿默认路由网卡的 IP 作为 Public IP 和 VXLAN 源地址这时集群的“数据面地址”和“管理面地址”就分叉了。手动部署时所有节点都要统一指定--ifaceeth1 --public-ip192.168.2.10iface决定 flannel 使用哪张网卡采集 MAC 和 MTUpublic-ip决定对端节点把包封装到哪个目标 IP。如果集群节点分散在不同机房需要各自填对应的独立 IP并用防火墙确保 4789 端口在所有节点间互通。这个参数我在多网卡机器上踩过不止一次后来习惯是写 systemd 之前先把每个节点的网卡名和 IP 列成表格再统一生成配置避免各写各的。5.4 subnet-len集群容量与路由表规模的权衡SubnetLen控制每个节点分到的子网大小。默认 24整个集群最多 256 个节点。如果你的 ARM64 集群规模不大这个默认值不用动但如果预计节点超过 100建议改成 23ETCDCTL_API2 etcdctl set /coreos.com/network/config \ {Network:10.244.0.0/16,SubnetLen:23,Backend:{Type:vxlan}}SubnetLen 每减小一位节点可容纳数量翻倍但每个节点的 Pod 容量减半。比如 10.244.0.0/16 配 /23最多 512 个节点每个节点 512 个 Pod 地址。这个值要在集群初始化阶段定好后期改会丢掉已分配的租约属于“后悔药里最难吃的一类”建议规划时想清楚。6. 验证一下隧道通没通tcpdump 三处抓包定位 VXLAN 链路集群部署完不要只看kubectl get pods是 Running 就完事。容器网络这类黑匣子跑通一次数据面才算真通。我验证的套路是在节点 A 上 ping 节点 B 的 Pod IP同时用 tcpdump 在链路的三处位置抓包。第一处节点 A 上抓flannel.1确认原始 ICMP 包已经进入隧道设备tcpdump -i flannel.1 icmp -nn第二处节点 A 物理网卡上抓 UDP 4789确认原始包确实被封装成了 VXLAN 报文tcpdump -i eth1 udp port 4789 -nn第三处节点 B 的解封装侧抓cni0或flannel.1tcpdump -i cni0 icmp -nn正常情况节点 A 的flannel.1能看到 ICMP 请求和回复物理网卡能看到 UDP 4789 的封包来回节点 B 的cni0能看到 ICMP 包到达。如果第一处有、第二处没有说明问题出在 flannel 封装或路由选择如果第二处有、第三处没有说明对端解封装或投递失败重点看 rp_filter 和 FORWARD 链。再补充一个查 VTEP 邻居的命令ip neigh show dev flannel.1这里能看到对端节点的 MAC 地址STALE状态是正常的FAILED就说明对端 flannel.1 没起来。从那以后我每次搭完 flannel 都强制走一遍这三处抓包流程十分钟就能定位到数据面断点再也不用靠重启节点碰运气。这套验证动作看起来简单但对 flannel 这种跨节点网络方案是最直接有效的落地检查希望帮到你。本文还有配套的精品资源点击获取