多彩编程 多彩编程MZPH · CODE BLOG
ARTICLE DETAIL

文章详情

深耕前端与后端开发技术的一线实战笔记与踩坑复盘。

ARM64内网离线部署Kubernetes:flannel v0.11.0节点网络落地指南

ARM64内网离线部署Kubernetes:flannel v0.11.0节点网络落地指南 简介flannel v0.11.0是Kubernetes集群中常用的CNI网络插件之一本安装包面向使用ARM64架构Linux主机如树莓派、飞腾、鲲鹏等部署K8s环境的运维工程师与开发者。它通过维护集群级路由表和Overlay隧道为每个Pod分配独立IP并实现跨节点容器网络互通解决多主机容器间通信难题。压缩包体积仅8.03MB共包含3个文件flanneld主程序负责与kube-apiserver交互并下发路由规则README文档提供启动参数、日志调试和故障排查说明mk-docker-opts.sh脚本用于自动生成Docker接入flannel时的网络环境变量。目前已有453人学习或下载说明该版本在ARM64场景下具有实际应用参考价值。获取本包后不仅可以直接运行二进制快速部署flannel还能通过配套脚本理解Docker与flannel的集成方式并借助官方文档掌握配置细节与排错思路减少从源码编译和整理资料的时间投入。适合需要在ARM设备上落地K8s集群、或深入理解CNI实现原理的中高级技术人员。1. 还在用 flannel-v0.11.0-linux-arm64.tar.gz这包是内网 ARM 集群的节点网络救命稻草在 ARM64 节点的内网环境里做 Kubernetes 离线部署节点网络组件经常要手动分发。我拿到 flannel-v0.11.0-linux-arm64.tar.gz 的第一反应不是版本太老而是这包能救我的老集群。v0.11.0 正好停在 Kubernetes API 与 etcd 两种子网管理方式并存的过渡期很多线上集群的内核版本、CNI 目录结构、镜像仓库内容都是按这个时代锁死的不存在随便升到新版的条件。这个压缩包解决的是最朴素的问题没有外网、镜像仓库没有 arm64 的 flannel 镜像时怎么把 Overlay 网络跑起来。适合正在维护 ARM 集群、需要补齐节点网络或者打算在一批 ARM 板子上从零搭 K8s 的工程师。下面我不讲怎么追新只讲这个包怎么落地成可用网络以及 v0.11.0 在 ARM64 设备上最容易翻车的几个位置。2. 解包与落地先搞清楚包里是什么再决定怎么跑2.1 拿到 tar.gz 后先做四个确认离线包最怕的不是版本老而是包在转存过程中被改过、换过架构或者依赖的库对不上。我不会一上来就解压到 /opt/bin而是先做四件事看包结构、确认 ELF 架构、确认动态链接依赖、确认有没有附带 CNI 插件文件。tar -tzf flannel-v0.11.0-linux-arm64.tar.gz file flanneld ldd flanneld | head -20 find . -maxdepth 1 -type f -printf %f %s\n逻辑说明第一条命令列出包内所有文件确认是否有 flanneld 主程序、install.sh、README 和系统服务模板第二条命令检查 flanneld 是不是 ARM64 架构的 ELF 可执行文件正常输出会有一个ARM aarch64的字样如果显示 x86-64说明包的名字和内容不一致立刻停手第三条命令查看动态库依赖重点看 libc 版本老 tar.gz 里的静态编译并不常见一旦目标机器的 glibc 比编译环境旧就会报version GLIBC_2.XX not found第四条命令确认包内到底有没有 CNI 插件文件。参数说明tar -tzf只列出文件名不解压适合大包先摸底file和ldd是任何离线二进制落地前都该跑的基础体检。我遇到过包内 flanneld 是在 glibc 2.27 环境编译的目标机器还在 2.24结果怎么跑都报缺版本最后是换了一个静态编译的 flanneld 才解决。2.2 systemd 跑二进制还是容器跑 DaemonSet落地形态一般有两种把 flanneld 直接跑在宿主机上用 systemd 托管或者走容器化 DaemonSet 方式。在有内网镜像源的时候我优先 DaemonSet一个 yaml 就能把配置、RBAC、镜像拉起排障时看 Pod 日志也顺手。但绝大多数碰到这个 tar.gz 的场景恰恰是镜像源里没有对应 ARM 架构的 flannel 镜像这时候 systemd 方式反而是保底方案。部署形态适用场景核心依赖排障难度systemd 二进制内网无镜像源、节点内存紧张flanneld 二进制、kubeconfig、CNI 插件文件低日志直接 journalctlDaemonSet 容器有内网 registry 或外网可拉镜像镜像仓库有 arm64 镜像、RBAC、Pod CIDR中需要看 Pod 日志和容器网络我一般这样决策如果节点是 2G 内存的 ARM 板子DaemonSet 里多跑一个容器会挤占 Pod 配额systemd 方式更省如果是标准服务器两种都行但系统里已经有 containerd 的话用容器化方式能少纠结 glibc 版本问题。2.3 最小 systemd 启动配置与参数说明选 systemd 方式后最小服务文件可以这样写cat /etc/systemd/system/flanneld.service EOF [Unit] Descriptionflanneld network service Wantsnetwork-online.target Afternetwork-online.target [Service] ExecStart/opt/bin/flanneld \ --ifaceeth0 \ --ip-masq \ --kube-subnet-mgr \ --kubeconfig-file/etc/kubernetes/flannel.conf \ --public-ip192.168.6.21 Restarton-failure RestartSec5 EnvironmentFile/etc/kubernetes/flannel.env [Install] WantedBymulti-user.target EOF systemctl daemon-reload systemctl enable --now flanneld逻辑说明--ifaceeth0指定 flannel 绑定的物理网卡多网卡机器上必须显式指定否则 flannel 会自己挑选一个网卡经常选出管理网卡或 Docker 网桥隧道建起来但 Pod 之间就是不通--ip-masq让 flannel 替 Pod 网段做 SNATPod 访问外部网络时才不会因为没有回程路由而超时--kube-subnet-mgr表示子网分配走 Kubernetes API不从 etcd 读网络配置这是 v0.11.0 之后的主流用法--kubeconfig-file指定访问 apiserver 的凭证文件可以用 kubeadm 生成的 admin.conf 复制一份只读权限也够用--public-ip在多网卡或 NAT 场景下指定对端封装报文时用的源地址。参数说明我习惯把 VXLAN 端口和日志级别放进EnvironmentFile因为改端口不用动 service 文件。启动后立刻执行journalctl -u flanneld -f看到输出里有Subnet added的日志基本可以认为 flanneld 已经和 apiserver 打通了。3. net-conf.json 与后端选型VXLAN 还是 host-gw3.1 Network、SubnetLen 与 IPMasq 怎么配合v0.11.0 的 flanneld 在 kube-subnet-mgr 模式下网络配置存在名为 kube-flannel-config 的 ConfigMap 里内容是一份 net-conf.json。这个 JSON 决定了整个集群的 Pod 网段划分方式。{ Network: 10.244.0.0/16, SubnetLen: 24, SubnetMin: 10.244.1.0, SubnetMax: 10.244.200.0, Backend: { Type: vxlan, VNI: 1, Port: 8472 } }逻辑说明Network是集群内所有 Pod 的地址池每个节点从这个大网段里分走一个子网SubnetLen24表示每个节点拿一个 /24也就是约 252 个可用地址节点数少的实验室集群保持 24 就行SubnetMin和SubnetMax限定分配范围适合给预留网段留空间比如我经常把 10.244.0.0/24 留作服务或网关网段Backend.Type决定数据面怎么封装vxlan 是默认且最省心的选择。参数说明VNI1是 VXLAN 网络的标识同一台物理机上多个 VXLAN 网络需要不同 VNI 才不串包默认 1 够用Port8472是 flannel 自管的 UDP 端口刻意不用标准的 4789就是为了避免和数据中心里其他 VXLAN 冲突。这里有个容易忽略的点IPMasq顶层字段在这里没有出现因为我在 systemd 里已经用--ip-masq参数开启了两个位置其实都能开建议二选一避免重复设置。3.2 VXLAN 与 host-gw适合什么网络怎么探活选后端前先判断节点之间的网络形态如果节点都在同一个二层host-gw 性能最好只要跨网段、跨机房或者云环境里不支持自组路由协议老老实实用 vxlan。下面是 v0.11.0 时代最常对比的两个后端后端网络要求封包方式性能要点vxlan三层可达即可UDP 8472 封装中等需要放行 UDP 8472、内核 vxlan 模块host-gw二层直连修改主机路由表最好不能跨网段CNI 冲突风险小我一般先探活再选型。执行下面这条命令看内核能不能加载 vxlan 模块lsmod | grep vxlan modprobe vxlan ip link add vxlan-test type vxlan id 100 remote 192.168.6.22 dstport 8472 ip link del vxlan-test逻辑说明第一条命令确认 vxlan 模块已经在内核里第二条命令动态加载失败则说明内核裁剪过vxlan 后端不能用第三条命令用一条实际的 VXLAN 链路做最小联通测试能创建成功说明内核支持最后的删除命令把测试链路清理掉。如果内核不支持 vxlan再看节点间是不是二层可达是的话就改用 host-gw绕开内核模块依赖。参数说明id 100是测试用的 VNI和 flannel 的 VNI 不冲突即可remote填对端节点 IPdstport 8472保证和 flannel 的默认数据面端口一致否则测了等于白测。3.3 MTU 不是玄学overlay 网卡的成帧开销vxlan 后端下每个数据包外面会套一层 UDP/IP 头大约多出 50 字节。如果物理网卡 MTU 是 1500而 flannel 的 overlay 也宣称 1500那实际发出的帧会超过物理链路上限结果就是 Pod 到外部网络变慢、偶发超时日志里大量 fragment 重传。常见做法是把 Backend 里加上MTU: 1450也就是物理 MTU 减 50{ Network: 10.244.0.0/16, Backend: { Type: vxlan, VNI: 1, Port: 8472, MTU: 1450 } }逻辑说明MTU 减 50 是 VXLAN 封装的固定开销只适用于 underlay MTU 等于 1500 的场景。云环境里很多虚拟网卡的 MTU 本身就是 1450这时候 overlay 得设成 1400 甚至更小不然照样分片。参数说明改完 MTU 后flanneld 会重建 flannel.1 接口节点上现存 Pod 需要重启才能拿到新 MTU。验证方法是从 Pod 里向网关方向做大包 ping用类似ping -M do -s 1372 目标IP的方式逐步加大会看到临界点MTU 设对的情况下不会出现小包通、大包不通。4. 接入 Kubernetes 集群从解包到 Pod 互通4.1 flanneld 和 flannel CNI 插件是两个东西这是整个 ARM64 离线部署里最容易栽的坑。flanneld 是控制面程序负责分配子网、维护路由但它不直接给 Pod 建网络命名空间。真正被 kubelet 调用的是/opt/cni/bin/flannel这个 CNI 插件可执行文件。它读 flanneld 写出来的/run/flannel/subnet.env再去创建 veth 对和 bridge。手头这个 tar.gz 按惯例只装 flanneld 和安装脚本CNI 插件经常是独立发布的产物。拿到包先按 2.1 的方法确认如果没有 CNI 插件文件就得从 CNI 插件构建物里单独解一个。把插件放到位mkdir -p /opt/cni/bin /etc/cni/net.d cp flannel /opt/cni/bin/flannel chmod x /opt/cni/bin/flannel cat /etc/cni/net.d/10-flannel.conflist EOF { name: cbr0, type: flannel, delegate: { isDefaultGateway: true } } EOF逻辑说明CNI 插件文件必须放在 kubelet 的--cni-bin-dir指向的目录里默认就是/opt/cni/bin配置文件放在/etc/cni/net.dkubelet 按文件名顺序读取第一个配置文件。flannel 的 CNI 配置写得很简短因为网段、MTU 这些信息都从 subnet.env 里自动读取。参数说明delegate.isDefaultGateway是让 flannel 给 Pod 里的容器网卡配置默认网关指向宿主机的 cni0 bridge。如果没有这个 flannel 插件kubelet 起 Pod 时会报failed to find plugin flannel和 flanneld 是否健康完全无关别在错误的方向上排查。4.2 用 DaemonSet 方式接入集群的最小步骤有内网镜像源时DaemonSet 方式还是最顺手的。v0.11.0 对应的 manifest 核心是一个 ConfigMap 加一个 DaemonSetDaemonSet 里的 Pod 使用hostNetwork: true所以它启动不依赖 CNI天然适合做网络组件。grep -n 10.244.0.0/16 kube-flannel.yml sed -i s#10.244.0.0/16#10.88.0.0/16#g kube-flannel.yml kubectl apply -f kube-flannel.yml kubectl -n kube-flannel rollout status ds/flannel逻辑说明第一行确认 manifest 里的默认 Pod 网段第二行把它替换成和kubeadm init --pod-network-cidr一致的网段。如果两边不一致kubelet 校验 Pod CIDR 时会把 flannel 的网段判定为非法所有节点都无法分配子网。参数说明替换网段用sed时注意#作为分隔符避免和地址里的斜杠冲突。rollout status命令会等到所有节点上的 flannel Pod 进入 Ready如果卡住先kubectl get pods -n kube-flannel -o wide看哪个节点没起来再去看对应节点的 kubelet 日志通常问题出在 RBAC 或镜像拉取。4.3 高版本集群上的兼容性注意点v0.11.0 的 flanneld 依赖的 Kubernetes API 在老版本上完全正常但新集群上要留个心眼。常见做法是先给 flannel 的 ServiceAccount 绑定一个够用的 ClusterRole确认 flanneld 能读 Node、Event 和 Lease 资源。如果 flannel 日志里出现资源版本冲突或者 Forbidden 字样优先检查 RBAC 而不是怀疑网络。另一个要注意的是节点注册信息。flanneld 在 kube-subnet-mgr 模式下会读取 Node 对象的 PodCIDR 字段如果集群创建节点时没有给 Node 分配 PodCIDRflanneld 会一直等。遇到这种情况看 apiserver 的日志确认 ControllerManager 是否正常给 Node 补 PodCIDR。我用 systemd 方式接入时还会把 flanneld 的--kubeconfig-file权限单独收敛成一个只读 ServiceAccount 的 token 文件而不是直接丢 admin.conf 给所有节点。这个习惯能避免后续排查 Kubernetes 审计日志时满屏都是 flanneld 在用一个高权限凭证。5. 避坑ARM64 老版本 flannel 的五个常见翻车位5.1 跨节点 Pod 不通先放行 UDP 8472现象同一节点上的 Pod 互相通跨节点 ping 不通每台机器的 flannel.1 接口和路由表都正常。原因vxlan 后端用 UDP 8472 封装节点防火墙默认 drop 了这个端口封装包发出去对端不处理也不回包。解决ss -ulnp | grep 8472 firewall-cmd --permanent --add-port8472/udp firewall-cmd --reload第一行确认 flanneld 确实在监听 8472第二行放行端口。云环境的话还要去安全组把节点的 UDP 8472 加上。如果你用的是 host-gw 后端则没有端口要放但要求节点二层互通。5.2 镜像 exec format errorARM64 镜像标签不可信现象容器化部署时镜像能拉下来但 Pod 启动马上报exec format error。原因镜像仓库里那个 tag 其实是 amd64 的镜像只是把 tag 命名成了带 arm64 后缀的名字或者拉取端 docker/containerd 在多架构 manifest 中选中了错误架构。解决用docker manifest inspect核实目标镜像确认里面确实有linux/arm64的入口。如果仓库不支持 manifest 查询就从另一台正常的 ARM 设备上docker save这个镜像再推到内网 registry。docker manifest inspect 镜像地址:tag | grep -i architecture参数说明输出里能看到一串架构列表必须出现arm64否则换镜像源或者放弃容器化方式改回 systemd 二进制。5.3 MTU 改错后 Pod 访问外部网络变慢现象Pod 之间通信正常但 Pod 访问外部服务时 curl 经常超时重试传大文件一半中断。原因overlay MTU 大于物理链路实际 MTU数据包被层层分片安全组或中间设备丢弃分片包表现就是小包通、大包断。解决先确认物理网卡 MTU再按 3.3 的方式把 net-conf.json 里的 MTU 调小重启 flanneld 和所有 Pod。5.4 etcd 模式下的 subnet 残留占用现象flanneld 重启后日志报subnet is already in use节点一直拿不到子网。原因网络配置走 etcd 存储时旧 flanneld 非正常退出lease 没有释放etcd 里保留了对应节点的 subnet 记录。解决用 etcdctl 查看并清理残留 key前提是先确认旧节点已经不在集群里etcdctl --endpointshttp://127.0.0.1:2379 get /coreos.com/network --prefix etcdctl --endpointshttp://127.0.0.1:2379 del /coreos.com/network/subnets/10.244.1.0-24注意v0.11.0 之后的新部署我都推荐直接走 kube-subnet-mgr 模式让子网记录由 Kubernetes API 管理这类残留问题基本就没了。5.5 vxlan 内核模块缺失与加载验证现象flanneld 启动即退出日志里报和 vxlan 设备创建相关的错误某些精简内核的 ARM 板子尤其常见。原因内核没有编入 or 没有加载 vxlan 模块ip link创建 vxlan 接口失败。解决lsmod | grep vxlan modprobe vxlan echo vxlan /etc/modules-load.d/vxlan.conf如果modprobe提示模块不存在说明内核镜像本身没带需要换内核或者改用 host-gw 后端。这条我放在最后是因为它最容易误判——很多人以为是网络配置问题把 net-conf.json 改来改去实际内核里压根没有这个模块。6. 验证与排障技巧半小时定位 flannel 网络问题网络类问题最怕在错误层排查。我现在的习惯是拿到一台看起来异常的节点先跑三个检查ip a show flannel.1、ip route | grep Pod网段、cat /run/flannel/subnet.env。三样都正常再往数据面深处看。ip a show flannel.1 ip route | grep 10.244 cat /run/flannel/subnet.env逻辑说明第一行确认 flannel.1 接口的 MAC 和 MTU 是预期值MTU 不对会导致大包问题第二行确认路由表里有没有指向 flannel.1 的 /24 路由每台节点应该只有自己子网的一条直连路由和通过其他节点学习到的路由第三行确认 flanneld 写入的本地子网和 MTU 配置CNI 插件就是靠这个文件创建 cni0 和 veth。跨节点不通时在接收端节点抓包看封装是否到达tcpdump -i eth0 udp port 8472 -nn -c 20 tcpdump -i flannel.1 icmp -nn -c 20第一条看物理网卡上有没有来自对端节点的 UDP 8472 包没有说明发送端封装有问题回去查路由表和--iface参数有包但第二条在 flannel.1 上抓不到 ICMP问题在 vxlan 解封装或内核转发检查 vxlan 模块和系统net.ipv4.ip_forward是否开启。别忘了所有节点都要持久化打开 IP 转发写入/etc/sysctl.confecho net.ipv4.ip_forward1 /etc/sysctl.conf sysctl -p有次在 ARM 设备上排查了很久的跨节点通讯问题最后发现就是net.ipv4.ip_forward被系统镜像默认关着。flannel 只负责封装和路由表转发这件事它不替你开。这个坑踩过一次之后我把sysctl -p写进了所有节点的初始化脚本里。希望这篇笔记能帮你少走两步弯路。本文还有配套的精品资源点击获取
返回列表