news 2026/10/14 9:14:42

Calico v3.25.0离线包制作与内网K8s集群导入实战指南

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Calico v3.25.0离线包制作与内网K8s集群导入实战指南

简介:这份资源是面向 Kubernetes 运维与集群管理人员的 Calico v3.25.0 离线安装包,专为解决内网、隔离环境或网络受限场景下无法在线拉取镜像、导致网络插件部署失败的问题。压缩包共 3 个文件,约 187.24MB,包含 1 个 tar 镜像包、1 个 yaml 部署清单和 1 个 txt 说明文档:tar 包集中存放 Felix、BIRD、Typha 等 Calico 核心组件镜像,yaml 提供标准部署配置,txt 则记录离线安装流程与注意事项,三者配合即可完成从镜像导入到插件上线的完整链路。目前已有 453 人学习下载,适合需要快速搭建稳定集群网络、实施网络策略控制的中高级 k8s 使用者参考。借助该离线包,读者可跳过外网依赖,直接在内网完成 Calico 部署,同时对照文档理解组件职责与配置要点,为后续排错和策略调优提供依据。

1. calico-image-v3.25.0离线包:内网 K8s 集群绕不过去的那道坎

在金融、制造、政务这类物理隔离的内网环境里,Kubernetes 集群的搭建从来不是kubeadm init一条命令的事。当你敲下初始化命令,kubelet 会去拉calico/node、calico/cni、calico/kube-controllers这几个镜像,而内网节点根本连不上任何镜像仓库,Pod 卡在ImagePullBackOff是必然结局。calico-image-v3.25.0 离线包要解决的,就是把这个版本 Calico 所需的全部容器镜像提前导出成 tar 文件,带到内网后批量导入到各节点的容器运行时里,让网络插件能正常起来。这篇文章面向的是需要在无外网环境部署 K8s 网络插件的运维和平台工程师,我会把镜像清单怎么定、tar 包怎么导、containerd 和 docker 两种运行时怎么分别处理、导入后怎么验证,以及我踩过的几个坑,一次讲清楚。

2. 先搞清楚 v3.25.0 到底需要哪几个镜像

2.1 Calico 镜像的组成逻辑

很多人以为 Calico 就一个镜像,实际上从 v3.20 之后,Calico 的部署清单里至少涉及三个镜像:calico/node负责 BGP 路由和 felix 策略下发,calico/cni提供 CNI 插件二进制和 IPAM,calico/kube-controllers处理 NetworkPolicy 和 IP 池的同步。如果你用的是 Typha 架构(节点数超过 50 的集群推荐开启),还会多一个calico/typha。另外calico/pod2daemon-flexvol在旧版本里用于挂载 flexvolume 驱动,v3.25 已经默认用 CSI 替代,但部分清单里仍会引用。

所以离线包里的镜像数量不是固定的,取决于你的calico.yaml或 Helm values 里实际启用了哪些组件。我一般会先把部署清单下载下来,用 grep 把image:字段全部抓出来,去重后再决定要导出哪些。

2.2 从官方 manifest 提取镜像清单

假设你已经在有外网的机器上准备好了 v3.25.0 的部署文件,执行下面这段命令提取镜像列表:

# 下载 calico v3.25.0 的部署清单(有外网时操作) curl -O https://raw.githubusercontent.com/projectcalico/calico/v3.25.0/manifests/calico.yaml # 提取所有 image 字段并去重 grep -oP 'image:\s*\K\S+' calico.yaml | sort -u

执行后你会看到类似这样的输出:

docker.io/calico/cni:v3.25.0 docker.io/calico/node:v3.25.0 docker.io/calico/kube-controllers:v3.25.0

如果你用的是 Typha 模式,清单里还会多一行docker.io/calico/typha:v3.25.0。注意镜像地址前缀可能是docker.io/calico/也可能是quay.io/calico/,取决于你下载的是哪个版本的 manifest。v3.25.0 官方默认走docker.io,但如果你之前用的是 quay 的清单,导出的镜像 tag 会不一样,导入后要对应修改 YAML 里的 image 地址。

