简介:这份面向 Kubernetes 集群网络部署与运维场景的 Flannel v0.11.0 发布包,专为 Linux ARM64 平台准备,适合在 ARM 架构节点上快速搭建或排查 Pod 覆盖网络的学习者与工程师使用。压缩包共 3 个文件,包含 1 个 flanneld 可执行程序、1 份 Markdown 说明文档和 1 个 Shell 辅助脚本,整体约 8.03MB,可省去从源码编译的步骤。已有 455 人学习下载。随附的说明文档可用于了解版本信息与基本用法,Shell 脚本则能辅助生成 Docker 容器运行时所需的网络参数,便于将 flanneld 接入集群网络配置。对于需要理解 Flannel 后端通信、验证 ARM64 二进制可用性、复现节点网络问题或做轻量实验的读者,这份包提供了可直接运行的组件与基础参考,适合作为环境搭建和排错练习的起点。
1. flannel v0.11.0 的 arm64 包,先搞清楚它到底解决什么
在 arm64 的 k8s 节点上手工装 CNI,最容易让工作停滞的环节往往不是写 YAML,而是拿到一个 amd64 的 flanneld,然后对着 exec format error 发呆半天。这份 flannel-v0.11.0-linux-arm64.tar.gz 走的是另一条路:不去镜像仓库碰运气,直接把编译好的 flanneld 二进制铺到机器上,配 etcd 或 kube-subnet-mgr 都能跑。它适合边缘盒子、国产化 arm64 服务器这类镜像 tag 经常缺架构、集群规模又不大(几十个节点以内)的场景,核心作用只有一个——让每个节点拿到属于自己的 Pod 网段,并把跨节点流量封出去。缺点也明确:版本停在 0.11.0,后面几章会讲清这个版本的边界在哪、什么时候别硬上。
2. 解包与节点预检:arm64 上跑 flanneld 之前要过的四道关
拿到一个 tar.gz 就急着tar -xzf然后./flanneld,在半数情况下能跑起来,但跑起来和跑对是两件事。flanneld 是一个需要内核配合的守护进程,它对 vxlan 模块、转发开关、rp_filter、端口占用都有隐含依赖,这些条件不满足时,进程可能起来了,Pod 却一直卡在 ContainerCreating。下面按拆包、内核、网卡三步走一遍,每一步都给出可验证的输出。
2.1 先列清单再解压:确认二进制架构与依赖
我一般不解压,先tar -tzf看清单,这一步能省掉后面很多麻烦,尤其是从内网论坛转手拿到的包,文件名写着 arm64、里面躺着 amd64 的情况并不罕见。
# 1) 列清单,不解压 tar -tzf flannel-v0.11.0-linux-arm64.tar.gz # 2) 解压到独立目录,避免覆盖旧的 flanneld mkdir -p /opt/flannel/v0.11.0 tar -xzf flannel-v0.11.0-linux-arm64.tar.gz -C /opt/flannel/v0.11.0 ls -l /opt/flannel/v0.11.0 # 3) 验架构 + 验能不能跑,这两步别省 file /opt/flannel/v0.11.0/flanneld /opt/flannel/v0.11.0/flanneld --versionfile输出应该是ELF 64-bit LSB executable, ARM aarch64。如果出现x86-64,后面的工作都失去意义,请换包。flanneld --version除了打印版本号,还顺带验证了动态链接库是否齐全——这是个低成本检查,比等到 systemd 里看 exit code 127 要直观得多。
包里的文件各有用处,接手后先对一遍:
| 文件 | 用途 | 实际处理建议 |
|---|---|---|
| flanneld | 主程序,负责申请网段、下发路由、维护 FDB | 装到/opt/flannel/bin/或/opt/bin/ |
| mk-docker-opts.sh | 从 subnet.env 生成 docker 启动参数 | 只对 dockershim 时代有意义,新集群可以忽略 |
| README 类文本 | 版本与后端说明 | 快速扫一眼默认后端是哪种 |
mk-docker-opts.sh这个脚本是历史遗留物,它的作用是把/run/flannel/subnet.env里的FLANNEL_SUBNET、FLANNEL_MTU转成--bip=、--mtu=塞给 dockerd。在容器运行时已经不是 docker 的集群里,这个脚本只会误导人去改 docker 配置,看到它知道来历就行。
2.2 内核模块与转发开关:四个必须落地的参数
flannel 的 vxlan 后端不是一个纯用户态程序,它依赖内核的 vxlan 模块和标准的 Linux 转发能力。装二进制之前先把这些确认掉,比事后查 Pod 为什么不通要省时间。
# 1) 架构与内核版本,4.x 以下要留心里核对 vxlan 的支持情况 uname -m; uname -r # 2) 加载 vxlan 与 br_netfilter,后者决定 Pod 经过网桥时 iptables 是否生效 modprobe vxlan modprobe br_netfilter lsmod | grep -E 'vxlan|br_netfilter' # 3) 写死成开机加载,避免节点重启后 flannel.1 建不出来 cat > /etc/modules-load.d/flannel.conf <<'EOF' vxlan br_netfilter EOF # 4) 转发与反向路由过滤 cat > /etc/sysctl.d/99-flannel.conf <<'EOF' net.ipv4.ip_forward = 1 net.bridge.bridge-nf-call-iptables = 1 net.ipv4.conf.all.rp_filter = 0 net.ipv4.conf.default.rp_filter = 0 EOF sysctl --systemnet.ipv4.ip_forward=1是唯一硬性条件,不开这个跨节点包直接丢。bridge-nf-call-iptables=1关系到 NetworkPolicy 和 Service 转发能不能生效,kube-proxy 的 iptables 规则挂在 nat 表上,Pod 走网桥出流量时若不过 iptables,规则形同虚设。rp_filter是那个容易被忽略、又最容易影响判断的参数:多数发行版默认是 1(严格模式),当 vxlan 封装包从flannel.1进来、回包却从eth0出去时,严格反向路由校验会判为非法并丢包,现象就是单向不通——ping 有去无回,而tcpdump在eth0上能看到请求、看不到响应。改成 0 或 2 都行,我习惯直接 0。
提示:
sysctl --system之后用sysctl net.ipv4.conf.all.rp_filter复查一遍,有些发行版的 cloud-init 会在稍后重新覆盖这个值。
2.3 VXLAN 端口与网卡选型:别让 8472 撞车,别让 flannel 选错网卡
flannel 默认的 VXLAN 端口是8472,不是 IANA 分配的 4789。这个差异导致两个常见事故:一是宿主机上跑着别的 vxlan 方案(比如某些 SDN agent)也占了 8472,flanneld 建flannel.1时报address already in use;二是网络设备侧的 ACL 只放通了 4789,封包出去就被拦。
# 查 8472 是否被占用 ss -ulnp | grep 8472 # 查是否已有同名 vxlan 设备(多半是上次卸载没清干净) ip -d link show flannel.1网卡选型同样值得先定下来。多网卡机器上 flannel 默认取默认路由那张卡,边缘设备常见的「管理口 + 业务口」双网卡布局里,选错就会导致跨节点不通、但同节点 Pod 互访正常这种半瘫状态。显式指定比依赖自动探测稳:
# 三种指定方式,按场景选一种 flanneld --iface=eth0 # 直接点名 flanneld --iface-regex='^(eth|enp).*' # 正则,适合网卡名不固定的机型 flanneld --iface-can-reach=10.0.0.1 # 反查:哪张卡能到 apiserver 就用哪张--iface-can-reach在 ARM 边缘场景里最实用,因为这类设备的网卡命名经常随内核版本漂移,eth0和enp1s0混着来,写死名字的配置文件换台机器就失效。这三个参数建议在启动脚本里就固化下来,不要依赖默认行为——默认行为在标准 x86 服务器上大概率正确,在 arm64 盒子上则不一定。
3. 后端选型与配置落盘:vxlan、host-gw、udp 到底怎么挑
flannel 的价值有一半在后端可插拔上,三种后端的性能与适用条件差得相当远,选错了后面所有调优都是白费。这一章先把三者的开销与边界摆出来,再落到net-conf.json的实际写法和 MTU 的算法上,因为这两个文件配置错了,症状都是一样的「跨节点不通」,但修法完全不同。
3.1 三种后端的开销与适用边界
| 后端 | 封装方式 | 网络要求 | 单跳额外开销 | 适用场景 |
|---|---|---|---|---|
| vxlan | 内核态 UDP 封装,外层走 8472 | 节点间三层可达即可 | 约 50 字节包头 + 轻微 CPU | 云上、跨网段、跨机房,默认选它 |
| host-gw | 不封装,纯静态路由 | 所有节点在同一二层广播域 | 几乎为零 | 同机架、同 VLAN 的自建机房 |
| udp | 用户态封装,走 8285 | 三层可达 | 明显,包要进出用户态两次 | 老内核没有 vxlan 模块时的保底 |
v0.11.0 默认后端就是 vxlan,官方清单里也是这个值。我一般不在第一版就动它,因为 vxlan 的兼容性最好——只要节点之间能互 ping,vxlan 基本就能通。host-gw 的性能确实好,路由直接指向对端节点 IP,没有封装解封装,但它要求节点全在一个二层域里,这一条在混合云、跨可用区的部署中基本不成立,而这类部署恰恰是「节点能互通但不在同一网段」的情况。至于 udp 后端,除非你手上是 3.10 以下的老内核、modprobe vxlan直接失败,否则不建议用,它的转发路径太长,一旦出问题排查起来也最费劲。
3.2 net-conf.json 的字段含义与 subnet.env 的来历
配置分两个文件,职责不同,很多人搞混:net-conf.json是你写给 flanneld 的输入,subnet.env是flanneld 算完给你的输出。前者写错,进程起不来;后者不存在,kubelet 和 CNI 插件就没法给 Pod 配网。
# flanneld 的输入:集群级网段与后端类型 mkdir -p /etc/kube-flannel cat > /etc/kube-flannel/net-conf.json <<'EOF' { "Network": "10.244.0.0/16", "Backend": { "Type": "vxlan", "Port": 8472 } } EOF三个字段的含义与约束:Network必须和 kube-controller-manager 的--cluster-cidr完全一致,不一致的直接后果是 controller 分配 PodCIDR 用的是 A 网段、flannel 建路由用的是 B 网段,Pod 起来了但跨节点永远不通,而且日志里不会报错;Type取vxlan、host-gw、udp三者之一,改了之后必须重启 flanneld 才生效;Port省略时按 8472 处理,只有在明确需要避让端口时才写。这个 JSON 里不能写注释,写完用python -m json.tool或jq .验一下格式,因为 flanneld 读取失败时的报错信息相当含糊,只会说配置解析错,不告诉你哪一行。
flanneld 启动后会把结果落到/run/flannel/subnet.env,内容是四行键值:
# 这是 flanneld 生成的结果,不要手工改 cat /run/flannel/subnet.env # FLANNEL_NETWORK=10.244.0.0/16 # FLANNEL_SUBNET=10.244.1.1/24 # FLANNEL_MTU=1450 # FLANNEL_IPMASQ=trueFLANNEL_SUBNET就是本节点分到的 /24,CNI 插件据此给 Pod 分配地址并把cni0网桥配上网关 IP。注意/run通常是 tmpfs,节点重启后目录清空,所以 flanneld 必须先于 kubelet 的网络配置步骤把文件重新写出来——依赖顺序错了,kubelet 会报找不到 subnet.env。
3.3 MTU 算法与跨节点大包:影响排查最多的一个参数
vxlan 封装要额外占 50 字节(外层 IP 20 + UDP 8 + VXLAN 头 8 + 内层以太网 14),所以物理网卡 1500 时,Pod 网卡的 MTU 应该是 1450。计算出来的值由 flanneld 写进subnet.env的FLANNEL_MTU,CNI 插件再据此设置 veth 和cni0。
# 手工核对三个位置的 MTU 是否自洽 ip link show eth0 | grep mtu # 物理卡,应为 1500 ip link show flannel.1 | grep mtu # vxlan 设备,通常等于物理卡减 50 ip link show cni0 | grep mtu # 网桥,应等于 FLANNEL_MTU这三个值不一致时的症状很有迷惑性:ping用小包,通;kubectl exec进容器执行curl访问另一个节点上的服务,卡在连接建立之后没有响应;tcpdump能看到请求过去,回包却出现frag needed and DF set。我遇到过一种更隐蔽的情况——节点分两批上线,第一批物理网卡 1500、第二批开了巨型帧 9000,FLANNEL_MTU分别是 1450 和 8950,跨批通信时大包全丢,而两批内部的 Pod 互访完全正常,排查时非常容易被「集群有一半是好的」这个现象带偏方向。所以集群内物理 MTU 必须统一,这不是 flannel 的限制,是任何叠加网络的前提。
4. 把 flanneld 接进 k8s:CNI 配置、DaemonSet 与三项验证
二进制装好只是准备阶段,真正要让 Pod 拿到网络,还需要 CNI 插件二进制、CNI 配置文件、kubelet 参数三边对齐,外加 flanneld 以 DaemonSet 或 systemd 的形式常驻在每个节点上。这一章给出一条从零到跨节点互通的完整链路,每一步都有可验证的输出。
4.1 CNI 插件二进制:arm64 版本自己要对上
flannel 的 CNI 插件本身不是 flanneld,它来自另一个项目,flanneld 只负责把subnet.env准备好,插件负责读它并给 Pod 配网。两边的架构必须一致。
# cni-plugins 也要 arm64 版本,文件名通常带 arm64 后缀 mkdir -p /opt/cni/bin tar -xzf cni-plugins-arm64-<版本>.tgz -C /opt/cni/bin ls /opt/cni/bin | head -20 # 确认插件能执行(架构对不上的话这里就会报错) /opt/cni/bin/bridge --version 2>/dev/null || /opt/cni/bin/flannel --version/opt/cni/bin下的插件会被 kubelet 按名字调用,flannel、bridge、host-local、portmap这几个必须存在。翻车点在于:从 x86 环境拷贝过来的/opt/cni/bin目录看着文件齐全,执行起来全是Exec format error,而 kubelet 的报错只会说 no such file or directory 或者 plugin not found——因为它拿到的退出码不带细节。所以装完先手动执行一次,这一步花十秒钟,能省一小时。
4.2 写 conflist 并对齐 kubelet 参数
CNI 配置文件的格式决定了 kubelet 怎么组链,flannel 用链式调用,第一个插件产出网段与路由,第二个插件做端口映射。
mkdir -p /etc/cni/net.d cat > /etc/cni/net.d/10-flannel.conflist <<'EOF' { "name": "cbr0", "cniVersion": "0.3.1", "plugins": [ { "type": "flannel", "delegate": { "hairpinMode": true, "isDefaultGateway": true } }, { "type": "portmap", "capabilities": { "portMappings": true } } ] } EOF四个参数逐个说:name是网络名,必须和 kubelet 侧的期望值一致,随便改会导致kubelet认为网络未初始化;cniVersion取 0.3.1 时 kubelet 会走新版 CNI 调用,如果 kubelet 版本较老报incompatible CNI versions,降成0.2.0即可,这是 0.11.0 时代最常见的版本摩擦;delegate.hairpinMode打开后才能让 Pod 通过 Service 访问自己,关掉的话同 Pod 内 curl Service IP 会超时;isDefaultGateway让 flannel 插件在 Pod 里写默认路由,少了这个参数、Pod 只能访问同节点。
kubelet 侧对应三个启动参数,缺一不可:
# systemd 环境下的 kubelet 参数(1.24 之前,dockershim 还在的时代) --network-plugin=cni --cni-conf-dir=/etc/cni/net.d --cni-bin-dir=/opt/cni/bin改完systemctl daemon-reload && systemctl restart kubelet。注意 CNI 配置只在 kubelet 启动或 Pod 重建时读取,改了 conflist 不重启 kubelet、Pod 也不会感知,这是「我明明改对了为什么还是不通」的常见来源。
4.3 DaemonSet 换镜像与挂载点:arm64 tag 要对,hostPath 也要对
flanneld 通常以 DaemonSet 常驻,官方清单默认给的是 amd64 tag,arm64 节点上必须换成对应架构的 tag(这个版本的 tag 是按架构分开的,不像后来有多架构 manifest)。
containers: - name: kube-flannel image: <内网仓库>/flannel:v0.11.0-arm64 command: - /opt/bin/flanneld - --ip-masq - --kube-subnet-mgr securityContext: privileged: true volumeMounts: - name: run mountPath: /run/flannel - name: cni mountPath: /etc/cni/net.d - name: flannel-cfg mountPath: /etc/kube-flannel/ volumes: - name: run hostPath: { path: /run/flannel } - name: cni hostPath: { path: /etc/cni/net.d } - name: flannel-cfg configMap: { name: kube-flannel-cfg }--kube-subnet-mgr表示网段分配走 Kubernetes API(读 Node 对象的 PodCIDR),不再依赖 etcd 里的租约,这是 0.11.0 时代推荐的方式,也顺手绕开了 etcd v2/v3 API 的问题。privileged: true是为了让容器内能建 vxlan 设备、写 iptables,官方清单用的是更细的NET_ADMIN/NET_RAW能力集,我用 privileged 图省事,但生产环境建议按最小权限收窄。
/run/flannel这个挂载点必须和 flanneld 的默认输出路径/run/flannel/subnet.env对上。有些旧文档写的是/var/run/flannel,在/var/run是/run软链的系统上两者等价,但在部分精简镜像或容器内,软链不存在,挂载了/var/run/flannel而进程往/run/flannel写,结果就是宿主上永远看不到 subnet.env。
4.4 三项验证:路由表、flannel.1、跨节点抓包
部署完别急着跑业务 Pod,按顺序验三项,能定位到九成问题。
# 1) flanneld 日志:应该能看到选中的网卡和拿到的租约 kubectl -n kube-system logs -l app=flannel -c kube-flannel --tail=30 # 典型输出:Using interface with name eth0 and address 192.168.1.11 # SubnetLease acquired: 10.244.1.0/24 # 2) 节点侧设备与路由:flannel.1 存在,路由指向对端节点 ip -d link show flannel.1 ip route | grep 10.244 # 3) 跨节点连通:小包 + 大包都要测 kubectl run t1 --image=<内网仓库>/tools:latest --overrides='{"spec":{"nodeName":"node-a"}}' -- sleep 3600 kubectl run t2 --image=<内网仓库>/tools:latest --overrides='{"spec":{"nodeName":"node-b"}}' -- sleep 3600 kubectl exec t1 -- ping -c 3 -s 1400 <t2的PodIP> # 4) 不通时抓两边:内层看 flannel.1,外层看 eth0 的 8472 tcpdump -i flannel.1 -n icmp tcpdump -i eth0 -n udp port 8472ip route | grep 10.244的输出应该能看到目的网段是10.244.x.0/24、下一跳是10.244.x.0 dev flannel.1这样的条目,每个对端节点一条。如果只有本节点的条目、没有对端的,说明 flanneld 没拿到对端租约——通常是对端 flanneld 没起来,或者节点列表没同步。抓包这一步要内外结合看:flannel.1上能看到封包前的内层 ICMP,eth0上能看到 UDP 8472 的外层封装,两者都有但对方没回,问题在网络层(安全组、路由、rp_filter);只有内层没有外层,问题在 vxlan 设备没建起来或者 FDB 表项缺失。这套组合拳的价值在于把「不通」这个模糊结论切成「封装前丢」和「封装后丢」两段,排查范围立刻缩小一半。
5. 排查与避坑:五个让 flanneld 起不来的现场
flannel 的报错信息普遍不友好,很多故障在日志里只有一句话甚至没有。下面五个是我在 arm64 节点上反复遇到的情况,按「现象 → 原因 → 解决」拆开写,遇到同类症状可以直接对号。
5.1 Pod 一直 ContainerCreating,节点上没有 subnet.env
现象:新建的 Pod 卡在ContainerCreating,kubectl describe里只有一句failed to set up sandbox container或者network plugin is not ready,到节点上一看/run/flannel/subnet.env根本不存在。
原因:两种可能。一是 flanneld 容器的/run/flannel挂载路径与实际写入路径不一致,最常见的是 hostPath 用了/var/run/flannel而进程默认写/run/flannel,在/var/run不是软链的精简系统上两者就是两个目录;二是 flanneld 根本没起来,它在等 apiserver,等不到就退出,于是 subnet.env 永远不生成。
解决:先kubectl -n kube-system logs看 flanneld 是否在刷 API 连接失败的日志;再看 DaemonSet 里mountPath与hostPath是否都写着/run/flannel。确认路径后重启 flanneld 的 Pod,等宿主上出现 subnet.env,再删掉卡住的业务 Pod 让它重建——已经被 kubelet 标记为失败的网络配置不会自动重试。
5.2 小包通、大包不通,tcpdump 里满屏 frag needed
现象:同节点 Pod 互访正常,跨节点ping -s 1400丢包,curl某个接口卡住不返回;tcpdump -i eth0能看到ICMP frag needed and DF set。
原因:MTU 链路不自洽。可能是FLANNEL_MTU被设成了物理值 1500 而不是 1450,也可能是集群里物理网卡 MTU 本身不统一(一批 1500、一批 9000),还有一种少见但存在的情况是中间网络设备做了 MSS clamping 而 vxlan 封装后长度又超了。
解决:先统一物理网卡 MTU,再让 flanneld 重新计算FLANNEL_MTU,重启 flanneld 后必须重建已有 Pod——veth 的 MTU 是在创建时写死的,改 subnet.env 不会回溯修改运行中的 Pod。验证方式就是ping -s 1400加ping -s 1472,前者通后者不通,基本就能确认是 MTU 问题。
5.3 flanneld CrashLoopBackOff,日志报 failed to acquire lease
现象:flanneld 的 Pod 反复重启,日志里出现failed to acquire lease: node "xxx" pod cidr not assigned或者error registering network。
原因:走--kube-subnet-mgr时,网段来自 Node 对象的spec.podCIDR,而它由 kube-controller-manager 分配。如果 controller-manager 没开--allocate-node-cidrs=true,或者--cluster-cidr与net-conf.json里的Network不一致,节点就永远拿不到 PodCIDR。另一种情况是节点重装或改了 hostname,旧 Node 对象残留,新节点认为自己是新节点、controller 又没给旧对象清理。
解决:先查 controller-manager 的三个参数--allocate-node-cidrs、--cluster-cidr、--node-cidr-mask-size;再用kubectl get node <名字> -o jsonpath='{.spec.podCIDR}'看分配结果,为空就是 controller 侧的问题。确认是残留对象的话,删掉 Node 让它重新注册,比手工 patch podCIDR 干净。
5.4 kubelet 报 failed to set bridge addr,cni0 已有别的 IP
现象:Pod 创建失败,kubelet 日志里出现failed to set bridge addr: "cni0" already has an IP address different from 10.244.x.1/24。
原因:节点上的cni0网桥残留了上一次集群的网关地址。典型触发场景是改过cluster-cidr(比如从 10.244 换到 172.20),或者这台机器之前属于另一个集群、卸载时只删了 Pod 没清网桥。
解决:停 kubelet,ip link set cni0 down && ip link del cni0,清掉/var/lib/cni下的缓存,再启动 kubelet 让 flannel 重建网桥。注意顺序不能反——kubelet 还在跑的时候删网桥,它可能立刻重建出一个同样错误的 cni0。
5.5 镜像拉不下来或 exec format error:架构 tag 对不上
现象:ImagePullBackOff,或者镜像拉下来了但容器起不来,kubectl describe显示exec format error。
原因:0.11.0 这个年代的镜像 tag 是按架构分开的,v0.11.0和v0.11.0-amd64通常只含 amd64,arm64 要用带-arm64后缀的 tag。从 x86 环境复制清单到 arm64 节点是最常见的来源,而且拉取阶段不一定报错——如果内网仓库对 tag 做了重定向,能拉下来但跑不了,症状就延后到运行期。
解决:kubectl -n kube-system get pod -o jsonpath逐个核对实际拉取的镜像地址;用uname -m的结果反推需要的 tag。内网仓库建议直接把架构写进 tag 名(flannel:v0.11.0-arm64),不要靠 manifest list 隐式匹配,这个版本的多架构支持并不完整。
6. 巡检与升级判断:三个信号决定 0.11.0 还能用多久
v0.11.0 是个能长期稳定跑的版本,但它有几条明确的能力边界:CNI spec 支持到 0.3.1 为止,对更新版本 kubelet 的兼容性没保证;网段分配要么走 etcd 租约、要么走 Node 的 PodCIDR,后者依赖 controller-manager 参数正确;镜像没有统一的多架构 manifest,跨架构迁移必须手工换 tag。判断要不要升级,我一般看三个信号:集群里开始出现cniVersion不兼容的报错、节点规模超过单 etcd 或单 controller 的处理能力、以及需要 NetworkPolicy 之外的更细网络能力。这三条任何一条成立,就该规划迁移,而不是继续在 0.11.0 上打补丁。
日常巡检我写了个脚本,扔到每台节点上跑,输出比翻日志快得多:
#!/usr/bin/env bash # 节点侧 flannel 巡检:只看四件事,全部有输出再谈业务 set -u SF=/run/flannel/subnet.env echo "== node: $(hostname) arch: $(uname -m)" # 1) 租约文件是否存在,内容是否自洽 if [ -f "$SF" ]; then . "$SF" echo "subnet=${FLANNEL_SUBNET:-NA} mtu=${FLANNEL_MTU:-NA}" else echo "subnet.env MISSING -> flanneld 未成功启动" fi # 2) vxlan 设备与端口 ip -d link show flannel.1 >/dev/null 2>&1 \ && echo "flannel.1 OK mtu=$(ip link show flannel.1 | awk '{print $5}')" \ || echo "flannel.1 MISSING -> 查 modprobe vxlan" # 3) 对端路由条数,应与集群节点数大致相当 echo "remote routes: $(ip route | grep -c 'dev flannel.1')" # 4) 转发开关 echo "ip_forward=$(sysctl -n net.ipv4.ip_forward) rp_filter=$(sysctl -n net.ipv4.conf.all.rp_filter)"脚本里第四个检查项容易被忽略。ip_forward是 0 的时候,同节点 Pod 之间照样通(走网桥,不过转发),但跨节点全挂,而你从 Pod 内部完全看不出区别。我现在的习惯是每次上线新节点,先跑一遍这个脚本,四项都正常再往节点上调度业务;上线后第一件事是ping -s 1400打一次跨节点大包,而不是等业务方来报「接口超时」。血泪经验是 MTU 这类问题在小流量测试里根本暴露不出来,一上量就是一整片 502。
从那以后,我每次在 arm64 节点上装 CNI,都强制按file flanneld→lsmod | grep vxlan→cat /run/flannel/subnet.env这个顺序走一遍,三条不过就不动 Pod。希望帮到你。
本文还有配套的精品资源,点击获取