☰
Calico离线部署实战:镜像下载、定制YAML与推送私有仓库全攻略
2026/10/19 15:17:00 网站建设 项目流程

简介:面向Kubernetes集群管理员与运维工程师,Calico v3.20.6离线部署资源包提供集群网络所需的完整组件与配置,可解决Pod间通信、网络策略控制及跨节点BGP路由等场景下的部署难题。压缩包共5个文件,包含4个tar格式容器镜像和1个核心配置文件calico.yaml。四个镜像分别对应节点守护进程、CNI插件、控制器和FlexVol挂载组件:node负责为每台节点的Pod分配地址并实施策略,cni用于在Pod创建时配置网络接口,kube-controllers处理网络策略与地址池管理,pod2daemon-flexvol则负责将配置卷挂载到需要的Pod中。calico.yaml覆盖DaemonSet、CNI配置、策略控制器及BGP参数,可通过kubectl apply快速集成到集群。所有组件版本统一为v3.20.6,避免版本错配导致的兼容问题。包体约96.68MB,适合内网、离线或对安全要求较高的多租户环境,无需逐一下载镜像。已有1075人学习,资源镜像与配置配套,部署时只需导入镜像并应用配置,即可获得支持细粒度网络策略的Kubernetes网络基底,有效提升集群网络部署效率。 做 Kubernetes 集群网络,Calico 几乎绕不开。这几个月我一直在帮不同的环境搭容器平台,其中碰到的需求高度一致:集群能连外网的时候,直接一条kubectl apply -f拉默认 Calico 清单就能跑起来;可一旦到了内网环境、离线交付,或者需要把镜像统一收编到企业私有仓库的时候,官方默认流程就完全不够用了。我这次整理的正是这么一套实践:Calico v3.20.6 版本容器镜像 + calico.yaml 文件,把从下载镜像、安全校验、改写清单到推送到腾讯云容器镜像服务的全链路讲清楚。

这套东西适合谁?如果你是刚接触 Kubernetes、第一次自己拉 Calico 镜像部署的新手,你能照着步骤把镜像下载和清单改好;如果你已经维护过几个集群,但每次都被离线镜像、私有仓库、镜像地址替换这类事折腾,本文的故障排查和经验提示也能帮上忙。下文不是官方文档翻译,是我在实际操作中把该踩的坑都踩过一遍之后的总结。

1. 项目概览与实际需求分析

1.1 为什么是 v3.20.6

在讨论怎么下载镜像之前,我建议先明确版本。Calico 的版本迭代不算慢,v3.20 这个分支属于比较稳定的老分支,兼容当时主流的 Kubernetes 1.18 到 1.22 附近版本。相比追新版本,很多生产环境更倾向锁定一个已经验证过的稳定版本,避免后续 API 变更带来理解成本。v3.20.6 正是在 v3.20.0 基础上发布的补丁版本,修复了上一阶段反馈的部分问题,整体行为没有大的破坏性改变,所以成了不少离线环境、交付项目的首选版本。

版本选择还会直接影响 calico.yaml 的获取方式。Calico 官方在 GitHub 发布页上会为每个版本单独维护一份 manifests 文件,如果你直接去 master 分支下载 calico.yaml,里面镜像 tag 可能是最新版本,和本地已经准备好的 v3.20.6 镜像对不上,安装时就会出现ImagePullBackOff。这个问题我在实际环境里遇见过不止一次,所以本文后面会专门讲“怎么拿到和镜像 tag 完全一致的 yaml 文件”。

1.2 calico.yaml 在集群安装中的位置

calico.yaml 并不是一个普通配置文件,它是包含 Calico 全部资源对象的编排清单,简单来说,里面定义了好几十个 Kubernetes 资源:自定义资源定义 CRD、ServiceAccount 和 RBAC 权限、ConfigMap、DaemonSet(calico-node)、Deployment(calico-kube-controllers)、以及网络策略相关资源。