提示:不要只导出calico/node一个镜像就以为完事了,CNI 和 kube-controllers 缺一个,集群网络都起不来。

2.3 镜像 tag 和架构的确认

v3.25.0 这个 tag 是明确的,但你要确认目标节点的 CPU 架构。如果你的内网集群是 ARM 服务器(比如鲲鹏、飞腾),而你在 x86 机器上导出的镜像,导入后 Pod 会报exec format error。确认方法:

# 查看镜像支持的架构 docker manifest inspect docker.io/calico/node:v3.25.0 | grep architecture

如果输出里有amd64和arm64两个值,说明是多架构镜像。但docker save默认只导出当前机器架构的那一层。所以导出镜像的机器架构必须和目标集群节点架构一致。我一般会在 x86 和 ARM 环境分别导出一份,或者用docker buildx做多架构导出,但后者操作复杂,离线场景下不推荐。

3. 导出镜像并打包成离线 tar 的完整流程

3.1 用 docker save 导出镜像

确认好镜像清单后,在一台有外网、架构匹配的机器上执行导出。我习惯把三个镜像打成一个 tar 包,方便传输:

# 拉取 v3.25.0 的三个核心镜像 docker pull docker.io/calico/node:v3.25.0 docker pull docker.io/calico/cni:v3.25.0 docker pull docker.io/calico/kube-controllers:v3.25.0 # 导出为一个 tar 文件 docker save -o calico-v3.25.0-images.tar \ docker.io/calico/node:v3.25.0 \ docker.io/calico/cni:v3.25.0 \ docker.io/calico/kube-controllers:v3.25.0

docker save的-o参数指定输出文件名,后面跟一个或多个镜像名。导出的 tar 文件大小通常在 200MB 到 400MB 之间,取决于镜像层数。如果你有 Typha,记得把它也加进去。

导出完成后用ls -lh看一下文件大小,再用tar -tf calico-v3.25.0-images.tar | head确认 tar 结构正常。有时候磁盘空间不足会导致 tar 包不完整,导入时报unexpected EOF,这个后面避坑章节会细说。

3.2 传输到内网节点

传输方式取决于你的环境。U 盘、内网文件服务器、跳板机 scp 都可以。我一般会在跳板机上放一份,然后通过内网 scp 分发到各节点:

# 从跳板机分发到各 worker 节点 for node in node1 node2 node3; do scp calico-v3.25.0-images.tar root@${node}:/tmp/ done

如果节点数量多,建议写个简单的循环脚本,或者用 ansible 的copy模块批量推送。注意/tmp分区大小,有些系统/tmp只给了几个 G,tar 包放不下会中途失败。

3.3 containerd 运行时的导入方法

这是最容易翻车的地方。K8s 1.24 之后默认用 containerd,而 containerd 不能用docker load导入镜像。正确做法是用ctr命令:

# 导入镜像到 containerd 的 k8s.io 命名空间 ctr -n k8s.io images import /tmp/calico-v3.25.0-images.tar # 验证导入结果 ctr -n k8s.io images ls | grep calico

关键在-n k8s.io这个参数。containerd 有多个命名空间,kubelet 用的是k8s.io,如果你不加这个参数,镜像会导入到 default 命名空间,kubelet 根本看不到,Pod 照样ImagePullBackOff。这个坑我见过太多次了,很多人导入后ctr images ls能看到镜像,就以为成功了,结果集群还是起不来。

导入后ctr -n k8s.io images ls应该能看到三个镜像,tag 都是v3.25.0。如果 tag 显示为sha256:xxx而不是版本号,说明导出时镜像没有 tag,需要重新docker tag后再导出。

3.4 docker 运行时的导入方法

如果你的集群还在用 docker 作为运行时(K8s 1.23 及之前),那就简单直接:

