K8s离线部署必看:Calico v3.20.6镜像包与yaml配置详解 简介面向 Kubernetes 集群管理员、运维工程师及网络策略配置人员这份 Calico v3.20.6 版本容器镜像与 calico.yaml 部署文件合集聚焦 Calico 在 Kubernetes 中的核心组件与部署配置。包含 Node、CNI、kube-controllers、pod2daemon-flexvol 四个 tar 格式镜像分别负责节点网络与 BGP 路由、Pod 接口设置、网络策略与 IP 管理、配置卷挂载等任务另附一份完整的 calico.yaml 清单文件定义了 DaemonSet、CNI 插件、策略控制器及 BGP 参数。这些组件协同工作可实现跨节点 Pod 通信、路由宣告与基于策略的访问控制。压缩包共 5 个文件大小约 96.68MB便于内网离线分发与快速部署。目前已有 1076 人学习下载。通过这一资源可一次性获得整套组件镜像和统一配置模板省去手动拉取镜像、编写繁琐 YAML 的步骤适合在离线或受限网络环境下搭建具备安全隔离和细粒度策略控制的 Kubernetes 集群无论是新集群初始化还是已有环境补全都能直接复用。1. calico v3.20.6 镜像包 calico.yaml离线集群网络插件的最省心组合先给一个反直觉的结论CNI 部署里翻车最多的往往不是 BGP 对等关系也不是 IP 池规划而是“yaml 里写的镜像 tag 和仓库里实际存的镜像对不上”。尤其是离线环境网络插件没起来整个集群的 Pod 调度都会卡在 ContainerCreating排查一圈发现只是镜像版本漂移非常不值。这份资源是 calico v3.20.6 的容器镜像集合加一份配套的 calico.yaml 部署清单。它解决的是 K8s 集群在无法直接访问外网镜像仓库时怎么把 CNI 网络跑起来的核心问题。适合三类人做离线交付的实施工程师、自建机房或内网环境的运维、以及想把网络插件版本固定下来避免“追最新追出问题”的集群管理员。版本固定、镜像齐全、yaml 配套这就是它最实在的价值。2. 拆解 calico.yaml五个核心组件与镜像的一一对应拿到这份资源第一步不是急着 apply而是先弄清楚 calico.yaml 里到底声明了什么东西。很多人习惯性kubectl apply -f calico.yaml一把梭等 Pod 报错了再回头看 yaml那个时候往往已经绕了弯路。v3.20.6 的这份 yaml 是标准的手动安装形态里面组件分工很清晰值得先花十分钟拆一遍。2.1 calico.yaml 里真正被用到的组件calico.yaml 不是单个资源而是一整套声明式部署文件。它包含 CustomResourceDefinition、ConfigMap、DaemonSet、Deployment 和 RBAC 授权对象拆开看主要有五个角色第一个是 calico-node DaemonSet这是整个 CNI 的核心yaml 中它以 DaemonSet 形式在每个节点上启动一个 PodPod 内部实际跑了两个进程Felix 负责路由和网络策略BIRD 负责 BGP 路由广播。第二个是 calico-kube-controllers Deployment它是管控面组件负责同步网络策略、清理 IPAM 租约没有它 Calico 的策略功能会失灵但普通路由转发不受影响。第三个是 calico-cni 相关的 CNI 插件二进制与配置yaml 里通过 initContainer 把二进制写入宿主机的 /opt/cni/bin再由 ConfigMap 生成 /etc/cni/net.d 配置给 kubelet 调用。第四个是 flexvol 相关的 DaemonSet 组件用于支持 Calico 的文件系统挂载能力一般 AlibabaCloud 或自建存储相关场景才会显式用到它。第五个是 CRD 定义包括 IPPool、FelixConfiguration、KubeControllersConfiguration 等calicoctl 能查询的这些对象都由它们支撑。这里有个细节值得注意v3.20.6 的 yaml 里 Typha 组件默认是注释掉的。Typha 是 Calico 的扩展组件专门用来在高密度节点集群里降低 API Server 压力节点数少的时候不启用反而更简洁。很多人在部署时看到 yaml 里有注释的 Deployment 就开始纠结“要不要打开”实际不需要默认注释状态就是官方推荐的路数。2.2 四个镜像与 yaml 内的位置理解了组件再对照镜像逐个确认就不会出现“节点上镜像都导入了还是起不来”的尴尬。v3.20.6 这套资源里最具辨识度的四个镜像如下镜像名对应 yaml 中的角色说明calico/node:v3.20.6DaemonSet calico-node主进程镜像内含 Felix 与 BIRDcalico/cni:v3.20.6DaemonSet 的 initContainer提供 CNI 插件二进制写入宿主机calico/kube-controllers:v3.20.6Deployment calico-kube-controllers管控面组件处理策略与 IPAM 租约calico/pod2daemon-flexvol:v3.20.6DaemonSet 的辅助容器提供 flexvol 挂载能力部分环境必需镜像与角色的对应关系在排查问题时的实际用途非常大。比如 calico-node Pod 起来后一直 CrashLoopBackOff先看它用的是不是 calico/node 镜像如果是 calico/cni 镜像被误用在了 node 位置那必然是启动参数解析失败。类似这种错位光看日志很难快速定位对照表格查一遍就清楚了。2.3 为什么固定 v3.20.6 而不是追 latest很多人在部署时习惯性拉 latest理由是“反正能跑就行”。但 CNI 这种底层组件恰恰最怕版本漂移。今天拉到的 latest 和三个月前部署环境的 behavior 可能完全不同接口名变了、Felix 默认参数变了、IP 池校验逻辑变了结果就是集群升级的时候网络静默翻车。v3.20.6 这个版本在 v3.20.x 这条线里属于稳定迭代期Kubernetes 1.20 到 1.23 这个区间内它经历了足够多的生产验证。把版本固定在 v3.20.6意味着两件事一是离线环境部署时所有组件行为可预期二是后续排查问题时社区检索到的经验、参数、issue 都与你手上的版本对齐不会出现“网上答案是 v3.19 的yaml 写法对不上”的情况。这也是这类固定版本镜像包比直接拉 latest 更适合生产环境的原因。3. 离线部署 v3.20.6镜像搬运、yaml 改址与三处强制检查离线部署的核心链路就三步把镜像弄进内网把 yaml 里的镜像地址改成内网仓库然后 apply 并观察启动。每一步都有对应的检查点跳过任何一步后面都会用异常状态回报你。3.1 联动镜像导出与导入的完整链路在有外网访问的机器上先把四个镜像拉到本地并打包命名规范一点避免传到内网后分不清哪个文件对应哪个镜像。常见做法是用镜像名加版本号做文件名例如 calico_node_v3.20.6.tarmkdir -p calico-v3.20.6-images cd calico-v3.20.6-images for img in calico/cni:v3.20.6 calico/node:v3.20.6 calico/kube-controllers:v3.20.6 calico/pod2daemon-flexvol:v3.20.6; do image_name$(echo $img | tr / _ | tr : _) docker pull docker.io/$img docker save -o ${image_name}.tar docker.io/$img done这段脚本的逻辑很直白循环拉取四个指定版本的镜像然后按“镜像名_版本号.tar”的规则导出。这里有一个血泪经验值得强调——导出前务必确认 tag 完整不要只打docker pull不校验。曾经见过有人拉的时候写了calico/node:latest导出还叫 v3.20.6传到内网加载后 Pod 起不来查了半天才发现 tag 被 latest 覆盖了。内网侧导入时先确认运行环境用的是 docker 还是 containerd。纯 docker 环境直接用docker load -i导入即可k8s 1.24 之后默认用 containerd 的环境需要走ctr命令sudo ctr -nk8s.io images import calico_node_v3.20.6.tar sudo ctr -nk8s.io images list | grep calico-nk8s.io这个参数很关键它指定了命名空间。containerd 的镜像默认命名空间是default而 kubelet 拉取镜像时走的是k8s.io命名空间导入到错误命名空间的话kubelet 依然会报镜像不存在。3.2 改 yaml 前先核对的三件事镜像进入仓库或本地后下一步是修改 calico.yaml。这里说的“修改”不是把镜像 tag 改一改就完事而是三处强制检查镜像仓库地址、Pod 网段、以及 API Server 参数一致性。镜像仓库地址的替换是首先做的。如果内网搭了私有仓库将docker.io/calico/批量替换成内网仓库地址sed -i s#docker.io/calico/#registry.local/calico/#g calico.yaml grep -E image: calico.yaml | sort | uniq -csort | uniq -c的作用是把替换后的镜像地址汇总计数一眼就能看出全部 image 字段是否都指向了同一个仓库前缀。替换完成后要查看每个 Deployment / DaemonSet 的 image 值确认没有任何一处漏改。很多“部分节点起得来、部分节点 pull 失败”的问题根源就是 sed 没替换干净手工检查比盲目相信正则更可靠。第二处检查是 Pod 网段。calico.yaml 里默认的CALICO_IPV4POOL_CIDR是 192.168.0.0/16如果kubeadm init时已经指定了--pod-network-cidr10.244.0.0/16两者必须一致。不一致的直接后果是 kubelet 分配的 Pod IP 与 Calico 的 IP 池完全不匹配Pod 创建后 IP 地址落在池外路由表乱成一团。第三处检查是看 kube-apiserver 是否启用了--network-plugincni。这个参数在 kubeadm 部署的集群里通常由 kubelet 配置自动带入但二进制部署环境下很容易漏。集群没网络插件且 kubelet 没开启 CNI 模式时CNI 插件不会生效calico-node 就算全 RunningPod 依然会在容器创建阶段卡住。3.3 应用与滚动观察三处检查确认无误后apply yaml 并观察 Pod 状态kubectl apply -f calico.yaml kubectl -n kube-system get pod -l k8s-appcalico-node -o wide kubectl -n kube-system get pod -l k8s-appcalico-kube-controllers -o widecalico-node 是 DaemonSet预期状态是每个节点一个 Running Podcalico-kube-controllers 是 Deployment预期是 1/1 Running。启动顺序上calico-node 先起来因为它是提供 CNI 网络能力的实体kube-controllers 随后完成策略同步和租约清理。如果你的集群节点有几十个第一次滚动启动时看到部分节点还在 ContainerCreating 是正常的calico-node 的 initContainer 需要先把 CNI 二进制写入宿主机再启动主容器这个过程在批量节点上会有几十秒的窗口期。超过五分钟仍未 Running直接看对应节点的 Pod 事件重点查镜像拉取和 CNI 配置挂载两类问题。4. IP 池与封装选型四个关键参数改完立即生效calico.yaml 部署成功只是第一步真正影响网络表现的是 IP 池和封装模式这几个参数。v3.20.6 的 calico.yaml 里这些参数大多数以环境变量形式出现在 calico-node DaemonSet 中少数以 CRD 形式存在。改参数的方式很直接改 yaml 后重新 applyDaemonSet 会自动滚动。但有几个典型的理解误区需要先讲清楚。4.1 修改 CALICO_IPV4POOL_CIDR一处地址两处同步CALICO_IPV4POOL_CIDR 是最常被改的参数但也是最容易改出“只改一半”问题的地方。在 calico.yaml 中这个 CIDR 同时存在于两个位置calico-node DaemonSet 的环境变量CALICO_IPV4POOL_CIDR以及默认的 IPPool CRD 资源里。只改环境变量、不改 CRD 的话calico-node 会按新网段执行 IPAM但 IPPool 对象里记录的仍是旧网段calicoctl 查询时看到的是旧配置后续扩容节点或新增 pool 时可能冲突。反过来只改 CRD 不改环境变量calico-node 启动时会按环境变量重新自动创建 IPPool手动改的 CRD 被覆盖。正确做法是两处同步修改确保环境变量与 CRD 一致。改完 apply 后用以下命令确认 IP 池实际生效范围calicoctl get ippool -o wide看到输出中的 CIDR 与预期一致后再去创建测试 Pod 验证分配出的 IP 是否落在该网段内。4.2 IPIPMode跨网段与同网段怎么选IPIPMode 控制的是跨节点通信的封装方式模式行为适用场景Always所有跨节点流量都走 IPIP 封装节点间网络不互通底层路由不可控CrossSubnet同子网直连跨子网才封装节点分处多个网段同网段性能优先Never不封装依赖底层路由可达节点网络全互通或已由底层 BGP 接管Always 最省心但性能最差每个数据包多一层 IP 头Never 性能最好但要求底层交换机或路由已经允许 Pod 网段路由通过。大多数内部网络可控的机房场景首选 CrossSubnet它在同机房同网段节点之间走直连跨网段节点自动加封装兼顾性能与可用性。v3.20.6 默认为 Always实际生产环境建议根据集群规模重新评估后再确定。4.3 MTU 与接口前缀网卡级翻车点MTU 不一致是 Pod 间通信时隐晦丢包的高频原因。Calico 创建的 veth 接口默认 MTU 取 0 时会跟随主网卡自动推导但推导规则不是直接复制而是取“主网卡 MTU 减 50”。例如主网卡 MTU 是 1500veth 接口就是 1450这 50 字节是为封装层预留的。主机网卡 MTUCalico veth 推荐 MTU说明15001450默认以太网环境90008950数据中心 jumbo frame 环境需同时调整底层交换机此参数对应 yaml 中的FELIX_MTUIFACE或MTU相关字段v3.20.6 里也可在 IPPool 中设置。若集群网络流量大、延迟敏感建议显式设置 MTU 值不要依赖自动推导。另外接口前缀默认是cali多个网络插件共存时可通过INTERFACE_PREFIX调整以避免接口名冲突比如改成cali0。5. 避坑清单五个真实翻车场景与排查路径这一部分是把 v3.20.6 部署过程中最容易踩到的坑集中做一遍复盘每一条都是真实环境里出现过的现象。按“现象 → 原因 → 解决”的顺序写下来排查时直接对号入座。5.1 镜像 tag 换了节点 Pull 不下来现象calico-node Pod 长时间 ImagePullBackOffkubectl describe pod显示manifest unknown但仓库里明明有 calico 相关镜像。原因打包镜像时拉取了 latest 或未固定 tag离线导入后镜像列表里根本没有带 v3.20.6 标签的镜像。解决在镜像列表源侧执行docker images | grep calico确认 tag 完整不存在的 tag 用docker tag补齐后重新 save、传输、load。如果已经是通过 commit 生成的镜像tag 只是标签需要重新打标签再导入。5.2 Pod 网段和节点网段重叠路由错乱现象calico-node 全部 Running但部分节点上的 Pod 无法跨节点通信ip route里出现与物理网段冲突的条目。原因CALICO_IPV4POOL_CIDR 设置的网段与节点主机的物理网段重叠BGP 路由把物理流量和容器流量混在了一起。解决在部署前先确认所有节点的/etc/kubernetes/manifests/或 kubelet 配置里的 Pod CIDR一定不要与主机网段交叠。一旦部署后发现重叠需要重新安装 calico修改 CIDR 后卸载老旧 IPPool 资源再重新 apply没有简单后悔药。5.3 残留的 flannel 干扰 CNI 初始化现象calico-node 正常但 Pod 创建时仍报 CNI 插件初始化失败日志里出现 flannel 相关残留。原因该节点此前部署过 flannel/etc/cni/net.d下残留了10-flannel.conflistkubelet 优先读到了它阻塞了 calico 的 CNI 配置生效。解决清理旧插件rm -f /etc/cni/net.d/10-flannel.conflist rm -rf /opt/cni/bin/flannel* systemctl restart kubelet同时确认 flannel 相关的 DaemonSet、NetworkAttachmentDefinition 已删除避免重复配置 CNI。5.4 镜像导进去了kubelet 还是报拉取失败现象用docker load导入镜像成功后calico-node Pod 仍然报image pull failed。原因节点实际运行环境是 containerd 而非 dockerdocker load导入的镜像是写进 docker 自己的存储层的containerd 完全看不到。解决用ctr -nk8s.io images import重新导入或用crictl images确认 containerd 侧确实能看到镜像。实际工作中还有部分环境用nerdctl管理 containerd此时nerdctl --namespace k8s.io load -i也是可行的替代方案。5.5 只改了 env没改 IPPool CRD现象应用新网段后calico-node 启动正常但 calicoctl get ippool 看到的 CIDR 还是旧值Pod 分配的 IP 与预期不符。原因改环境变量后 calico-node 会自动创建或者复用已有 IPPool已有 IPPool 的 CIDR 不会因为环境变量变化而同步变更。解决同时修改 calico.yaml 中的 env 与 CRD 资源两处apply 前用grep -n CALICO_IPV4POOL_CIDR calico.yaml确认出现位置逐个核对全部一致再执行。6. 部署后的验证从 calicoctl 状态到镜像安全校验部署完成不等于交付完成验证阶段要落到两件事网络状态是否健康以及镜像是否可信。calicoctl 是验证 Calico 状态的直接入口。先看 BGP 节点状态calicoctl node status calicoctl get ippool -o yaml calicoctl get workloadEndpoint -o widecalicoctl node status会列出每个节点的 BGP 会话状态正常情况下相邻节点间的状态应为 Established。如果某个节点与所有邻居都不建立会话先检查该节点的 BGP 配置和节点间 179 端口是否被防火墙拦截。IPPool 的 yaml 输出则用于二次确认网段与封装模式这两个输出与 yaml 配置一致再进入网络连通性验证。镜像安全校验是很多人忽略的一步。离线交付的镜像包传输过程中是否被篡改、导入后 tag 与内容是否对应都应该做一次显式校验。拿到 tar 包时先算 sha256与源侧记录比对sha256sum calico_node_v3.20.6.tar docker run --rm docker.io/calico/node:v3.20.6 calico-node --version校验过后再看镜像的 layer 信息确认没有额外的奇怪历史层。从容器安全的角度镜像导入后尽量先在工作节点之外单独跑一次容器做冒烟测试观察是否正常输出版本确认镜像本身没有被植入额外指令这也是保护生产集群的最后一道防线的习惯性动作。从那以后我每次接手 K8s 集群在网络阶段都会强制走一遍“三对表”镜像 tag 对一遍calico.yaml 版本对一遍Pod CIDR 对一遍。这套流程省下的排查时间远超部署时的几分钟希望帮到你。本文还有配套的精品资源点击获取