我通常把 calico.yaml 理解成一个“一键安装套件”:kubectl apply -f calico.yaml执行后,Kubernetes 会根据 YAML 里的定义依次创建这些对象。calico-node 以 DaemonSet 方式在每个节点上启动,负责维护节点的网络路由、ARP 表、安全策略规则;calico-kube-controllers 负责监控集群状态和响应策略变更。正因为它承载了网络核心功能,我们在离线部署时不能拿过来直接 apply,必须先确认两件事:镜像 tag 是否本地存在,镜像地址是否指向当前环境能拉取的仓库。

1.3 一套完整的安全交付链路

很多人以为“下载镜像”就是把镜像docker pull下来就行。真到了离线交付,你会面临几个连环问题:第一,Calico 的组件不止一个镜像,至少包括 calico/cni、calico/node、calico/kube-controllers,甚至还有 calico/pod2daemon-flexvol,漏一个都不行;第二,镜像下了之后不能直接用,需要做安全校验,确认镜像确实来自官方渠道且没有被动过手脚;第三,如果集群节点不能访问 Docker Hub,就需要把镜像推送到企业自己的私有仓库,这就涉及登录、tag、push 到腾讯云容器镜像服务这一套流程。

结合最近的镜像安全、容器安全话题,我的建议是不要只图“能拉下来”,而是要拉得明白、推得安全、装得可回溯。下面从实际操作开始讲,每一步都提供具体命令和可复现的方法。

2. 下载指定版本容器镜像的硬核操作

2.1 先定位一份完整的镜像清单

我在操作新环境时,会先把 calico.yaml 下载下来,然后再从 yaml 里抠出所有镜像列表。与其凭记忆去 Docker Hub 挨个搜索 tag,不如直接看官方清单,这样最准。先获取官方 v3.20.6 的 calico.yaml:

curl -L https://raw.githubusercontent.com/projectcalico/calico/v3.20.6/manifests/calico.yaml -o calico-v3.20.6.yaml

然后执行:

grep -n "image:" calico-v3.20.6.yaml

在 v3.20.6 里,典型的输出通常包含下面这类镜像:

  • calico/cni:v3.20.6
  • calico/node:v3.20.6
  • calico/kube-controllers:v3.20.6
  • calico/pod2daemon-flexvol:v3.20.6

如果你的网络规模较大,打算启用 Typha 组件,那么镜像清单里还会出现calico/typha:v3.20.6。我建议在任何环境里都以实际 yaml 中 grep 出的结果为准,不要想当然。

2.2 拉取镜像导出与导入

镜像清单确定后,在能访问 Docker Hub 的机器上执行批量拉取。这一步建议指定平台参数,避免在多架构环境里拉到不符合节点架构的镜像:

docker pull --platform linux/amd64 calico/cni:v3.20.6 docker pull --platform linux/amd64 calico/node:v3.20.6 docker pull --platform linux/amd64 calico/kube-controllers:v3.20.6 docker pull --platform linux/amd64 calico/pod2daemon-flexvol:v3.20.6

如果你用的是 containerd 运行时,而不是 Docker,拉下来的镜像通过 docker save 导成 tar 文件后,需要在目标节点上用ctr导入。我常用的导出命令是这个:

docker save -o calico-images-v3.20.6.tar \ calico/cni:v3.20.6 \ calico/node:v3.20.6 \ calico/kube-controllers:v3.20.6 \ calico/pod2daemon-flexvol:v3.20.6

到了离线节点,用 Docker 环境就执行:

docker load -i calico-images-v3.20.6.tar

如果用 containerd 作为 Kubernetes 容器运行时,需要导入到 k8s.io 命名空间,否则 kubelet 不一定能识别:

ctr -n k8s.io images import calico-images-v3.20.6.tar

这一步容易忽略,因为ctr images import不带-n k8s.io时,镜像会导入到默认命名空间,而 Kubernetes 实际使用的镜像命名空间是 k8s.io,结果就是明明 load 成功了,Pod 还是提示拉取不到镜像。

2.3 镜像安全与容器安全检查