# docker 运行时导入 docker load -i /tmp/calico-v3.25.0-images.tar # 验证 docker images | grep calico

docker load会自动恢复镜像的 tag 和层信息。导入后确认三个镜像的 tag 都是v3.25.0,没有出现<none>。如果出现<none>,说明导出时镜像本身就没有 tag,需要回退到导出步骤重新打 tag。

注意:docker 和 containerd 的镜像存储是隔离的,不要在一台机器上混用。确认你的 K8s 节点用的是哪个运行时,用kubectl get nodes -o wide看 CONTAINER-RUNTIME 列。

4. 导入之后:让 Calico 真正跑起来的验证步骤

4.1 修改 YAML 中的 image 地址

镜像导入到本地后,还需要确保calico.yaml里的 image 地址和导入的镜像名完全一致。如果你导入的是docker.io/calico/node:v3.25.0,而 YAML 里写的是quay.io/calico/node:v3.25.0,kubelet 会尝试去拉 quay 的镜像,然后失败。

# 检查 YAML 中的 image 地址 grep 'image:' calico.yaml # 如果地址不匹配,用 sed 批量替换 sed -i 's|quay.io/calico/|docker.io/calico/|g' calico.yaml

替换后再grep确认一遍。这个步骤看起来简单,但经常有人忽略,尤其是从不同来源下载的 manifest,前缀不统一。

4.2 应用清单并观察 Pod 状态

# 应用 calico 清单 kubectl apply -f calico.yaml # 观察 calico-system 或 kube-system 下的 Pod kubectl get pods -n kube-system -l k8s-app=calico-node -w

-w参数会持续监听 Pod 状态变化。正常情况下,calico-node会在 30 秒到 1 分钟内变成Running。如果超过 2 分钟还是ImagePullBackOff或ErrImagePull,用kubectl describe pod看事件:

kubectl describe pod -n kube-system -l k8s-app=calico-node | grep -A 10 Events

事件里会明确写是镜像找不到还是导入的命名空间不对。如果是failed to resolve reference,说明镜像名和 YAML 里的不一致;如果是not found,说明 containerd 命名空间不对。

4.3 验证 Calico 网络实际可用

Pod 变成 Running 不代表网络就通了。我一般会做两步验证:

# 查看 calico-node 日志,确认 felix 和 BGP 正常启动 kubectl logs -n kube-system -l k8s-app=calico-node -c calico-node --tail=50 # 创建一个测试 Pod,验证跨节点通信 kubectl run test-pod --image=busybox --restart=Never -- sleep 3600 kubectl exec test-pod -- ping -c 3 <另一个节点上的Pod IP>

日志里如果看到Felix started和BGP peering established,说明 Calico 核心组件工作正常。跨节点 ping 通,说明 IPIP 或 BGP 路由生效。如果 ping 不通,检查节点的ip route和iptables规则,常见原因是内核模块ipip没加载或者防火墙挡了 BGP 的 179 端口。

5. 离线导入 Calico 镜像的避坑清单

5.1 坑一:containerd 命名空间搞错导致镜像“隐身”

现象:ctr images ls能看到 calico 镜像,但 Pod 一直ImagePullBackOff,kubectl describe pod显示failed to resolve reference "docker.io/calico/node:v3.25.0"。

原因:ctr images import默认导入到default命名空间,而 kubelet 通过 CRI 接口查询的是k8s.io命名空间。两个命名空间互相隔离,default 里的镜像 kubelet 看不见。

解决:导入时显式指定命名空间ctr -n k8s.io images import。已经导入错的,先ctr -n default images rm删掉,再重新导入到k8s.io。验证时也要用ctr -n k8s.io images ls而不是直接ctr images ls。

5.2 坑二:docker save 导出的 tar 包不完整

现象:docker load或ctr images import时报unexpected EOF或invalid tar header。

原因:导出过程中磁盘空间不足,或者docker save被中断,导致 tar 包尾部数据缺失。也有情况是传输过程中 scp 断连,文件没传完。

