K8s离线部署flannel镜像包全攻略:从拉取到导入避坑

发布时间:2026/10/11 13:13:09

K8s离线部署flannel镜像包全攻略:从拉取到导入避坑 简介这份资源面向正在搭建 Kubernetes 集群、需要为节点配置网络插件的运维与开发人员解决 k8s 安装过程中 flannel 网络组件镜像难以获取、离线环境拉取不便的问题。压缩包共 3 个文件以 2 个 tar 镜像包和 1 个 yaml 清单为主整体约 27.34MB其中 tar 文件用于导入 flannel 与 flannel-cni-plugin 的容器镜像yaml 文件则提供配套的部署清单方便直接应用到集群中完成网络初始化。资源覆盖 flannel-cni-plugin:v1.1.2 与 flannel:v0.21.5 两个关键组件版本适合单机实验、多节点部署以及内网离线安装等场景对刚接触 k8s 网络配置的初学者和需要快速复现环境的工程师都较为友好。目前已有 1613 人学习下载可作为搭建 flannel 网络时的镜像与清单参考帮助减少镜像查找与版本匹配的试错成本提升集群网络组件的部署效率。1. 离线装 k8s 时flannel 镜像为什么总在最后一公里翻车很多团队在机房内网部署 Kubernetes 时kubeadm init 一路顺畅结果节点状态卡在 NotReadykubectl describe node 里一行network plugin is not ready: cni config uninitialized直接把节奏打断。问题往往不在 kubelet也不在 kube-proxy而是 flannel 的镜像根本没进内网——外网能docker pull的镜像到了隔离环境就变成一串ImagePullBackOff。这篇笔记就围绕「安装 k8s 所需 flannel 必要镜像包」这件事把该拉哪些镜像、怎么导出成 tar 包、怎么在内网导入、版本怎么对齐、踩过哪些坑按可复现的顺序讲清楚。适合正在做离线集群交付、内网机房部署、或者被 CNI 插件卡住的运维和平台工程师。核心结论先放这flannel 不是单个镜像而是一组镜像加一份 CNI 配置漏掉任何一个节点都起不来。2. flannel 镜像清单到底要拉哪几个为什么不是一个flannel 在 Kubernetes 里落地时实际参与运行的组件不止一个容器。很多人以为docker pull flannel/flannel就够了结果导入内网后还是起不来。原因在于 flannel 的部署方式决定了它需要多个镜像协同负责分配网段和写入 etcd/kubernetes 的 flanneld 主进程、负责在节点上配置网桥和路由的 CNI 插件、以及某些部署模式下用到的辅助镜像。下面把清单和选型理由拆开讲。2.1 flannel 核心镜像与辅助镜像的分工flannel 的官方部署通常以 DaemonSet 形式跑在每个节点上容器里跑的是 flanneld它从 apiserver 或 etcd 读取集群网段配置然后调用 CNI 插件在宿主机上创建 flannel.1 网桥、veth pair 和路由规则。所以至少需要两类镜像flannel 主镜像提供 flanneld 二进制和启动脚本是 DaemonSet 里真正跑的容器。CNI 插件镜像提供 bridge、host-local、flannel 等 CNI 二进制kubelet 在创建 Pod 沙箱时会调用它们。很多离线包只导了主镜像忘了 CNI 插件结果 kubelet 报failed to find plugin flannel in path [/opt/cni/bin]。如果集群用的是较新的 flannel 版本主镜像里可能已经内置了部分 CNI 插件但为了兼容不同 kubelet 版本和不同部署方式稳妥做法是把 CNI 插件单独准备一份。另外如果集群启用了 NetworkPolicy 或者用了 flannel 的 host-gw 模式可能还需要额外的辅助镜像但绝大多数场景下主镜像加 CNI 插件镜像就能覆盖。常见做法是先确定 flannel 版本再根据版本去拉对应的主镜像和 CNI 插件镜像。版本对齐是后面避坑章节的重点这里先记住一个原则——flannel 版本、CNI 插件版本、kubelet 版本三者要能互相兼容不能随便混搭。2.2 用 docker pull 拉取 flannel 镜像的完整命令假设你已经在一台能访问外网的机器上准备把镜像导出成 tar 包。第一步是拉取。下面这组命令覆盖了主镜像和 CNI 插件镜像版本号用变量统一管理方便后面替换。# 定义版本变量方便统一替换 FLANNEL_VERSIONv0.24.2 CNI_PLUGIN_VERSIONv1.4.0 # 拉取 flannel 主镜像 docker pull flannel/flannel:${FLANNEL_VERSION} # 拉取 CNI 插件镜像包含 bridge、host-local、flannel 等二进制 docker pull flannel/flannel-cni-plugin:${CNI_PLUGIN_VERSION} # 查看已拉取的镜像确认 tag 和 IMAGE ID docker images | grep -E flannel|flannel-cni逻辑说明FLANNEL_VERSION和CNI_PLUGIN_VERSION是两个独立变量因为 flannel 主镜像和 CNI 插件镜像的版本号并不总是同步发布。参数说明docker pull后面跟的是仓库名:标签标签不写默认是 latest但生产环境绝对不要用 latest否则内网导入后无法追溯版本。docker images用来确认镜像已经落地重点看 IMAGE ID 和 SIZE后面导出时会用到。如果外网机器是 arm64 架构而内网节点是 amd64这里就会埋下架构不匹配的坑。拉取时可以用--platform指定架构例如docker pull --platform linux/amd64 flannel/flannel:${FLANNEL_VERSION}。这一步不做后面导入内网后容器会报exec format error排查起来很费时间。2.3 镜像导出为 tar 包docker save 的参数与命名规范镜像拉下来之后下一步是导出成 tar 包方便拷贝进内网。导出命令本身简单但命名和分批策略有讲究。# 创建导出目录 mkdir -p /opt/k8s-offline/flannel # 导出 flannel 主镜像 docker save -o /opt/k8s-offline/flannel/flannel-${FLANNEL_VERSION}.tar \ flannel/flannel:${FLANNEL_VERSION} # 导出 CNI 插件镜像 docker save -o /opt/k8s-offline/flannel/flannel-cni-plugin-${CNI_PLUGIN_VERSION}.tar \ flannel/flannel-cni-plugin:${CNI_PLUGIN_VERSION} # 确认 tar 包大小和数量 ls -lh /opt/k8s-offline/flannel/逻辑说明docker save -o把镜像导出成 tar 文件-o后面是输出路径。参数说明文件名里带上版本号是为了在内网导入时一眼能看出对应关系避免多个版本混在一起。ls -lh用来确认文件大小flannel 主镜像通常在几十 MB 到一百多 MB 之间CNI 插件镜像更小如果发现某个 tar 包只有几 KB大概率是导出失败或者镜像没拉全。这里有个容易忽略的点docker save默认导出的是镜像的所有层如果镜像层很多tar 包会比较大。可以用docker save配合gzip压缩例如docker save flannel/flannel:${FLANNEL_VERSION} | gzip flannel.tar.gz内网导入时用docker load -i flannel.tar.gz也能识别。但压缩包在传输过程中如果损坏排查起来比 tar 包麻烦所以内网拷贝建议用 tar 包加校验和的方式。3. 内网导入与版本对齐让 flannel 在隔离环境跑起来镜像包拷进内网只是第一步真正决定 flannel 能不能跑起来的是导入后的 tag 是否正确、版本是否和 kubelet 兼容、CNI 配置是否落到了正确路径。这一章按导入、校验、配置三个环节展开每一步都有可复现的命令和检查点。3.1 docker load 导入镜像并校验 tag内网机器拿到 tar 包后用docker load导入。导入完成后必须校验 tag因为docker save导出的镜像如果原本没有 tag导入后可能变成none导致 DaemonSet 拉不到镜像。# 导入 flannel 主镜像 docker load -i /opt/k8s-offline/flannel/flannel-v0.24.2.tar # 导入 CNI 插件镜像 docker load -i /opt/k8s-offline/flannel/flannel-cni-plugin-v1.4.0.tar # 校验导入结果确认 REPOSITORY 和 TAG 都存在 docker images | grep flannel # 如果发现 tag 是 none手动补 tag # docker tag IMAGE_ID flannel/flannel:v0.24.2逻辑说明docker load -i从 tar 包导入镜像导入后镜像的 REPOSITORY 和 TAG 取决于导出时的状态。参数说明docker images | grep flannel用来确认导入结果重点看 REPOSITORY 是不是flannel/flannelTAG 是不是v0.24.2。如果 TAG 显示none说明导出时镜像没有正确 tag需要用docker tag手动补上否则 DaemonSet 的 image 字段匹配不到。校验通过后还要确认镜像架构和内网节点一致。可以用docker inspect查看镜像的 Architecture 字段docker inspect flannel/flannel:v0.24.2 | grep -i architecture如果输出是amd64而节点是 arm64或者反过来就需要重新拉取对应架构的镜像。这一步在混合架构集群里尤其重要很多团队在内网导入后才发现架构不对又得重新走一遍导出流程。3.2 flannel 版本与 kubelet、CNI 插件的兼容性对照版本对齐是 flannel 离线部署里最容易翻车的地方。flannel 版本太老可能不支持新版 kubelet 的 CNI 接口CNI 插件版本太新可能和 flannel 主镜像里的 flanneld 不兼容。下面这张表是常见组合的对照关系实际选型时以官方 release note 为准这里给的是经验值。flannel 版本推荐 CNI 插件版本兼容 kubelet 范围备注v0.24.xv1.4.x1.24 - 1.28支持 host-gw 和 vxlanv0.23.xv1.3.x1.22 - 1.26较稳定适合老集群v0.22.xv1.2.x1.20 - 1.24部分新特性缺失v0.21.xv1.1.x1.19 - 1.23不建议用于新集群选型理由如果集群是新建的kubelet 版本在 1.24 以上优先选 flannel v0.24.x 配 CNI 插件 v1.4.x这个组合对 NetworkPolicy 和双栈的支持更完整。如果是存量集群升级kubelet 版本较老就按表里对应的范围选不要强行上新版本。参数说明kubelet 范围是经验值实际以 flannel 官方文档的兼容性矩阵为准但离线环境里没法随时查文档所以提前把对照表存到本地很有必要。3.3 把 CNI 配置和二进制放到 kubelet 能找到的路径flannel 的 DaemonSet 跑起来后会在每个节点上写入 CNI 配置文件和二进制。但离线环境里CNI 二进制往往需要提前放到/opt/cni/bin配置文件放到/etc/cni/net.d否则 kubelet 创建 Pod 时会找不到插件。# 确认 CNI 二进制目录存在 mkdir -p /opt/cni/bin mkdir -p /etc/cni/net.d # 如果 CNI 插件镜像是通过容器方式提供的可以从容器里拷贝二进制 # 假设已经用 docker create 创建了临时容器 docker create --name cni-temp flannel/flannel-cni-plugin:v1.4.0 docker cp cni-temp:/flannel /opt/cni/bin/flannel docker cp cni-temp:/bridge /opt/cni/bin/bridge docker cp cni-temp:/host-local /opt/cni/bin/host-local docker rm cni-temp # 确认二进制权限 chmod x /opt/cni/bin/flannel /opt/cni/bin/bridge /opt/cni/bin/host-local ls -l /opt/cni/bin/逻辑说明docker create创建一个不启动的临时容器docker cp从容器里把 CNI 二进制拷到宿主机。参数说明/flannel、/bridge、/host-local是 CNI 插件镜像里二进制的常见路径不同版本可能略有差异可以用docker run --rm flannel/flannel-cni-plugin:v1.4.0 ls /先看一眼目录结构。chmod x确保二进制有执行权限否则 kubelet 调用时会报 permission denied。CNI 配置文件通常由 flannel DaemonSet 自动生成但离线环境里如果 DaemonSet 还没跑起来可以手动放一份最小配置到/etc/cni/net.d/10-flannel.conflist内容包含 flannel 和 portmap 两个插件。这一步不是必须的但能加快排查速度——当节点 NotReady 时先确认/etc/cni/net.d下有没有配置文件再看/opt/cni/bin下有没有对应二进制两个都齐了问题基本就缩小到 flanneld 和 apiserver 的通信上了。4. 避坑与排查flannel 离线部署最常见的 5 个翻车现场离线部署 flannel 的坑大多集中在镜像、版本、路径和网络四件事上。下面这 5 条是按实际排查频率排序的每条都按「现象 → 原因 → 解决」写方便对照。4.1 节点 NotReady报错 cni config uninitialized现象kubectl get nodes显示节点 NotReadykubectl describe node里 Events 出现network plugin is not ready: cni config uninitialized。原因kubelet 在/etc/cni/net.d下找不到任何 CNI 配置文件或者配置文件格式不对。离线环境里flannel DaemonSet 可能因为镜像拉不到还没跑起来自然没人写配置。解决先确认 flannel DaemonSet 的 Pod 状态kubectl get pods -n kube-flannel。如果 Pod 是 ImagePullBackOff回到第 3 章检查镜像导入和 tag。如果 Pod 已经 Running 但节点还是 NotReady手动检查/etc/cni/net.d下有没有10-flannel.conflist没有就手动放一份或者重启 kubelet 让它重新触发 CNI 配置写入。4.2 镜像导入后 tag 变成 noneDaemonSet 拉不到现象docker images里能看到 flannel 镜像但 REPOSITORY 和 TAG 都是noneDaemonSet 的 Pod 一直 ImagePullBackOff。原因docker save导出时镜像没有正确 tag或者导出的是中间层镜像。常见于用docker save直接跟 IMAGE ID 而不是仓库名:标签的情况。解决用docker tag IMAGE_ID flannel/flannel:v0.24.2手动补 tag然后确认 DaemonSet 的 image 字段和 tag 完全一致。注意大小写和冒号flannel/flannel:v0.24.2和flannel/flannel:V0.24.2是两个不同的 tag。4.3 架构不匹配容器报 exec format error现象Pod 状态是 CrashLoopBackOffkubectl logs里看到exec format error或者cannot execute binary file。原因外网拉取镜像的机器架构和内网节点架构不一致比如外网是 arm64 的开发机内网是 amd64 的服务器。解决在外网拉取时用docker pull --platform linux/amd64指定架构重新导出 tar 包。如果已经导入内网用docker inspect确认镜像 Architecture 字段不对就重新走一遍导出导入流程。混合架构集群里建议按架构分别准备镜像包不要混在一个 tar 里。4.4 flanneld 连不上 apiserver日志报 connection refused现象flannel Pod 是 Running但日志里反复出现Failed to create SubnetManager: error retrieving pod spec或者connection refused。原因flanneld 需要通过 apiserver 或 etcd 读取集群网段配置如果 kubeconfig 挂载不对、apiserver 地址写错、或者网络策略挡住了 flannel Pod 到 apiserver 的流量就会连不上。解决先确认 flannel DaemonSet 的 kubeconfig 挂载路径和内容kubectl exec进 Pod 用cat看/etc/kube-flannel/kubeconfig里的 server 地址是不是 apiserver 的真实地址。如果是 etcd 模式确认 etcd 端点可达。离线环境里还要注意flannel Pod 用的镜像里可能没有 curl 或 nc排查网络连通性时可以用kubectl run起一个临时 Pod 来测。4.5 网段冲突导致 Pod 之间 ping 不通现象节点都是 ReadyPod 也能创建但跨节点 Pod 互相 ping 不通或者 ping 通但丢包严重。原因flannel 默认用的网段和宿主机现有网络、其他集群网段、或者云厂商的 VPC 网段冲突。离线环境里机房网络规划往往和测试环境不一样很容易撞上网段。解决检查 flannel 的 ConfigMap 里Network字段默认是10.244.0.0/16确认这个网段和宿主机路由表、VPC 网段没有重叠。如果有冲突改成一个空闲网段然后重启 flannel DaemonSet。改网段后已经创建的 Pod 需要重建才能拿到新网段的 IP。5. 进阶技巧用校验和与版本锁把离线包做成可复用的交付物前面讲的是一次性部署的流程但如果团队经常要做离线交付每次都手动拉镜像、导出、导入迟早会出错。更稳的做法是把 flannel 离线包做成一个带校验和、带版本锁、带导入脚本的交付物下次直接复用。这一章讲三个具体技巧都是我在多次交付里攒下来的习惯。5.1 给每个 tar 包生成 sha256 校验和镜像包在拷贝和传输过程中可能损坏导入时报unexpected EOF或者invalid tar header排查起来很费时间。提前生成校验和导入前先校验能把问题挡在导入之前。# 在导出目录生成所有 tar 包的校验和 cd /opt/k8s-offline/flannel sha256sum *.tar SHA256SUMS # 内网导入前先校验 sha256sum -c SHA256SUMS逻辑说明sha256sum *.tar为每个 tar 包生成校验和并写入SHA256SUMS文件sha256sum -c会逐行校验并输出 OK 或 FAILED。参数说明-c表示 check 模式读取文件里的校验和和文件名进行比对。如果输出里有 FAILED说明对应的 tar 包在传输中损坏需要重新拷贝。这个习惯看起来简单但在跨机房拷贝几十 GB 镜像包的场景里能省下大量排查时间。我一般会把SHA256SUMS和 tar 包放在同一目录导入脚本里第一行就是校验校验不过直接退出。5.2 用版本锁文件固定 flannel 和 CNI 插件版本版本漂移是离线交付的另一个大坑。这次交付用的是 flannel v0.24.2下次有人拉了 v0.25.0镜像包混在一起导入后版本对不上排查起来很麻烦。解决办法是用一个版本锁文件把所有组件的版本写死。# versions.lock 文件内容示例 FLANNEL_VERSIONv0.24.2 CNI_PLUGIN_VERSIONv1.4.0 KUBELET_COMPAT1.24-1.28逻辑说明versions.lock是一个纯文本文件记录本次交付锁定的所有版本。导出脚本和导入脚本都从这个文件读取版本变量而不是在脚本里硬编码。参数说明KUBELET_COMPAT是备注字段记录兼容的 kubelet 范围方便后续查。每次交付前更新这个文件交付物和版本锁一起归档下次要复现或者升级直接看这个文件就知道当时用的什么版本。5.3 写一个导入脚本把 docker load 和 tag 校验串起来手动执行docker load和docker images校验步骤多了容易漏。写一个导入脚本把校验和、导入、tag 检查串起来能减少人为失误。#!/bin/bash set -e # 导入脚本先校验再导入最后检查 tag cd /opt/k8s-offline/flannel echo 校验 tar 包完整性... sha256sum -c SHA256SUMS echo 导入 flannel 主镜像... docker load -i flannel-${FLANNEL_VERSION}.tar echo 导入 CNI 插件镜像... docker load -i flannel-cni-plugin-${CNI_PLUGIN_VERSION}.tar echo 检查镜像 tag... docker images | grep -E flannel/flannel|flannel-cni-plugin echo 导入完成请确认上方 tag 与 versions.lock 一致逻辑说明set -e让脚本在任意命令失败时立即退出避免校验失败还继续导入。参数说明脚本里的${FLANNEL_VERSION}和${CNI_PLUGIN_VERSION}从versions.lock读取可以在脚本开头加一行source versions.lock。最后的docker images | grep是人工确认点脚本不自动判断 tag 对不对因为 tag 的期望值可能因环境而异留给人看一眼更稳妥。这个脚本我一般会放在离线包的根目录和SHA256SUMS、versions.lock、tar 包放在一起。内网机器上解压后直接bash import.sh校验、导入、检查一步到位。如果导入过程中报错脚本会停在出错的那一步不会继续往下跑排查时看最后一行输出就知道卡在哪。最后一个习惯每次交付完把这次用的镜像包、版本锁、校验和、导入脚本打成一个压缩包归档命名带上日期和集群标识。下次做类似交付时先翻归档能复用就复用不能复用就在旧包基础上改版本锁比重头拉镜像快得多。离线部署这件事拼的不是手速是能不能把一次性的操作变成可复用的流程。希望帮到你。本文还有配套的精品资源点击获取
延伸阅读