镜像安全不是一句空喊的口号,在网络交付中尤其重要。拉取镜像前,我习惯先用docker buildx imagetools inspect查看远程镜像的 digest 信息,这里注意docker buildx在较新版本 Docker 中已经内置:

docker buildx imagetools inspect docker.io/calico/node:v3.20.6

记录输出的Digest值,再和拉取到本地后的镜像 ID 进行比对。本地镜像的 ID 其实就是镜像配置层的 SHA256 摘要,如果远程摘要和本地摘要来源一致,基本可以确认镜像在传输过程中没有被篡改。

进一步做漏洞扫描的话,可以用 Trivy 这类开源工具:

trivy image --severity HIGH,CRITICAL docker.io/calico/node:v3.20.6

扫描结果如果在合理范围,再进入下一步。不要因为 Calico 是常见开源项目就跳过这一步,尤其是从非官方源下载或经过第三方网盘中转时,镜像内容有没有被改动完全不可知。容器安全方面,Calico 因为需要操作节点网络和 iptables,calico-node 容器本身会要求特权模式,这个没法完全避免。我们能做到的是尽量使用官方镜像、锁定版本和摘要、通过 Pod Security Admission 限制集群内其他工作负载的权限,避免安全策略被绕过。

3. 手工定制 calico.yaml:三处必改点

3.1 下载一份干净的 v3.20.6 描述文件

官方 v3.20.6 的清单文件地址前面已经给过。我建议把下载后的文件保存成带版本号的名字,例如calico-v3.20.6.yaml,不要直接叫 calico.yaml,因为你可能后面会在同一台机器上保留多个版本,方便对比差异和回滚。下载完成后,先检查文件内容是否完整,最简单的办法是看 CRD 定义数量以及末尾是否有资源对象被截断。

wc -l calico-v3.20.6.yaml

正常情况下这个文件大概有几百行。如果行数明显太少,说明下载内容不完整,应重新下载。

3.2 把镜像仓库替换成你的私服地址

这里的“私服地址”可能是企业 Harbor、Nexus,也可能是腾讯云容器镜像服务。核心思路是全局替换镜像前缀。例如你准备把镜像推到腾讯云的ccr.ccs.tencentyun.com/calico路径下,那么需要把:

  • calico/cni:v3.20.6替换为ccr.ccs.tencentyun.com/calico/cni:v3.20.6
  • calico/node:v3.20.6替换为ccr.ccs.tencentyun.com/calico/node:v3.20.6
  • 以此类推

我通常直接使用 sed 做批量替换,但注意替换时要精确到/边界,避免出现calico/cni/v3.20.6之类错误路径。实际操作中,我会写成这样:

sed -i 's#calico/cni#ccr.ccs.tencentyun.com/calico/cni#g; s#calico/node#ccr.ccs.tencentyun.com/calico/node#g; s#calico/kube-controllers#ccr.ccs.tencentyun.com/calico/kube-controllers#g; s#calico/pod2daemon-flexvol#ccr.ccs.tencentyun.com/calico/pod2daemon-flexvol#g' calico-v3.20.6.yaml

这里我刻意用#作为分隔符,因为镜像地址里包含/,如果用默认/分隔符,sed 会直接报错。替换完以后,再执行一次 grep 确认每个镜像地址都带上了新前缀。这种看似琐碎的检查,在真实环境里能省下很多排障时间。

3.3 按网络模式调整 IP 池与网卡发现参数

改完镜像地址只能保证镜像拉取没问题,但要真正把网络跑通,还需要关注两个参数。第一个是 IP 池定义,在 calico.yaml 里通常会看到CALICO_IPV4POOL_CIDR,默认值是192.168.0.0/16。如果你的集群物理网络或现有子网已经占了这段地址,就要改成不冲突的网段,例如:

- name: CALICO_IPV4POOL_CIDR value: "10.244.0.0/16"

第二个是 IP 自动检测策略。很多节点不止一块网卡,如果 Calico 自动选错了网卡,节点就会用错误 IP 注册路由,然后出现跨节点网络不通。我建议在 calico-node 容器的环境变量部分显式指定:

- name: IP_AUTODETECTION_METHOD value: "interface=eth.*"

这里interface=eth.*是正则表达式,如果你的节点网卡名是 ens、enp 之类的,就改成对应的正则。另外,如果你选用 IPIP 或 VXLAN 封装模式,需要确认CALICO_IPV4POOL_IPIP和CALICO_IPV4POOL_VXLAN这两个参数符合预期,避免封装类型与物理网络约束不匹配,导致性能下降或节点无法通信。

4. 把镜像推送到腾讯云容器镜像服务的全过程

4.1 在 TCR 中创建命名空间与镜像仓库

腾讯云容器镜像服务有两种常见形态,一个是经典的个人版 CCR,另一个是 TCR 企业版。个人版使用公共入口ccr.ccs.tencentyun.com,企业版则一般是类似tcr.xxxx.tencentcloudcr.com的专属域名。不论选哪个,我建议先规划好命名空间。命名空间相当于镜像仓库的顶层目录,通常一个项目或一个业务团队一个命名空间,例如infra、calico。

在控制台完成命名空间和镜像仓库创建后,建议立即配置访问凭证。腾讯云控制台里有“访问凭证”或“长期凭证”功能,可以生成 docker login 时要用到的密码。这个密码不是腾讯云登录密码,而是专门给 Docker 客户端用的。把它存到自己的密钥管理工具里,不要在 yaml 或 shell 脚本里明文硬编码。

4.2 docker login tag push 的完整命令

先在本地机器登录镜像仓库:

docker login ccr.ccs.tencentyun.com

根据提示输入用户名和访问凭证密码。登录成功后,把本地 Calico 镜像打上仓库地址的 tag:

docker tag calico/node:v3.20.6 ccr.ccs.tencentyun.com/calico/node:v3.20.6 docker tag calico/cni:v3.20.6 ccr.ccs.tencentyun.com/calico/cni:v3.20.6 docker tag calico/kube-controllers:v3.20.6 ccr.ccs.tencentyun.com/calico/kube-controllers:v3.20.6 docker tag calico/pod2daemon-flexvol:v3.20.6 ccr.ccs.tencentyun.com/calico/pod2daemon-flexvol:v3.20.6

接着推送:

docker push ccr.ccs.tencentyun.com/calico/node:v3.20.6 docker push ccr.ccs.tencentyun.com/calico/cni:v3.20.6 docker push ccr.ccs.tencentyun.com/calico/kube-controllers:v3.20.6 docker push ccr.ccs.tencentyun.com/calico/pod2daemon-flexvol:v3.20.6

推送完成后,在控制台对应镜像仓库里应该能看到 v3.20.6 这个 tag。我习惯在这种情况下顺手把镜像的 digest 记下来,和第一节里通过官方buildx imagetools inspect拿到的摘要做比对,确保你推送到仓库的镜像是可信的。

4.3 离线集群节点如何从 TCR 拉取

镜像推到腾讯云仓库后,集群节点要么通过公网拉取,要么在 VPC 内通过内网域名拉取。多数生产集群会配置 VPC 内网访问,这样不走公网流量,速度更快也更安全。你可以先测试一下节点上能否解析并访问 TCR 的域名,例如用curl -I https://ccr.ccs.tencentyun.com/v2/看返回结果。

由于拉取私有仓库需要凭证,你需要在集群中创建imagePullSecret,然后给 calico-node、calico-kube-controllers 的 Pod 模板加上这个 secret:

kubectl create secret docker-registry tcr-secret -n kube-system \ --docker-server=ccr.ccs.tencentyun.com \ --docker-username=<你的账号ID> \ --docker-password=<访问凭证密码>

再修改 calico-node DaemonSet:

kubectl patch ds calico-node -n kube-system -p '{"spec":{"template":{"spec":{"imagePullSecrets":[{"name":"tcr-secret"}]}}}}'