解决:导出前用df -h确认磁盘剩余空间至少是镜像总大小的 2 倍。导出后用tar -tf验证 tar 包完整性,能列出文件列表说明结构正常。传输后用md5sum对比源文件和目标文件的哈希值,确保传输无损。

5.3 坑三:镜像 tag 丢失变成 none

现象:导入后docker images或ctr images ls显示的 tag 是<none>或sha256:xxx,YAML 里指定的v3.25.0找不到对应镜像。

原因:docker save时镜像本身就没有 tag,或者导出命令里写的是 image ID 而不是name:tag格式。

解决:导出前先docker tag <image-id> docker.io/calico/node:v3.25.0打上正确 tag,再用name:tag格式导出。已经导出错的,重新打 tag 再导出一次。不要试图用docker tag给<none>镜像改名后继续用,层信息可能已经乱了。

5.4 坑四:ARM 和 x86 架构混用

现象:Pod 状态是CrashLoopBackOff,日志报exec format error或cannot execute binary file。

原因:在 x86 机器上导出的镜像,拿到 ARM 节点上导入。docker save只导出当前架构的镜像层,ARM 节点上的容器运行时无法执行 x86 二进制。

解决:导出镜像的机器架构必须和目标节点一致。混合架构集群需要分别在 x86 和 ARM 机器上各导出一份,或者使用docker buildx build --platform构建多架构镜像后导出 manifest list。离线场景下推荐前者,简单可靠。

5.5 坑五:YAML 里 image 地址和导入的镜像名不一致

现象:镜像明明导入了,ctr -n k8s.io images ls也能看到,但 Pod 还是报ImagePullBackOff,事件里显示尝试拉取的地址和你导入的地址不一样。

原因:calico.yaml里写的是quay.io/calico/node:v3.25.0,而你导入的是docker.io/calico/node:v3.25.0。kubelet 严格按照 YAML 里的地址去拉镜像,地址不匹配就找不到本地镜像。

解决:grep 'image:' calico.yaml确认所有镜像地址,和ctr -n k8s.io images ls的输出逐一比对。不一致的用sed批量替换 YAML 里的前缀,然后重新kubectl apply。建议在导出镜像前就先确认好 YAML 里的地址格式,按那个格式来 tag 和导出。

6. 用脚本把导出和校验串起来:一个省心的习惯

手动敲命令导出镜像,做一两次还行,版本一多就容易漏。我后来写了个小脚本,把镜像清单、导出、校验三步串在一起,每次升级 Calico 版本只需要改一个变量。脚本不复杂,但能省掉不少重复劳动:

#!/bin/bash # calico-offline-pack.sh # 用法:修改 CALICO_VERSION 后直接执行 CALICO_VERSION="v3.25.0" IMAGES=( "docker.io/calico/node:${CALICO_VERSION}" "docker.io/calico/cni:${CALICO_VERSION}" "docker.io/calico/kube-controllers:${CALICO_VERSION}" ) OUTPUT="calico-${CALICO_VERSION}-images.tar" # 拉取镜像 for img in "${IMAGES[@]}"; do echo "Pulling ${img}..." docker pull "${img}" || { echo "拉取失败: ${img}"; exit 1; } done # 导出为一个 tar 包 docker save -o "${OUTPUT}" "${IMAGES[@]}" # 校验 tar 包完整性 if tar -tf "${OUTPUT}" > /dev/null 2>&1; then echo "导出成功: ${OUTPUT}" ls -lh "${OUTPUT}" # 输出 md5 供传输后校验 md5sum "${OUTPUT}" else echo "tar 包损坏,请检查磁盘空间" exit 1 fi

脚本里IMAGES数组就是镜像清单,升级版本时只改CALICO_VERSION一个变量。docker save之后用tar -tf做一次完整性检查,能提前发现磁盘写满导致的 tar 损坏。最后输出md5sum,传到内网后用同样的命令算一遍,两个值一致才说明文件没传坏。