更多相关文章

2026/10/11 13:13:09

CSAPP实验1全攻略:工具链、链接加载与进程漫游避坑详解

简介:面向哈工大计算机专业学生的《计算机系统漫游》实验1配套资料包,聚焦课程入门实践,帮助初学者打通从二进制到系统调用的完整知识链。压缩包大小约969MB,内含实验指导文档、可运行代码样例及配套数据文件,目录按知…

2026/10/11 14:23:16

Flutter适配OpenHarmony的Container组件实战指南

1. 项目概述 大概从去年开始,我就在关注 Flutter 在 OpenHarmony 上的适配进展。之前很多团队还停留在“能跑起来”的阶段,页面稍微复杂一点就各种崩溃、布局错乱,尤其是想用基础组件的时候,经常发现行为跟标准 Flutter 不一致。所…

2026/10/11 14:23:16

城市运管服平台下综合办公数字化建设实践与思考

数字政府建设持续向纵深推进,城市运行管理服务平台作为城市治理 的重要载体,除城市事件处置、监测预警、指挥调度等核心业务之外,内部综合办公数字化建设,已经成为提升部门协同效率、规范内部业务流程、实现治理业务与内部管理双向…

2026/10/11 14:23:16

IBM-PC汇编课后习题答案详解:补码、寻址与标志位避坑指南

