K8s离线安装flannel镜像包全攻略:从打包到导入

发布时间:2026/10/13 4:59:47
K8s离线安装flannel镜像包全攻略:从打包到导入 简介这份资源面向正在搭建 Kubernetes 集群、需要为节点配置网络插件的运维与开发人员重点解决 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 镜像包到底卡在哪一步很多人在内网机房装 k8s卡住的地方不是 kubelet 配置也不是证书而是 flannel 的镜像拉不下来。控制节点kubeadm init跑完kubectl get nodes一直是 NotReadykubectl get pods -n kube-system里 flannel 那个 Pod 停在 ImagePullBackOff日志里翻来覆去就是dial tcp: i/o timeout或者no such host。这就是典型的「镜像包没备齐」——k8s 安装部署里最容易被低估的一环。flannel 本身是个 CNI 插件它需要的不只是一个flannel/flannel镜像还牵扯到flannel/flannel-cni-plugin以及初始化阶段 kubeadm 自己要用到的kube-apiserver、kube-controller-manager、kube-scheduler、kube-proxy、pause、etcd、coredns这一整套。标题说的是「安装 k8s 所需 flannel 必要镜像包」落到实操就是把 flannel 相关的镜像和 k8s 核心镜像一起打成 tar 包带到没有外网的环境里用docker load或ctr images import导进去让 flannel 能正常起 Pod节点从 NotReady 变 Ready。这篇写给两类人一是在内网、专线受限或纯离线环境里部署 k8s 的运维和平台工程师二是刚学 k8s、想在自己机器上用 containerd 或 docker 手动把 flannel 跑起来的新手。下面从镜像清单怎么定、tar 包怎么打、导进去怎么验证、踩过哪些坑一步步讲清楚。2. flannel 镜像包清单哪些必须打哪些可以省2.1 先分清 flannel 的两个镜像和 k8s 核心镜像flannel 从 v0.20 之后拆成了两个镜像一个是flannel/flannel跑 flanneld 主进程另一个是flannel/flannel-cni-plugin提供 CNI 二进制。很多人只拉了flannel/flannel结果 Pod 起来后 CNI 配置写不进去节点还是 NotReady。这两个必须一起备。k8s 核心镜像则由 kubeadm 决定。kubeadm config images list会列出当前版本需要的全部镜像包括registry.k8s.io/kube-apiserver、kube-controller-manager、kube-scheduler、kube-proxy、pause、etcd、coredns。这些镜像的 tag 跟你的 k8s 版本严格绑定比如 k8s 1.28 对应v1.28.xetcd 是3.5.9-0coredns 是v1.10.1。版本对不上kubeadm init 会直接报镜像缺失。flannel 的镜像 tag 则跟 k8s 版本无关跟 flannel 自己的 release 走。常见稳定版是v0.22.3、v0.23.0、v0.24.0。选哪个我一般看两点一是 flannel 官方 release notes 里对 k8s 版本的兼容说明二是你集群的 k8s 版本。k8s 1.24 以后移除了 dockershimflannel 的 CNI 插件版本要跟上否则 containerd 下会报failed to find plugin flannel in path。下面这张表是我在离线环境里常用的镜像清单按 k8s 1.28 flannel v0.23.0 举例镜像用途是否必须registry.k8s.io/kube-apiserver:v1.28.2控制面是registry.k8s.io/kube-controller-manager:v1.28.2控制面是registry.k8s.io/kube-scheduler:v1.28.2控制面是registry.k8s.io/kube-proxy:v1.28.2网络代理是registry.k8s.io/pause:3.9沙箱是registry.k8s.io/etcd:3.5.9-0存储是registry.k8s.io/coredns/coredns:v1.10.1DNS是flannel/flannel:v0.23.0flanneld是flannel/flannel-cni-plugin:v1.2.0CNI 插件是提示pause镜像的 tag 在不同 k8s 版本里可能是 3.6、3.7、3.9以kubeadm config images list输出为准不要凭记忆写。2.2 用 kubeadm 和 docker 两条命令把清单拉全在有外网的机器上先确认 kubeadm 版本再列镜像# 查看 kubeadm 版本确保和要部署的集群一致 kubeadm version -o short # 列出当前 kubeadm 需要的全部镜像 kubeadm config images list输出类似registry.k8s.io/kube-apiserver:v1.28.2 registry.k8s.io/kube-controller-manager:v1.28.2 registry.k8s.io/kube-scheduler:v1.28.2 registry.k8s.io/kube-proxy:v1.28.2 registry.k8s.io/pause:3.9 registry.k8s.io/etcd:3.5.9-0 registry.k8s.io/coredns/coredns:v1.10.1flannel 的两个镜像不在 kubeadm 列表里要单独拉# 拉取 flannel 主镜像和 CNI 插件镜像 docker pull flannel/flannel:v0.23.0 docker pull flannel/flannel-cni-plugin:v1.2.0逻辑说明kubeadm config images list只负责 k8s 自身组件flannel 作为第三方 CNI 必须手动补。参数上-o short让版本输出更干净方便脚本取值。如果你用的是 containerd 而不是 docker把docker pull换成ctr -n k8s.io images pull命名空间k8s.io不能省否则 kubelet 找不到镜像。拉完之后用docker images | grep -E flannel|kube|etcd|coredns|pause核对一遍确认 tag 和清单一致。这一步偷懒后面离线导入就会缺东少西。3. 把镜像打成 tar 包docker save 与 ctr 导入的实操3.1 docker save 打包的两种写法与体积控制镜像拉齐后用docker save打成 tar。可以一个镜像一个包也可以合并成一个包。合并包传输方便但单包过大时导入慢分镜像包灵活但文件多。我一般按「k8s 核心一个包 flannel 一个包」来分便于排查。# 把 k8s 核心镜像合并打成一个 tar 包 docker save -o k8s-core-images.tar \ registry.k8s.io/kube-apiserver:v1.28.2 \ registry.k8s.io/kube-controller-manager:v1.28.2 \ registry.k8s.io/kube-scheduler:v1.28.2 \ registry.k8s.io/kube-proxy:v1.28.2 \ registry.k8s.io/pause:3.9 \ registry.k8s.io/etcd:3.5.9-0 \ registry.k8s.io/coredns/coredns:v1.10.1 # flannel 两个镜像单独打一个包 docker save -o flannel-images.tar \ flannel/flannel:v0.23.0 \ flannel/flannel-cni-plugin:v1.2.0逻辑说明-o指定输出文件后面跟镜像全名含 registry 和 tag。合并打包时 docker 会把所有 layer 去重后写入所以总体积小于各镜像之和。参数上没有压缩选项tar 本身不压缩传输前可以gzip一下但导入前要gunzip回来因为docker load不认.tar.gz。打包完用ls -lh看体积k8s 核心包通常在 600MB 到 900MB 之间flannel 包在 100MB 左右。如果明显偏小说明镜像没拉全。3.2 离线端导入docker load 与 ctr images import 的差别离线机器上如果容器运行时是 docker直接# 导入 k8s 核心镜像 docker load -i k8s-core-images.tar # 导入 flannel 镜像 docker load -i flannel-images.tar # 核对导入结果 docker images | grep -E flannel|kube|etcd|coredns|pause如果运行时是 containerdk8s 1.24 以后默认docker load 导入的镜像在k8s.io命名空间里可能不可见要用ctr# 导入到 containerd 的 k8s.io 命名空间 ctr -n k8s.io images import k8s-core-images.tar ctr -n k8s.io images import flannel-images.tar # 列出确认 ctr -n k8s.io images ls | grep -E flannel|kube|etcd|coredns|pause逻辑说明-n k8s.io是关键kubelet 默认从k8s.io命名空间拉镜像导入到default命名空间等于白导。参数上ctr images import支持--all-platforms但离线环境一般只导当前架构不加也行。导入后如果ctr images ls能看到但 kubelet 还是拉不到检查/etc/containerd/config.toml里的sandbox_image是否指向了正确的 pause 镜像。注意docker 和 containerd 的镜像存储是两套docker load 进去的镜像不会自动出现在 containerd 里。先确认你的 kubelet 用的是哪个运行时再决定用哪条导入命令。4. flannel 镜像导入后 Pod 起不来的排查4.1 现象一ImagePullBackOff 但镜像明明导入了现象kubectl describe pod -n kube-system kube-flannel-ds-xxxxx显示Failed to pull image flannel/flannel:v0.23.0: ... not found但你ctr -n k8s.io images ls能看到这个镜像。原因flannel 的 DaemonSet yaml 里镜像地址可能带了 registry 前缀比如docker.io/flannel/flannel:v0.23.0而导入时用的是flannel/flannel:v0.23.0containerd 认为这是两个不同的引用。解决要么在导入时用完整地址docker.io/flannel/flannel:v0.23.0要么改 DaemonSet 里的image字段去掉docker.io/前缀。我一般统一用完整地址导入避免歧义。4.2 现象二Pod Running 但节点仍 NotReady现象flannel Pod 状态是 Runningkubectl get nodes还是 NotReadykubectl logs里 flannel 没报错。原因flannel 的 CNI 配置文件没写到/etc/cni/net.d/或者flannel-cni-plugin二进制没放到/opt/cni/bin/。flannel 容器启动时会做这个动作但如果宿主机目录挂载不对或者 CNI 插件镜像版本不匹配就会静默失败。解决进 flannel Pod 或直接在宿主机检查/etc/cni/net.d/10-flannel.conflist是否存在/opt/cni/bin/flannel是否有可执行权限。缺哪个补哪个然后重启 flannel Pod。4.3 现象三kubeadm init 报 the api server is not healthy after 4m0.00747357s现象控制节点初始化卡住最后报the api server is not healthy after 4m0.00747357sjournalctl -u kubelet里能看到failed to pull image registry.k8s.io/kube-apiserver。原因k8s 核心镜像没导入全或者导入到了错误的命名空间。kubelet 拉不到 apiserver 镜像静态 Pod 起不来健康检查自然超时。解决先ctr -n k8s.io images ls | grep kube-apiserver确认镜像在不在。不在就重新导入在的话检查 tag 是否和kubeadm config images list输出一致。版本差一个小版本都会导致拉取失败。4.4 现象四flannel 镜像导入后磁盘被撑爆现象导入几个 tar 包后/var/lib/containerd或/var/lib/docker占用暴涨节点磁盘告警。原因docker save 的 tar 包和导入后的镜像各占一份空间多个版本叠加更明显。flannel 和 k8s 核心镜像加起来接近 1GB如果反复导入不同版本旧镜像不会自动清理。解决导入前docker system df或ctr -n k8s.io images ls看现有镜像删掉不用的旧版本。导入后及时删除 tar 包。生产环境建议把镜像仓库搭在内网用 registry 而不是 tar 包分发长期看更省事。4.5 现象五flannel 版本和 k8s 版本不兼容现象flannel Pod 反复重启日志报Failed to create pod sandbox: ... failed to find plugin flannel in path。原因flannel v0.20 之前的版本不包含独立的 CNI 插件镜像或者插件版本和 containerd 的 CNI 配置不匹配。k8s 1.24 以后 containerd 默认配置对 CNI 插件路径有要求。解决升级 flannel 到 v0.22 以上确保flannel/flannel-cni-plugin镜像一起导入。检查/etc/containerd/config.toml里bin_dir是否指向/opt/cni/binconf_dir是否指向/etc/cni/net.d。5. 用 kubeadm 离线初始化的完整验证链路5.1 从导入镜像到节点 Ready 的最小验证命令镜像导入只是第一步要确认整条链路通按下面顺序走# 1. 确认 containerd 里镜像齐全 ctr -n k8s.io images ls | grep -E flannel|kube-apiserver|etcd|coredns|pause # 2. 初始化控制节点指定离线镜像仓库或跳过拉取 kubeadm init --pod-network-cidr10.244.0.0/16 --image-repositoryregistry.k8s.io # 3. 按提示配置 kubectl mkdir -p $HOME/.kube cp -i /etc/kubernetes/admin.conf $HOME/.kube/config chown $(id -u):$(id -g) $HOME/.kube/config # 4. 部署 flannel kubectl apply -f kube-flannel.yml # 5. 观察节点和 Pod 状态 kubectl get nodes -w kubectl get pods -n kube-system -w逻辑说明--pod-network-cidr必须和 flannel 的Network配置一致默认是10.244.0.0/16写错会导致 Pod 之间不通。--image-repository在离线环境里如果镜像已经导入本地kubelet 会优先用本地但显式指定可以避免它去外网拉。kubectl apply -f kube-flannel.yml里的 yaml 要从 flannel 官方 release 页面下载对应版本不要用旧版。验证标准kubectl get nodes显示 Readykubectl get pods -n kube-system里 flannel、coredns、kube-proxy 全部 Running。如果 coredns 一直 Pending通常是 flannel 没起或者网络 CIDR 冲突。5.2 验证 Pod 跨节点通信是否真的通了节点 Ready 不代表网络通。建两个测试 Pod 验证# 在 node1 上起一个 nginx kubectl run nginx-test --imagenginx --restartNever # 查看 Pod IP 和所在节点 kubectl get pod nginx-test -o wide # 在 node2 上起一个 busyboxping node1 的 Pod IP kubectl run busybox-test --imagebusybox --restartNever -- sleep 3600 kubectl exec -it busybox-test -- ping -c 3 nginx-test-pod-ip逻辑说明flannel 默认用 VXLAN 模式跨节点 Pod 通信走 overlay 网络。如果 ping 不通检查ip route里有没有 flannel.1 接口iptables -L -n里 FORWARD 链是否被 DROP。常见原因是宿主机防火墙没放行 VXLAN 的 8472/UDP 端口。提示测试完记得删掉测试 Podkubectl delete pod nginx-test busybox-test避免占用 IP 和资源。6. 把 flannel 镜像包做成可复用资产的两个技巧第一个技巧是给 tar 包加校验和版本清单。离线环境里 tar 包靠 U 盘或内网共享传递损坏是常事。我习惯在打包目录里生成一个manifest.txt记录每个 tar 包的 sha256 和包含的镜像列表# 生成校验和 sha256sum k8s-core-images.tar flannel-images.tar manifest.txt # 记录镜像清单 docker images --format {{.Repository}}:{{.Tag}} | grep -E flannel|kube|etcd|coredns|pause manifest.txt导入前先sha256sum -c manifest.txt校验不过就别导省得导到一半报错还得重来。这个习惯在多次跨机房交付时救过我好几回。第二个技巧是用内网 registry 替代 tar 包。tar 包适合一次性交付但集群扩容、版本升级时反复导入很痛苦。条件允许的话在内网起一个 registry把镜像docker tag成内网地址后docker pushkubelet 配置--image-repository指向它。flannel 的 yaml 里镜像地址也改成内网地址。这样新节点加入时直接拉不用再传 tar 包。# 给镜像打内网 registry 标签 docker tag flannel/flannel:v0.23.0 registry.internal:5000/flannel/flannel:v0.23.0 # 推送到内网 registry docker push registry.internal:5000/flannel/flannel:v0.23.0参数上registry.internal:5000换成你实际的 registry 地址端口和路径按需调整。containerd 那边要在/etc/containerd/config.toml里配置mirrors指向内网 registry否则还是会去外网拉。我自己的习惯是第一次离线交付用 tar 包同时把镜像推进内网 registry后续扩容只维护 registry。这样既解决了首次没有仓库的问题又避免了长期依赖 tar 包。flannel 镜像包这件事说到底不是拉几个镜像那么简单而是把「离线环境里 k8s 网络怎么稳定起来」这条链路走通。希望帮到你。本文还有配套的精品资源点击获取

关于本文作者

来自尧图内容编辑团队

尧图内容编辑团队 内容团队

尧图内容编辑团队

本文由尧图网络内容编辑团队执笔。团队由资深项目经理、前端工程师与设计师组成,所有内容均来自亲手交付的真实项目,先讲清问题、再给出可落地的解法。尧图深耕北京网站建设十年,服务过京华建材集团、智造科技等各行业客户,把一线经验沉淀为可复用的行业观察。

  • 十年建站经验,覆盖建材、制造、服务、文创等
  • 项目经理把关选题与事实准确性
  • 工程师与设计师联合撰写专业细节
  • 统一编辑规范,保证文风与排版一致
  • 每月复盘转化数据,迭代选题方向

延伸阅读

相关资讯与近期热门内容

深度阅读推荐

建站决策前值得细读的三篇

网站改版的5个关键决策
2024-08-12

网站改版的5个关键决策

什么时候该改版、改到什么程度、如何避免流量掉光,京华建材集团改版复盘给出答案。

获取专属建站方案

看完文章,把您的行业与预算告诉我们,免费获取一份量身定制的官网建设方案与报价。

立即免费咨询