calico-kube-controllers 的 Deployment 用类似方式 patch 即可。如果节点使用 containerd,也可以在/etc/containerd/config.toml里配置 registry 的 auth 信息,不过用 imagePullSecret 更贴合原生 Kubernetes 工作流,也便于集群级别统一管理。

5. 实操中容易踩的坑与排查记录

5.1 版本与镜像标签对不上

这是我遇到最多的问题。很多人从网上拷贝了一段 calico.yaml,却不知道里面镜像 tag 是latest或者 v3.19、v3.22,结果本地只准备好了 v3.20.6 的镜像,装上去必然报ErrImagePull。所以我在第一节一再强调,先把官方 v3.20.6 的 yaml 拿下来,再基于这个 yaml 去 grep 镜像清单。版本锁定要严格到小版本,不要只锁大版本。

5.2 跨主机网段不通

镜像装好、Pod 也起来了,但不同节点上的 Pod 互相 ping 不通,这种情况优先排查 Calico 的 IP 自动检测结果。可以进入 pod 或直接在节点上执行:

kubectl -n kube-system logs ds/calico-node

或者使用 calicoctl 查看节点地址:

calicoctl node status

如果发现节点注册的 IP 是内网 Docker 网桥之类的地址,那就说明 IP_AUTODETECTION_METHOD 没设对。此时回到 calico.yaml 里增加网卡正则,重新 apply,之后重启 calico-node 让配置生效。另一个常见原因是 Calico IP 池和主机网段重叠,例如物理网络已经用了192.168.0.0/16,Calico 默认再给 Pod 分配同网段地址,就会导致路由冲突。这类问题排查最快的方法是直接去看每个节点上的路由表,例如ip route | grep 192.168,一旦确认 Pod 网段重叠,就必须改掉 CALICO_IPV4POOL_CIDR,重新部署。

5.3 镜像拉取超时与私有仓库证书

离线环境里,节点拉取私有镜像可能因为网络策略或代理设置导致超时。Docker 环境可以先看/etc/docker/daemon.json里的insecure-registries是否配置了目标仓库。如果仓库使用自签名证书,Docker 客户端默认会拒认,报x509: certificate signed by unknown authority。这里我建议不要简单地把仓库加到 insecure-registries 里,虽然那样能通,但会跳过 TLS 校验,无形中放大镜像安全风险。更稳妥的做法是把私有仓库的 CA 证书放到节点系统可信证书目录,然后重启容器运行时。

如果是 containerd,需要在/etc/containerd/config.toml里给对应 registry 配置auth和ca信息。证书相关的坑比较隐蔽,但排查思路清晰:先确认节点能解析域名,再确认 80/443 端口通,最后看 TLS 握手是否报错。

5.4 常见问题速查表

现象可能原因排查方向
Pod 启动报 ImagePullBackOff镜像 tag 与本地/仓库不一致对比 calico.yaml 中镜像 tag 与已推送镜像 tag
calico-node 一直 CrashLoopBackOffIP 自动检测出错或权限不足查看 pod 日志,确认网卡正则
跨节点 Pod 不通Pod 网段冲突或 BGP/VXLAN 配置不对查节点路由表、检查 IP 池 CIDR
节点无法拉取私有仓库镜像缺少 imagePullSecret 或证书不受信检查 secret 是否注入到 DaemonSet
docker push 到腾讯云失败登录态失效或命名空间不存在重新 docker login,确认命名空间已创建

每个人的网络环境不一样,遇到的具体报错可能千奇百怪,但排查链条基本一致:先定位镜像问题,再看配置,最后看路由和网络策略。按照这个顺序来,能少走很多弯路。

最后再分享一个小技巧:我会把 Calico 的版本信息、镜像 digest 列表、calico.yaml 的校验值一起存到一个MANIFEST.txt文件里,放进交付包。这样后期不管是集群出问题要对照版本,还是做安全审计,都不需要再回头猜当时用的是哪个镜像。如果你也常做多集群交付,这套“版本清单 + 镜像包 + 定制 yaml”的三件套组合,基本能覆盖绝大多数场景。

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

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询