简介:《IBM-PC汇编语言程序设计》配套习题答案,主要为使用沈美明、温冬婵教材的计算机专业学生和自学者提供课后练习参考。文档按习题解答主线展开,覆盖数制转换、8位补码加减运算、位操作、ASCII码与字符串处理等基础知识点,并对…

2026/10/11 14:23:16

Flutter for OpenHarmony 中 Container 组件核心属性与实战避坑

做客户端开发这些年,我接触过不少跨端方案,Flutter 算是用得最多的一套。前阵子把一个内部工具项目的界面迁移到 OpenHarmony 设备,用的就是社区维护的 Flutter for OpenHarmony 分支。迁移过程中我有个很深的感受:真正让你在真机…

2026/10/11 14:18:16

SpringBoot3+EasyExcel实现复杂Excel一键导入实战指南

1. 项目背景与方案选型1.1 从POI直接操作说起做后端开发的,谁没被Excel导入导出折磨过?我早年用Apache POI直接写导入功能,代码量大不说,最痛苦的是内存。一个几万行的Excel解析下来,整个JVM堆吃紧,频繁Ful…

2026/10/11 0:02:13

Python调用Gemini Structured Outputs实现工单路由门禁

客服工单最怕的不是模型“答错一句话”,而是它给出一段看起来合理的说明,程序却从中猜错优先级。通俗做法是:要求模型只交 JSON(JavaScript Object Notation,轻量数据格式),再让代码验证它。Gem…

