
简介面向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、DaemonSetcalico-node、Deploymentcalico-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.yamlcurl -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.6calico/node:v3.20.6calico/kube-controllers:v3.20.6calico/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 因为需要操作节点网络和 iptablescalico-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.6calico/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: interfaceeth.*这里interfaceeth.*是正则表达式如果你的节点网卡名是 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 镜像打上仓库地址的 tagdocker 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 模板加上这个 secretkubectl create secret docker-registry tcr-secret -n kube-system \ --docker-serverccr.ccs.tencentyun.com \ --docker-username你的账号ID \ --docker-password访问凭证密码再修改 calico-node DaemonSetkubectl 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/16Calico 默认再给 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 与已推送镜像 tagcalico-node 一直 CrashLoopBackOffIP 自动检测出错或权限不足查看 pod 日志确认网卡正则跨节点 Pod 不通Pod 网段冲突或 BGP/VXLAN 配置不对查节点路由表、检查 IP 池 CIDR节点无法拉取私有仓库镜像缺少 imagePullSecret 或证书不受信检查 secret 是否注入到 DaemonSetdocker push 到腾讯云失败登录态失效或命名空间不存在重新 docker login确认命名空间已创建每个人的网络环境不一样遇到的具体报错可能千奇百怪但排查链条基本一致先定位镜像问题再看配置最后看路由和网络策略。按照这个顺序来能少走很多弯路。最后再分享一个小技巧我会把 Calico 的版本信息、镜像 digest 列表、calico.yaml 的校验值一起存到一个MANIFEST.txt文件里放进交付包。这样后期不管是集群出问题要对照版本还是做安全审计都不需要再回头猜当时用的是哪个镜像。如果你也常做多集群交付这套“版本清单 镜像包 定制 yaml”的三件套组合基本能覆盖绝大多数场景。本文还有配套的精品资源点击获取