K8s离线交付:flannel镜像包从拉取到导入的全流程避坑指南
发布时间:2026/10/15 9:26:37 锦皓数字建站

简介在离线或网络受限环境下安装Kubernetes集群时flannel网络插件镜像的获取常成为阻塞项特别是国内用户常因拉取超时或版本缺失而中断部署。压缩包内含flannel v0.21.5与flannel-cni-plugin v1.1.2两个tar归档以及配套的kube-flannel.yaml编排文件面向K8s部署与运维人员。文件总数为3体积仅27.34MBtar镜像可通过docker load直接导入本地镜像库yaml文件则定义了flannel在集群中的部署参数与DaemonSet配置结构清晰便于检查与调整。已有1613人学习下载说明其确实覆盖了常见安装场景。拿到压缩包后用户可自行加载镜像并应用清单文件快速完成网络插件上线省去在公网反复拉取或版本匹配的困扰适合内网环境、离线交付以及需要快速复现K8s网络组件的学习与生产场景。1. 安装 k8s 所需 flannel 必要镜像包这活儿看着简单翻车点全在镜像清单上安装 k8s 所需 flannel 必要镜像包这个活儿看着简单但我见过太多集群卡在这一步kubeadm init 顺利通过控制平面起来了kubectl apply -f kube-flannel.yml敲下去kube-flannel-ds-xxxx 却一直 ImagePullBackOff。原因几乎都一样——动手之前没盘清楚必要到底指哪几个镜像。flannel 从来不是一个镜像而是一个镜像组合主守护进程一个CNI 插件安装用的 init 容器一个不同版本之间还有对齐关系。只拉一个 flannel 主镜像就以为完事是这条路上最大的坑。这篇笔记按离线交付的实际顺序把这组镜像的清单怎么提取、版本怎么对齐、tar 包怎么打、节点上怎么导入、翻车了怎么看一次讲透。适合用 kubeadm 搭集群、需要在离线或网络受限环境里交付 flannel 的运维和交付工程师。2. 先盘清楚 flannel 到底需要哪几个镜像版本对齐与缺失排查2.1 kube-flannel.yml 里的 image 字段主镜像和 init 镜像缺一不可kube-flannel.yml 是一个 DaemonSet你把它 apply 下去之后每个符合条件的节点上都会拉起一个 kube-flannel Pod。很多人只记得flannel 有个镜像于是拉了一个flannel/flannel就完事结果 Pod 起不来因为这份清单里的镜像远不止一个。从 flannel 官方维护的 kube-flannel.yml 来看Pod 模板里通常会出现两类镜像一类是主容器kube-flannel用的 flannel 镜像它负责跑 flanneld 进程维护 VXLAN 或 IPIP 后端、上报节点子网另一类是 init 容器用的 CNI 插件安装镜像负责把 flannel 的 CNI 二进制拷贝到节点的/opt/cni/bin目录再把 CNI 配置文件写到/etc/cni/net.d/。这两个 init 容器分别在使用不同镜像所以必要镜像包至少是两个镜像。具体是几个、叫什么名字只取决于你手上这份 kube-flannel.yml而不是网上的某篇教程。最可靠的办法是直接把你将要 apply 的那份 YAML 拿来做文本提取看它到底引用了哪些镜像grep -E ^\simage: kube-flannel.yml | awk {print $2} | sort -u这条命令的含义grep匹配以行首空白加image:开头的行把 manifest 里所有镜像字段捞出来awk {print $2}取第二列也就是镜像名sort -u去重排序。跑完之后你会得到一个类似下面的清单docker.io/flannel/flannel:v0.24.2 docker.io/flannel/flannel-cni-plugin:v1.4.0-flannel1看到这个输出你就明白主镜像flannel/flannel和 init 镜像flannel/flannel-cni-plugin缺一不可。如果你的集群用的是早期版本镜像里可能出现quay.io/coreos/flannel这种老地址还有少数社区整理的 manifest 会额外引用containernetworking/plugins用来补 bridge、host-local 这类基础 CNI 插件。我的建议是任何第三方整理的 YAML 都不要直接拿来用先用上面这条命令做一次镜像清单审计确认它引用的每个镜像你都能拿到才往下走。2.2 版本怎么对齐k8s 小版本、flannel 版本与 CNI 插件的匹配关系镜像名称确定之后第二件事是版本对齐。flannel 的版本号在语义上跟随 Kubernetes 的发布节奏但不存在必须严格一一对应的硬性规则——官方 manifest 里给出的 flannel 版本就是经过验证的组合所以最省事的做法是从你要用的那份 kube-flannel.yml 里读版本不要自己随便挑一个 latest。实操中我一般这样选型Kubernetes 1.28 到 1.30 这个区间flannel 主镜像用 v0.24.x 到 v0.25.x 都比较常见flannel-cni-plugin 用 v1.4.0-flannel1 这种带 CNI 规范版本号的 tag。组件之间的匹配关系主要是flannel 主进程支持的 CNI 规范版本要能被容器运行时接受如果 cni-plugin 镜像的 CNI 版本和 containerd 的 CNI 实现差异过大Pod 网络初始化时会报版本协商失败。下表是我在几个交付项目里验证过的参考区间注意这只是经验参考动手前一定要以官方 release 页和你手上的 YAML 为准Kubernetes 版本flannel 主镜像参考flannel-cni-plugin 参考1.26 ~ 1.27flannel:v0.21.x ~ v0.23.xflannel-cni-plugin:v1.1.0-flannel1 左右1.28 ~ 1.29flannel:v0.24.xflannel-cni-plugin:v1.4.0-flannel11.30 ~ 1.31flannel:v0.25.x 上下跟随官方 manifest另外注意一点VXLAN 和 IPIP 只是后端模式的选择不影响镜像本身。你不需要为不同后端准备不同的镜像包同一份镜像改 flannel 的 ConfigMap 里的Backend.Type就行。版本对齐这步的目标只有一个让镜像清单里的每一个 tag 都真实存在于你的交付包中并且能被目标节点的运行时架构接受。2.3 三条命令确认节点镜像现状grep 清单、crictl 查询、事件定位去目标节点上动手之前先确认现状。最常见的翻车是明明导入了镜像但 kube-flannel Pod 还在拉远端。所以要在节点上用下面几条命令核对节点实际有的镜像和YAML 需要的镜像是否完全一致。如果是 containerd 运行时用 crictl 查crictl 是 kubelet 视角比 ctr 更贴近真相crictl images | grep -i flannel如果是 docker 运行时或者装了 cri-dockerd 的节点用 docker 查docker images | grep -i flannel这两条命令的输出要和 2.1 里 grep 出来的清单逐项比对。比对的重点不是有没有 flannel 字样而是 registry 前缀、仓库路径、tag 三者完全一致。比如 YAML 里写docker.io/flannel/flannel:v0.24.2节点上只有flannel/flannel:latest那 kubelet 仍会去远端拉取因为 tag 不匹配在镜像查找逻辑里等于镜像不存在。如果 Pod 已经在跑但状态不对直接看事件kubectl describe pod -n kube-flannel \ $(kubectl get pods -n kube-flannel | awk /kube-flannel/{print $1; exit})在输出的 Events 尾部找Failed to pull image或ErrImagePull字样它会把你 kubelet 尝试拉取的完整镜像名打出来——这个镜像名才是你真正要准备的对象而不是你记忆里的那个。三个命令组合起来就是一个完整的缺失镜像定位流程先 grep 出 YAML 清单再在节点上查实际镜像最后用事件确认 kubelet 到底在拉什么、为什么失败。这一章盘清楚之后下一章就可以在能联网的机器上做打包了。3. 在能联网的机器上准备镜像包拉取、重打 tag、导出 tar 的完整命令3.1 镜像源怎么选内部仓库优先公共镜像源做补充准备镜像包的第一步是找一台能拉到 flannel 镜像的机器。这台机器不一定是集群节点我一般叫它打包机在整个离线交付链条里它负责把镜像变成 tar 包目标节点只负责导入不再触碰公网镜像仓库。镜像源的选择按可靠性排序我的习惯是这样的如果有公司内部的镜像仓库并且里面已经同步了 flannel 相关镜像那优先用它因为内部仓库地址固定、并发有保障交付文档里写死一个内网地址就行。如果没有内部仓库就用公共镜像源做中转——常见的做法是把 flannel 官方镜像同步到一个公共镜像源的路径下再拉下来。需要提醒的是这类公共镜像源的域名和可用性波动比较大今天能用的地址下周可能就失效所以不要把它写进正式交付文档只在准备阶段当临时通道用。下面的命令里我用registry.internal.example.com占位实操时替换成你实际能拉到的地址。选源有个核心原则打包机的架构要和目标节点一致。比如目标节点是 x86_64打包机也是 x86_64直接 pull 出来的镜像架构天然匹配。如果打包机是 ARM 的后面就必须用--platform显式指定架构这个坑在第 5 章专门讲。3.2 单镜像操作pull、tag、save 三步走拿到镜像源之后单个镜像的准备就是标准的三步拉取、改成 YAML 里的原始名字、导出。下面这段以内部仓库路径 常见 flannel 版本为例实际执行时把 REGISTRY 换成你能拉到的地址把版本号换成 2.1 里 grep 出来的值export REGISTRYregistry.internal.example.com export FLANNEL_VERv0.24.2 export CNI_VERv1.4.0-flannel1 docker pull ${REGISTRY}/flannel/flannel:${FLANNEL_VER} docker tag ${REGISTRY}/flannel/flannel:${FLANNEL_VER} docker.io/flannel/flannel:${FLANNEL_VER} docker pull ${REGISTRY}/flannel/flannel-cni-plugin:${CNI_VER} docker tag ${REGISTRY}/flannel/flannel-cni-plugin:${CNI_VER} docker.io/flannel/flannel-cni-plugin:${CNI_VER} docker save \ docker.io/flannel/flannel:${FLANNEL_VER} \ docker.io/flannel/flannel-cni-plugin:${CNI_VER} \ -o flannel-images.tar这段命令里最关键的一步是docker tag。为什么要把内部仓库路径改回docker.io/flannel/flannel因为 kube-flannel.yml 里写的就是这个名字kubelet 在找镜像时是按 YAML 里的字符串精确匹配的。如果你把内部仓库路径的原样保存进 tar到了目标节点上镜像名就带了一截内网前缀和 YAML 对不上等于白导。docker save可以把多个镜像打到一个 tar 里导出后建议ls -lh flannel-images.tar看一眼大小flannel 两个镜像的 tar 通常在 100 MB 上下如果只有几 MB八成是只打进去一个或者镜像拉成了空壳。参数一览参数含义说明REGISTRY镜像源地址你实际能拉到镜像的仓库内部仓库或公共镜像源FLANNEL_VERflannel 主镜像版本必须和 YAML 里的 tag 一致CNI_VERflannel-cni-plugin 版本必须和 YAML 里的 tag 一致这里有个容易搞混的点如果 YAML 里镜像名没有docker.io/前缀比如写的是flannel/flannel:v0.24.2那 tag 的时候也按 YAML 原样来不要自己脑补前缀。docker 和 containerd 都会把不带前缀的镜像解析到 docker.io但为了和 YAML 逐字对齐、也为了方便后续脚本比对我习惯让 tar 里的镜像名和 YAML 完全一致一种写法写到底。3.3 批量操作基于镜像清单写一个 5 行的准备脚本单镜像手工操作没问题但 flannel 往往不止一个镜像更别提以后如果还要准备 dashboard、metrics-server 的离线包手工复制粘贴容易漏。所以我在第二章 grep 的基础上把准备过程写成了一个小脚本思路是把 YAML 里的镜像清单当成唯一输入源#!/usr/bin/env bash set -euo pipefail YAML${1:-kube-flannel.yml} REGISTRY${REGISTRY:-registry.internal.example.com} IMAGES$(grep -E ^\simage: $YAML | awk {print $2} | sort -u) while IFS read -r image; do name${image#docker.io/} docker pull ${REGISTRY}/${name} docker tag ${REGISTRY}/${name} ${image} done $IMAGES docker save ${IMAGES} -o flannel-images.tar echo done: flannel-images.tar这段脚本的逻辑先用 grep 把 YAML 里的镜像名全部提取出来作为循环输入${image#docker.io/}是 bash 的字符串裁剪把docker.io/前缀去掉拼成内部仓库路径/flannel/flannel:v0.24.2这样的拉取地址拉下来之后 tag 回 YAML 里的原始名字保证 tar 里的镜像名和集群期望一致最后把所有镜像一次性 save 到一个 tar 里。注意docker save那行直接用了IMAGES变量如果镜像清单里有重复项sort -u已经去了重save 不会因此报错但会重复占用 tar 空间所以去重这步不能省。脚本里有个边界情况要提醒如果 YAML 里某个镜像用了 digest 形式比如flannel/flannelsha256:xxxdocker save需要额外处理digest 镜像在 save 和 load 时都要求保留摘要信息。实操中 flannel 的官方 manifest 基本都用 tag所以我一般要求团队在离线交付阶段不要引入 digest 写法省得脚本在边界上翻车。3.4 导出前校验架构与 digest 检查save 之前花 10 秒钟做两项校验能省掉第 5 章一半的排障时间。第一项是架构第二项是 digest。docker image inspect docker.io/flannel/flannel:${FLANNEL_VER} \ --format 架构: {{.Architecture}} / {{.Os}} docker image inspect docker.io/flannel/flannel:${FLANNEL_VER} \ --format digest: {{index .RepoDigests 0}}第一条命令打印镜像的 CPU 架构和操作系统amd64对应 x86_64 节点arm64对应 ARM 节点。如果打包机是 ARM 而目标节点是 x86_64这里就会暴露出来。第二条命令打印镜像的 RepoDigest这个值在后面导入节点后可以用来做二次校验目标节点导入完用crictl images看到的镜像 ID 应该和这里的 digest 对得上如果对不上说明 tar 在传输过程中被改动过或者打包时拉错了副本。还有一个不太起眼但很实用的校验直接看 tar 内容列表确认两个镜像都在里面docker save docker.io/flannel/flannel:${FLANNEL_VER} \ docker.io/flannel/flannel-cni-plugin:${CNI_VER} \ | tar -t 2/dev/null | grep -E manifest.json|layer | head -5这条命令把 save 的输出管道给 tar 去列目录不用落地临时文件就能看 tar 的结构。看到多个 layer 目录加一个 manifest.json说明结构正常。这一章做完你手上应该有一个 flannel-images.tar里面是 YAML 所需的全部镜像名字和 tag 都已经对齐。接下来就是把它搬到目标节点上导入。4. 把镜像包导入目标节点docker 与 containerd 两条路线4.1 docker 运行时docker load 加 tag 还原目标节点的容器运行时决定导入方式。老一点的集群用 docker 做运行时kubelet 通过 cri-dockerd 或 dockershim 跟 docker 通信这种情况下的镜像导入最直接docker load -i flannel-images.tar docker images | grep -i flanneldocker load会把 tar 里所有的镜像连同 tag 一起还原到本地镜像仓库。因为打包阶段我们已经把镜像名 tag 成了 YAML 里的原始名字所以 load 之后不需要再做任何改名操作kubelet 找镜像时就能直接命中本地不会触发远端拉取。执行完docker images确认两行记录存在并且 REPOSITORY 和 TAG 与 YAML 一致。docker 路线有一个隐藏要求tar 包是在打包机上用docker save生成的load 的目标节点 docker 版本不能太老。老版本 docker 在 load 新格式镜像时偶尔会报invalid manifest之类的错如果遇到先看两边的 docker 版本差得太多就让打包机用兼容的导出方式再打一次包或者直接改用 ctr 走 containerd 导入绕开版本差异。4.2 containerd 运行时ctr 导入的两个关键参数现在 kubeadm 装出来的集群默认就是 containerd。containerd 没有 docker load 这种一键命令最常用的是 ctr但它有两个参数容易踩坑第一个是命名空间第二个是 digest 保留# 错误示范不加 -n导入到 default 命名空间 ctr images import flannel-images.tar # 正确示范导入到 k8s.io 命名空间并保留 digest ctr -n k8s.io images import --digests flannel-images.tar为什么强调-n k8s.io因为 containerd 是多命名空间的设计kubelet 通过 CRI 接口操作镜像时默认落在k8s.io这个命名空间里。如果你不加-n镜像会进入default命名空间crictl images查不到kubelet 也看不到最终还是去远端拉。这是离线导入 flannel 镜像时最高频的翻车点没有之一。--digests参数的作用是让导入过程保留镜像的 digest 信息。保留 digest 的好处是后续用镜像 ID 做一致性校验时crictl images显示的 ID 能和打包时的 RepoDigest 对上不保留也能导入、也能跑但如果你的交付流程里有双人复核镜像一致性这种要求digest 是最可靠的凭据。还需要注意crictl 本身不支持 import 操作不要试图用 crictl 去导入。导入只能用 ctr导入完成之后再用 crictl 去验证两者的分工是ctr 管导入crictl 管查询别搞混。4.3 导入后的验证crictl 与 kubelet 视角的一致性检查导入完成不代表 kubelet 一定认所以验证要看kubelet 视角的输出也就是 crictlcrictl images | grep -i flannel输出里应该看到两行镜像名和你 grep 出来的 YAML 清单完全一致。这里要特别说明 crictl 和 ctr 的差异ctr -n k8s.io images list查到的是 containerd 里的存储状态crictl images查到的是 CRI 层面的镜像列表两者底层一致但 crictl 会按 CRI 规范对镜像做归一化展示。判断kubelet 能不能找到镜像永远以 crictl 为准。如果集群里有 kubectl 权限还可以做一次严格比对。把 DaemonSet 模板里引用的镜像和节点实际镜像拉出来做 diffdiff \ (kubectl get ds kube-flannel-ds -n kube-flannel \ -o jsonpath{range .spec.template.spec.initContainers[*]}{.image}{\n}{end}{range .spec.template.spec.containers[*]}{.image}{\n}{end} \ | sort -u) \ (crictl images --no-trunc | awk {print $1:$2} | grep -i flannel | sort -u)这段命令左边从 DaemonSet 模板提取所有容器和 init 容器的镜像名右边把节点上 crictl 能看到的 flannel 镜像列出来diff 无输出就说明完全对齐。如果只在节点上操作、没有 kubectl 权限就退一步用grep YAML 清单 crictl images两边肉眼比对重点照样是 registry、仓库路径、tag 三者全对。4.4 让 kubelet 不再去远端拉取镜像名与 YAML 完全一致才算数这一节把完全一致拆成三个核对点方便你照着检查。第一registry 前缀。YAML 写docker.io/flannel/flannel:v0.24.2你的镜像也必须是这个YAML 写flannel/flannel:v0.24.2你的镜像保持原样即可。注意不要出现YAML 写 docker.io 前缀节点上镜像却没有前缀这类半对齐状态kubelet 的镜像查找是字符串精确匹配差一个斜杠都算没有。第二仓库路径。flannel/flannel和flannel/flannel-cni-plugin是两个不同仓库导入的时候经常有人把主镜像导了两次cni-plugin 没导。tar 包里的镜像路径必须逐项对上 YAML多一个少一个都不行。第三tag。版本号、大小写、是否有 flannel1 后缀都要逐字符一致。v0.24.2、0.24.2、latest是三个不同的 tagkubelet 只认它看到的那一个。如果以上三点全对kubelet 就不会发起远端拉取Pod 能正常进入 Running。如果还有问题大概率是 tar 包本身或者导入参数出了问题这就是下一章要处理的排查场景。5. 镜像导入与 flannel 启动的常见问题排查5 个高频翻车现场这一章把我在交付现场见过的高频问题按现象、原因、解决整理出来。每个问题都对应一个具体的操作失误按顺序对照着查能省下大量翻日志的时间。5.1 现象kube-flannel Pod 一直 ImagePullBackOff事件里明确写着拉取失败现象apply kube-flannel.yml 之后kubectl get pods -n kube-flannel看到 Pod 卡在 ImagePullBackOff 或 ErrImagePulldescribe 看到 Events 里有Failed to pull image的记录。原因节点本地镜像仓库里没有 YAML 所引用的那个精确镜像名。最常见是只导入了主镜像没导入 cni-plugin或者 tag 对不上。解决按第 3 章脚本重新准备完整镜像包按第 4 章正确导入导入后不用重启整个 DaemonSet删掉当前 Pod 让 kubelet 重建即可它会重新走一遍镜像查找kubectl delete pod -n kube-flannel -l appkube-flannel删除后 kubelet 会基于 DaemonSet 的期望状态立刻重建 Pod新 Pod 在创建时就会检查本地镜像命中后直接进入容器启动流程。5.2 现象ctr 导入成功crictl 却查不到kubelet 继续报拉取超时现象节点上执行ctr images import显示 imported看起来导入成功了但 kubelet 日志里还在反复拉镜像crictl images里也没有 flannel。原因导入时没加-n k8s.io镜像进到了default命名空间。kubelet 只在k8s.io命名空间里找镜像所以它认为镜像不存在继续按照 YAML 里的地址去远端拉。解决用ctr -n k8s.io images import --digests重新导入导入后先用ctr -n k8s.io images list | grep flannel确认存储层面有了再用crictl images | grep flannel确认 kubelet 视角也有了。两步都通过才说明这次导入真正生效。5.3 现象主容器起来了init 容器卡在 Init:CrashLoopBackOff现象kube-flannel Pod 的主容器状态正常或等待中但 init 容器反复重启describe 显示 init 容器的镜像拉取失败。原因flannel-cni-plugin这个 init 镜像没导入。init 容器起不来flannel 的 CNI 二进制和配置文件就不会落到/opt/cni/bin和/etc/cni/net.d后续主容器即便启动也无法完成节点网络配置。解决补齐flannel-cni-plugin镜像并导入然后删除 Pod 触发重建。这个坑的教训是判断镜像包是否齐全不能只看主容器有没有起来要把 YAML 里所有 initContainers 的 image 都算进必要镜像。5.4 现象镜像导入了Pod 一启动就报 exec format error 或直接 panic现象Pod 能创建但容器启动后立刻退出日志里有exec format error或者 containerd 直接报无法执行。原因架构不匹配。ARM 架构的镜像被导入到了 x86_64 节点或者反过来。打包机的架构和目标节点不一致又没有用--platform指定就会打出错误架构的镜像。解决打包时用--platform显式指定目标架构导入前用docker image inspect校验 Architecture如果交付包要覆盖两种架构的节点按架构分别打 tar并在文件名里注明 amd64 和 arm64运输时别拿错docker pull --platform linux/amd64 ${REGISTRY}/flannel/flannel:${FLANNEL_VER}5.5 现象节点上 flannel 镜像有好几个但没一个和 YAML 匹配现象docker images或crictl images里能看到一堆 flannel 相关的镜像latest、v0.24、带 flannel1 后缀的都有但 Pod 依然在拉远端。原因之前从不同源拉过、手工 tag 出各种变体镜像仓库里看起来有但 YAML 要的那个精确字符串不存在。解决以 YAML 清单为唯一标准清理多余镜像只保留精确匹配的那个。docker 节点用docker image rm删掉多余 tagcontainerd 节点在确认无用后可以用ctr -n k8s.io images del清理不熟悉的建议先留着只新增精确镜像别在节点上做高危删除操作。然后按 4.4 的核对三要素逐项比对缺哪个补哪个。另外再提醒一个习惯不要在节点上改 YAML 去凑镜像名。改 YAML 会带来节点间配置漂移正确做法永远是让镜像包去匹配 YAML而不是反过来。6. 把镜像准备固化成脚本并用跨节点连通性做最终验证最后分享一个我自己的习惯把导入动作也固化成脚本交付现场不依赖记忆。目标节点上放一个import-flannel.sh自动识别运行时并导入#!/usr/bin/env bash set -euo pipefail TAR${1:-flannel-images.tar} if command -v ctr /dev/null 21; then ctr -n k8s.io images import --digests $TAR crictl images | grep -i flannel elif command -v docker /dev/null 21; then docker load -i $TAR docker images | grep -i flannel else echo no container runtime found exit 1 fi脚本根据节点上存在ctr还是docker命令自动走对应分支导入完直接把验证结果打印出来现场操作的人不用记命令。配合第 3 章的打包脚本整条链路就两个字可重复。镜像导入只是手段flannel 真正干活才是目的。Pod 进入 Running 之后我一般按下面这条链路做最终验证每一步都对应一个明确的结论# 1. 确认 VXLAN 网卡已创建 ip -d link show flannel.1 # 2. 确认节点子网已经分配 cat /run/flannel/subnet.env # 3. 跨节点连通性在两个不同节点上各起一个测试 Pod互相 ping kubectl run ping-a --imagebusybox --restartNever --overrides{spec:{nodeSelector:{kubernetes.io/hostname:node-a}}} -- sleep 3600 kubectl run ping-b --imagebusybox --restartNever --overrides{spec:{nodeSelector:{kubernetes.io/hostname:node-b}}} -- sleep 3600 kubectl exec ping-a -- ping -c 3 ping-b 的 Pod IP # 4. 网络插件之上的 DNS 链路 kubectl run test-dns --imagebusybox --rm -i --restartNever -- nslookup kubernetes.defaultflannel.1存在说明 flanneld 启动并完成了内核侧配置subnet.env有内容说明节点通过 kube-apiserver 成功注册了子网跨节点 ping 通说明 VXLAN 或 IPIP 的封装转发真正工作nslookup能解析说明 CNI、kube-proxy、CoreDNS 整条链路上层都通了。四步全过这个镜像包才算真正交付完成。我最早给客户做离线交付时只压了主镜像结果在现场被 init 容器卡了半小时最后还是靠 grep YAML 才找到缺的 cni-plugin。从那以后我把先 grep 出镜像清单写成了流程的第一步所有离线包都按这个流程出再没在 flannel 镜像上栽过跟头。希望这些经验能帮到你少走一段我当时走过的弯路。本文还有配套的精品资源点击获取
锦
锦皓数字建站
深耕本土企业品牌数字化升级,专注原创端正雅致商务官网,从视觉设计到稳定运维全程保驾护航。