2026/10/11 0:02:13

Spring Boot超市进销存系统毕设实战:从需求拆解到答辩通关

最近带的一个学生项目组里,有A同学跑来问我:选什么毕设题目最稳妥,既能让评审老师觉得工作量够,又不会在答辩时被问到语无伦次。我第一反应就是推荐基于Spring Boot的超市仓库管理系统——也就是超市进销存系统。这个题目乍一看平…

2026/10/11 0:02:13

Flutter StatefulWidget 生命周期核心解析

很多刚开始接触 Flutter 的朋友,在看完一堆“Hello World”和基础组件之后,大概率都会撞上同一堵墙:StatefulWidget 里那堆 initState、build、dispose 方法,到底什么时候被调用?为什么顺序是那样?在里面到…

2026/10/11 0:02:13

Python调用Gemini Structured Outputs实现工单路由门禁

客服工单最怕的不是模型“答错一句话”,而是它给出一段看起来合理的说明,程序却从中猜错优先级。通俗做法是:要求模型只交 JSON(JavaScript Object Notation,轻量数据格式),再让代码验证它。Gem…

2026/10/11 0:02:13

Spring Boot超市进销存系统毕设实战:从需求拆解到答辩通关

最近带的一个学生项目组里,有A同学跑来问我:选什么毕设题目最稳妥,既能让评审老师觉得工作量够,又不会在答辩时被问到语无伦次。我第一反应就是推荐基于Spring Boot的超市仓库管理系统——也就是超市进销存系统。这个题目乍一看平…

2026/10/11 0:02:13

Flutter StatefulWidget 生命周期核心解析

很多刚开始接触 Flutter 的朋友,在看完一堆“Hello World”和基础组件之后,大概率都会撞上同一堵墙:StatefulWidget 里那堆 initState、build、dispose 方法,到底什么时候被调用?为什么顺序是那样?在里面到…

还想了解更多?直接咨询顾问

免费诊断 + 免费方案 + 透明报价。

全国咨询热线400-8866-253
免费获取方案
☎咨询二维码 ☎ ↑