简介:面向 Kubernetes 集群网络部署与运维场景,flannel v0.11.0 的 linux-arm64 发行包适合在 ARM64 服务器、边缘节点或实验环境中部署容器跨主机通信方案,也可供需要对照旧版本行为的开发与运维人员做兼容性验证。压缩包共 3 个文件,由 flanneld 可执行程序、版本说明文档和辅助脚本组成,整体约 8.03MB,体积轻量,便于离线分发与快速替换。已有 455 人学习下载,说明该版本在特定架构与历史集群中仍有一定参考需求。对于需要在 ARM64 平台上复现旧版集群网络问题的团队,这类固定版本包能减少环境差异带来的干扰;读者还可获得配套说明与参数生成辅助,用于核对网络配置、排查版本差异,理解 flannel 在 Kubernetes 网络模型中的角色,适合搭建测试环境、做版本归档或研究容器跨主机通信机制。
1. 节点 Ready 了 Pod 却起不来:先从 flannel v0.11.0 的 tar 包说起
一个 ARM64 的边缘集群交付现场,kubelet 起得来,节点状态是 Ready,kubectl get node看着一切正常,但所有业务 Pod 都卡在 ContainerCreating。describe一看,networkPlugin cni failed to set up pod network: failed to find plugin "flannel" in path [/opt/cni/bin]。这类 flannel k8s 组网问题在 x86 上很少见,一到 arm64 就高发,原因也很朴素:镜像架构不对、二进制没落到/opt/cni/bin、Pod 网段和--cluster-cidr没对上,三件事里任一件出问题,节点都是「假 Ready」。手上这份flannel-v0.11.0-linux-arm64.tar.gz就是为这种场景准备的,v0.11.0 属于老一代版本,配套 k8s 1.13 到 1.16 那一档,工序比新版本多:二进制、CNI 插件、DaemonSet 清单要分三步落地,哪一步省了都会在 Pod 起网时暴露出来。
2. 装前对表:flannel v0.11.0 与 k8s 版本、内核、网卡的硬条件
装 flannel 最常见的翻车方式是「拿到包就解压、解压完就 apply」,中间两个东西没核:宿主内核有没有 vxlan 模块,节点上到底哪张网卡才是集群通信口。这两个信息在 x86 云主机上通常是默认就绪的,到了自建的 arm64 机器上(尤其是多网口板卡)就得亲手确认一遍。这一章把三张表对完再动手,后面能省掉大半排查时间。
2.1 版本三件套:k8s、flannel、CNI 规范要对得上
v0.11.0 是个有明确时代坐标的版本。它自带的kube-flannel.yml用的是 initContainer 方式安装 CNI 插件,配置文件写的是cniVersion: 0.3.1的 conflist 结构,这些都对应 k8s 1.13 到 1.16 的 kubelet 行为。如果你把它硬塞进 1.24 之后的集群(dockershim 已移除、kubelet 不再认--network-plugin参数),CNI 配置本身还能用,但节点侧的日志路径、插件目录默认值都会变,出问题时查错方向完全不同。
先把对照关系列清楚,别凭印象:
| 组件 | 推荐版本 | 说明 |
|---|---|---|
| kubelet / kube-apiserver | 1.13 ~ 1.16 | v0.11.0 官方清单的适配区间 |
| flannel | v0.11.0(arm64 包) | 本文主角,二进制 + DaemonSet 双形态 |
| CNI spec | 0.3.0 / 0.3.1 | conflist 里的cniVersion字段 |
| CNI 插件 | 0.7.x ~ 0.8.x | flannel、bridge、host-local、portmap 四个必需 |
提示:版本对照不是硬门槛,高于 1.16 也能跑,但每高一档,kubelet 的 CNI 相关参数就少一个,装之前先用
kubelet --help | grep -i cni看当前二进制还认哪些开关,比事后翻日志快得多。
2.2 宿主内核与模块:vxlan 不是装上就有的
vxlan 后端依赖内核的vxlan模块,跨节点转发还依赖br_netfilter和nf_conntrack。精简过的 arm64 系统镜像(尤其是裁剪版根文件系统)经常把这些模块编成外部模块,开机不自动加载。装 flannel 之前,每台节点都跑一遍:
# 看内核版本,vxlan 需要 3.7 以上,生产建议 4.9+ uname -r # 检查三个关键模块是否已加载 lsmod | grep -E 'vxlan|br_netfilter|nf_conntrack' # 没加载就手动拉起来,并写成开机自动加载 modprobe vxlan modprobe br_netfilter cat >/etc/modules-load.d/flannel.conf <<'EOF' vxlan br_netfilter nf_conntrack EOF模块之外还有两个 sysctl,net.bridge.bridge-nf-call-iptables决定二层桥接流量会不会过 iptables,net.ipv4.ip_forward决定本机能不能转发。这两个值不打开,最典型的症状是「同节点 Pod 互通、跨节点全丢」,ping 得通 Node IP 但 ping 不通对端 Pod IP。
cat >/etc/sysctl.d/99-flannel.conf <<'EOF' net.bridge.bridge-nf-call-iptables = 1 net.bridge.bridge-nf-call-ip6tables = 1 net.ipv4.ip_forward = 1 EOF sysctl --systemsysctl --system会重新加载所有配置文件,改完立刻生效,不用重启。写完用sysctl net.ipv4.ip_forward回读一遍,返回 1 才算数。这几步没做,后面 Pod 网络「看着起来了实际不通」的概率非常高。
2.3 网卡、网段、MTU:三条命令先摸清底
flannel 启动时要选一张网卡作为节点间通信的出口,默认策略是「找默认路由对应的那张」,多网口机器上这个默认值经常是错的那张。装之前先摸清三件事:
# 1. 列出所有 IPv4 地址,确认哪张是内网互联口 ip -4 addr show # 2. 看默认路由从哪张网卡出去 ip route show default # 3. 看这张网卡的 MTU,vxlan 要在它基础上减 50 ip link show eth0 | grep mtuMTU 这一项最容易被忽略。物理网卡 1500 的话,vxlan 封装后可用 MTU 只剩 1450,flannel 会自动把flannel.1设成 1450,但如果你上层还有一层隧道,或者业务里有不分片的大包,就会出现「小包通、大包卡死」的玄学现象。我的习惯是先把实际 MTU 记下来,后面配 backend 时按物理 MTU - 50反推。
网段方面,Pod CIDR 不能和这三类地址重叠:宿主物理网段、docker0 默认的172.17.0.0/16、Service CIDR。三者撞任意一个,kube-proxy 的规则和 flannel 的路由就会互相打架,表现是「部分节点通、部分节点不通」,查起来极其费劲。
3. 解包落盘:flanneld 与 CNI 插件分两个目录放
这份 arm64 包里的东西不多,tar -tzf一看就清楚:主要是flanneld主程序和mk-docker-opts.sh辅助脚本。真正让 Pod 起网的那批 CNI 插件(flannel、bridge、host-local、portmap)不在包里,它们是跟着 DaemonSet 的 initContainer 从镜像里拷出来的。所以安装动作天然分成两段:宿主机上落flanneld,节点上由 DaemonSet 落 CNI 插件。把这两段混成一件事,就会出现第 1 章开头那个报错。
3.1 校验包内容:先确认 aarch64 再解压
拿到包的第一步不是解压,是确认架构和完整性。arm64 和 amd64 的包名只差一个后缀,传错文件的情况在跨团队交付里非常常见,而错的结果是exec format error这种一眼看不出根因的报错。
# 看包内文件清单,确认是 flanneld 而不是别的 tar -tzf flannel-v0.11.0-linux-arm64.tar.gz # 校验完整性(有官方 sha256 就对比,没有就记录本地的) sha256sum flannel-v0.11.0-linux-arm64.tar.gz # 解压到临时目录 mkdir -p /tmp/flannel-v0.11.0 tar -xzf flannel-v0.11.0-linux-arm64.tar.gz -C /tmp/flannel-v0.11.0 # 关键一步:确认二进制是 aarch64 而不是 x86_64 file /tmp/flannel-v0.11.0/flanneldfile命令的输出必须是ELF 64-bit LSB executable, ARM aarch64。如果显示x86-64,说明包拿错了,后面所有步骤都不用做,先换包。这个检查花三秒钟,能省掉半小时的exec format error排查。
3.2 安装 flanneld 与 systemd 单元(可选路径)
如果你的集群是 DaemonSet 方式跑 flannel(官方清单就是这种),宿主机上其实不需要flanneld常驻,二进制放着当排障工具用即可。但有些老架构或者特殊场景会走「宿主机 systemd 起 flanneld + docker 走mk-docker-opts.sh」的路子,那就要正经安装:
# 落到标准路径,权限 0755 install -m 0755 /tmp/flannel-v0.11.0/flanneld /usr/local/bin/flanneld install -m 0755 /tmp/flannel-v0.11.0/mk-docker-opts.sh /usr/local/bin/mk-docker-opts.sh # 验证能跑起来 /usr/local/bin/flanneld --versioninstall -m 0755等价于cp加chmod,一步到位,比分开写两条命令干净。--version能打出版本号,说明动态链接库依赖齐全,arm64 上常见的not found类错误在这一步就能暴露。
如果是 systemd 托管模式,单元文件长这样:
[Unit] Description=Flanneld After=network.target [Service] ExecStart=/usr/local/bin/flanneld \ --etcd-endpoints=http://127.0.0.1:2379 \ --iface=eth0 \ --ip-masq Restart=always RestartSec=5 [Install] WantedBy=multi-user.target--iface指定节点通信网卡,多网口机器上必须显式写,不写就走默认路由那张,选错了就是跨节点不通。--ip-masq给 Pod 出集群的流量做源地址伪装,配合后面的 kube-subnet-mgr 使用。Restart=always加 5 秒间隔,保证进程异常退出后能自愈,运维上比手工拉起可靠。
3.3 补齐 CNI 插件:tar 包里没有的那一半
这是整个安装里最容易漏的一环。/opt/cni/bin目录下必须有四个可执行文件:flannel、bridge、host-local、portmap。前三个负责把 Pod 接进网桥并分配 IP,portmap负责 hostPort 映射。缺任何一个,kubelet 调用 CNI 时都会报failed to find plugin。
DaemonSet 方式的补齐动作由 initContainer 完成,逻辑是「从镜像里把插件拷到宿主机的/opt/cni/bin」。手工验证时可以预先看一眼目录:
# 看现有插件 ls -l /opt/cni/bin/ # 目录不存在就建,权限必须是 0755 mkdir -p /opt/cni/bin /etc/cni/net.d chmod 0755 /opt/cni/bin/etc/cni/net.d是 CNI 配置目录,flannel 会在里面写10-flannel.conflist。这个目录里如果还残留着别的 CNI 配置(比如之前装过 calico 或 cilium),kubelet 会按文件名字典序取第一个,取错了就整条网络栈跑偏。装之前ls /etc/cni/net.d/看一眼,有旧文件先移走,这是血泪经验。
4. 改 kube-flannel.yml:arm64 镜像、Pod 网段、backend 三处必改
官方清单直接kubectl apply在 arm64 上一定失败,原因集中在三处:镜像 tag 没有 arm64 后缀、net-conf.json里的网段和集群实际网段对不上、backend 类型没按网络环境选。这一章按改动顺序走一遍,每一处都给出改法和判断依据。
4.1 先把官方清单拆开看:五个对象各管什么
v0.11.0 的清单里包含五类对象,改之前先知道谁管什么,不然改错地方白费功夫:
| 对象 | 名称 | 作用 |
|---|---|---|
| Namespace | kube-flannel | 隔离 flannel 自身资源 |
| ServiceAccount + RBAC | flannel | 让 Pod 能读 Node 的 podCIDR 注解 |
| ConfigMap | kube-flannel-cfg | 存net-conf.json和cni-conf.json |
| DaemonSet | kube-flannel-ds | 每个节点跑一个 flanneld |
| initContainer | install-cni | 把 CNI 插件和 conflist 拷到宿主机 |
RBAC 部分是最容易被「精简清单」的人删掉的。删了以后 flanneld 拿不到 Node 的spec.podCIDR,日志里反复出现failed to acquire lease,Pod 永远起不来。改清单时这一段原样保留。
ConfigMap 里的cni-conf.json决定宿主机上生成什么配置文件,内容是:
{ "name": "cbr0", "cniVersion": "0.3.1", "plugins": [ { "type": "flannel", "delegate": { "hairpinMode": true, "isDefaultGateway": true } }, { "type": "portmap", "capabilities": {"portMappings": true} } ] }type: flannel让 CNI 调用 flannel 插件,插件再 delegate 给 bridge 和 host-local 完成实际配置。hairpinMode: true允许 Pod 访问自身的 Service,不开的话服务发现会出诡异问题。isDefaultGateway: true把网桥设成 Pod 的默认网关。
4.2 镜像地址替换与私有仓库拉取凭据
官方镜像在多架构支持上不是每个 tag 都全。v0.11.0 时期 arm64 的常见做法是找带-arm64后缀的 tag,找不到就在 amd64 机器上docker buildx自己构建一份推到私有仓库。清单里两处镜像都要改:initContainer 和主容器。
containers: - name: kube-flannel image: registry.internal/flannel/flannel:v0.11.0-arm64 imagePullPolicy: IfNotPresent command: ["/opt/bin/flanneld"] args: - --ip-masq - --kube-subnet-mgr - --iface=eth0--kube-subnet-mgr告诉 flanneld 从 apiserver 的 Node 对象读子网信息,不再依赖 etcd,这是 v0.11.0 推荐的方式。--iface=eth0显式指定出口网卡,多网口机器上必加。--ip-masq给出集群流量做 SNAT,集群要访问外部服务就得开。
私有仓库需要凭据的话,在 DaemonSet 的spec.template.spec下加:
imagePullSecrets: - name: regcred凭据本身用kubectl create secret docker-registry regcred --docker-server=... --docker-username=... --docker-password=...在kube-flannel命名空间里建。注意命名空间别建错,建在 default 里 DaemonSet 是读不到的,这个坑我踩过。
4.3 net-conf.json 的三个字段决定成败
net-conf.json是 flannel 的行为总开关,只有三个关键字段:
{ "Network": "10.244.0.0/16", "Backend": { "Type": "vxlan", "Port": 8472 } }Network必须和 kube-controller-manager 启动参数里的--cluster-cidr完全一致。不一致的后果是 Node 对象上分配的podCIDR落在 flannel 网段之外,flanneld 读到后直接报failed to acquire lease。改之前先确认:
# 看 controller-manager 的实际参数 ps -ef | grep kube-controller-manager | grep -o 'cluster-cidr=[^ ]*' # 或者直接看 Node 上分配到的 podCIDR kubectl get node <节点名> -o jsonpath='{.spec.podCIDR}'两个值对不上就改Network,别去改 controller-manager,改后者要重启控制面,风险大得多。
Backend.Type决定封装方式,Port是 vxlan 的 UDP 端口,默认 8472。这个端口要在所有节点的安全组或防火墙里放行,只放 TCP 不放 UDP 是最常见的疏漏。
4.4 backend 怎么选:vxlan、host-gw、udp 的取舍表
v0.11.0 支持三种后端,选型看网络拓扑:
| 类型 | 原理 | 适用场景 | 代价 |
|---|---|---|---|
| vxlan | 三层封装,跨网段可用 | 节点跨子网、云上混合部署 | MTU 减 50,有封装开销 |
| host-gw | 直接写主机路由,无封装 | 所有节点同一二层网段 | 不能跨网段 |
| udp | 用户态封装 | 调试、极端兼容场景 | 性能最差,生产不推荐 |
同一二层网段内优先host-gw,省掉封装开销,性能接近裸网。跨网段就只能vxlan。udp只在排查时临时用,用来区分「是封装问题还是路由问题」:换成 udp 能通、vxlan 不通,问题多半在 MTU 或防火墙。
改完清单,apply 之前先kubectl apply --dry-run=client -f kube-flannel.yml过一遍语法,能挡掉大半 YAML 缩进错误。
5. 避坑与排查:flannel v0.11.0 在 arm64 上最容易翻的五处
这一章的五条,是我在 arm64 环境上真真切切撞过的,按出现频率排序。每条按「现象 → 原因 → 解决」写,照着对照能省下大量翻日志的时间。
5.1 Pod 卡 ContainerCreating,报 failed to find plugin "flannel"
现象:节点 Ready,DaemonSet 的 flannel Pod 也 Running,但业务 Pod 全部 ContainerCreating,describe里是failed to find plugin "flannel" in path [/opt/cni/bin]。
原因:initContainer 没把插件拷到宿主机,或者/opt/cni/bin目录权限不对、路径不对。arm64 上还有一种情况是镜像里的插件目录结构和清单里挂载的路径不一致。
解决:先登节点看目录,ls -l /opt/cni/bin/缺哪个补哪个。手工验证时可以临时从镜像里拷:
# 用一个临时容器把插件拷出来 docker run --rm -v /opt/cni/bin:/host/opt/cni/bin \ registry.internal/flannel/flannel:v0.11.0-arm64 \ cp -f /opt/cni/bin/* /host/opt/cni/bin/ # 权限必须是 0755,否则 kubelet 执行不了 chmod 0755 /opt/cni/bin/*拷完重启 kubelet,Pod 会自动重试建网。
5.2 镜像 CrashLoopBackOff,日志第一行是 exec format error
现象:flannel Pod 起不来,kubectl logs第一行就是exec format error,后面全是退出码。
原因:镜像 tag 看着是 arm64,实际 manifest 里是 amd64 的层。多架构镜像的 tag 和 manifest 内容不一致,在私有仓库重新打 tag 时特别容易发生。
解决:docker manifest inspect registry.internal/flannel/flannel:v0.11.0-arm64看架构字段,确认是arm64。不对就重新构建,构建时显式指定平台:
docker buildx build --platform linux/arm64 \ -t registry.internal/flannel/flannel:v0.11.0-arm64 --push .推完把节点上的旧镜像删掉再拉,imagePullPolicy: IfNotPresent会缓存旧层,不清理会一直用错的那份。
5.3 flanneld 反复重启,日志是 failed to acquire lease
现象:flanneld 日志刷Error registering network: failed to acquire lease: node "xxx" pod cidr not assigned。
原因:kube-controller-manager 没开--allocate-node-cidrs,或者开了但--cluster-cidr和net-conf.json的Network不一致。RBAC 被删也会导致同样的报错。
解决:先确认 Node 上有 podCIDR,kubectl get node <名> -o jsonpath='{.spec.podCIDR}',输出为空就是 controller-manager 的问题。再确认两边的网段字符串完全一致,包括掩码位数。RBAC 那条用kubectl auth can-i list nodes --as=system:serviceaccount:kube-flannel:flannel验证。
5.4 同节点 Pod 通,跨节点全丢,tcpdump 能看到包发出去没回来
现象:kubectl exec进 Pod ping 同节点的另一个 Pod 正常,ping 跨节点的 Pod 100% 丢包,节点之间互相 ping 正常。
原因:iptables的 FORWARD 链默认策略被设成了 DROP。docker 或某些安全基线脚本会把FORWARD策略改成 DROP,vxlan 流量跨节点转发时被拦下来。
解决:iptables -L FORWARD -n | head -1看策略,是 DROP 就改回 ACCEPT,或者确保 kube-proxy 的规则链在前面放行。
# 看当前策略 iptables -L FORWARD -n | head -3 # 临时放行(重启会失效,确认有效后再考虑持久化) iptables -P FORWARD ACCEPT改完立刻验证跨节点连通性,通了就说明判断正确。持久化交给防火墙管理工具,别手工iptables-save了事。
5.5 多网卡选错出口,vxlan 走了管理网导致跨节点超时
现象:节点有两张网卡,一张业务内网一张管理网,flannel 起来后 vxlan 接口有流量但对端收不到,跨节点超时。
原因:--iface没指定,flanneld 选了默认路由那张(往往是管理网),对端节点从另一张网卡回包,路径不对称。
解决:DaemonSet 的 args 里显式加--iface=<内网网卡名>,重启 DaemonSet。验证方法是看flannel.1的 FDB 表里对端 MAC 对应的 VTEP IP 是不是内网段:
# 看 vxlan 设备的对端表项 bridge fdb show dev flannel.1 # 看 vxlan 接口的本地地址 ip -d link show flannel.1对端 VTEP IP 应该是内网网段,如果是管理网段就说明选错了。
6. 验收:把 flannel 从"跑起来"验到"通得了"
装完不等于跑通。我的验收习惯是四步走,从控制面看到数据面,从本机看到跨节点,任何一步不过都不算完成。第一步看对象状态,第二步看节点注解,第三步看内核里的接口和路由,第四步真发流量。前三步是静态检查,第四步才是真相。
| 验收项 | 命令 | 期望结果 |
|---|---|---|
| DaemonSet 就绪 | kubectl -n kube-system get ds kube-flannel-ds | READY 数等于节点数 |
| 节点注解 | kubectl get node <名> -o yaml | grep flannel | 有 backend-type、backend-data、public-ip 三条 |
| vxlan 接口 | ip -d link show flannel.1 | 状态 UNKNOWN、MTU 1450、有 vxlan id |
| 路由表 | ip route | grep 10.244 | 每个对端节点子网指向 flannel.1 |
| CNI 配置 | cat /etc/cni/net.d/10-flannel.conflist | cniVersion 0.3.1,plugins 含 flannel |
节点注解那一步最能说明问题。flannel.alpha.coreos.com/backend-data里带着对端节点的 VTEP MAC 和 IP,这行存在说明 flanneld 已经和 apiserver 完成握手,把子网信息注册上去了。三条注解缺一条,都说明 flanneld 那侧有问题,这时候去看 Pod 日志比看网络更有效。
静态检查全过之后发真实流量。最直接的办法是起两个测试 Pod,故意调度到不同节点:
# 起一个带网络的测试 Pod,指定调度到某节点 kubectl run nettest --image=busybox --restart=Never \ --overrides='{"spec":{"nodeName":"node-02"}}' -- sleep 3600 # 在另一个节点的 Pod 里 ping 它 kubectl exec -it nettest -- ping -c 3 <对端Pod IP>ping 通了还不够,要验 MTU。用ping -s 1400 -M do发不分片的大包,能过说明 MTU 1450 的设置是对的;如果小包通、1400 字节的包不通,就是 MTU 没算对,多半上层还有一层封装没扣掉。
最后一招是在两端节点上同时抓包,tcpdump -i flannel.1 -n udp port 8472,看请求发出去、响应回得来。只有一端有包,问题在路径;两端都有包但应用层不通,问题在 iptables 或 conntrack。这一招能一眼定位是封装层还是转发层的问题,比翻 kubelet 日志快。
从那以后我每次装完 flannel,不管多急,都强制走一遍「注解 → 接口 → 路由 → 跨节点大包」这四步,一步不跳。很多当时的「玄学不通」,事后回看都是某一步没验就宣布完工。希望帮到你。
本文还有配套的精品资源,点击获取