导入端的校验我习惯用一条命令搞定:

# 导入后确认三个镜像都在 k8s.io 命名空间 ctr -n k8s.io images ls | grep "calico.*${CALICO_VERSION}" | wc -l # 输出应该是 3(或 4,如果包含 typha)

如果输出不是预期的数量,说明有镜像没导入成功,回去看ctr images import的输出里有没有报错。这个习惯帮我省过好几次“以为导入了其实没导入”的后悔药。

最后说一个我自己的教训:离线包的版本号一定要和集群里其他组件的版本对齐。我有一次把 v3.25.0 的镜像导入了,但 YAML 用的是 v3.24.0 的清单,结果 kube-controllers 和 node 版本不一致,NetworkPolicy 同步一直报错,排查了半天才发现是版本混用。从那以后,我每次做离线包都会在文件名和目录名里带上完整版本号,导入前先grep image:确认 YAML 里的版本和 tar 包里的完全一致。这个习惯看起来笨,但比事后翻日志找原因省事得多。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/14 9:14:20

微电网双层调度优化:MATLAB实现与工程实践

1. 项目背景与核心价值 微电网作为分布式能源的重要载体&#xff0c;其调度优化一直是能源领域的重点研究方向。传统单层调度模型往往难以兼顾经济性和鲁棒性&#xff0c;而多时间尺度滚动优化通过分层决策机制&#xff0c;能够有效解决可再生能源出力不确定性与负荷波动带来的…

作者头像 李华
网站建设 2026/10/14 9:14:07

最长对称子串问题解析与中心扩展法实现

1. 最长对称子串问题概述在字符串处理领域&#xff0c;最长对称子串&#xff08;Longest Symmetric Substring&#xff09;是一个经典算法问题。给定一个字符串&#xff0c;我们需要找出其中最长的连续子串&#xff0c;这个子串正读和反读都相同。例如字符串"abba"中…

作者头像 李华
网站建设 2026/10/14 9:13:13

职场向上汇报三招:让你的努力被领导看见

在单位&#xff0c;3招让领导知道你干了很多活不知道你有没有这种经历&#xff1a;明明忙了一整天&#xff0c;活儿一点没少干&#xff0c;可到了总结汇报的时候&#xff0c;领导一脸茫然地看着你&#xff0c;仿佛你这一周都在摸鱼。反而是隔壁工位那位&#xff0c;活儿干得也就…

作者头像 李华
网站建设 2026/10/14 9:12:54

wpa_supplicant 实战:Linux 无线网络认证配置与排查指南

wpa_supplicant 不是个小工具&#xff0c;但它绝对是被低估的那个。大多数人第一次碰它&#xff0c;都是在 Linux 笔记本上插着无线网卡却发现图形界面连不上 Wi-Fi&#xff0c;然后被人甩过来一句“用 wpa_supplicant 手动连”。这一试&#xff0c;就再也不想碰图形工具了。我…

作者头像 李华
网站建设 2026/10/14 9:12:53

VSCode配置LaTeX的四层架构与工程化实践

1. 这不是“装个插件就完事”的事&#xff1a;为什么VSCode配LaTeX值得花两小时认真搞懂你搜“VSCode配置LaTeX”&#xff0c;首页跳出来的教程大多长这样&#xff1a;“安装LaTeX Workshop插件→装TeX Live→改settings.json→编译成功&#xff01;”——然后戛然而止。我试过…

作者头像 李华
网站建设 2026/10/14 9:12:51

DSGE模型的信息鲁棒框架构建与经济预测应用

1. 项目概述在经济预测领域&#xff0c;动态随机一般均衡&#xff08;DSGE&#xff09;模型一直是政策制定者和研究者的重要工具。然而&#xff0c;传统DSGE模型建立在"完全信息"这一理想化假设之上&#xff0c;这与现实经济中普遍存在的信息不对称、信息滞后等问题形…

作者头像 李华