简介面向Kubernetes集群管理员、运维工程师及容器网络学习者这份资源打包了Calico v3.20.6版本的四个核心组件镜像和配套的YAML部署清单用于在集群中快速启用容器网络、实现Pod间通信与细粒度网络策略管控。资源包共5个文件以tar镜像包为主分别对应Calico Node、CNI插件、控制器和FlexVol卷插件另含一份可直接执行的YAML定义涵盖DaemonSet、策略控制器、BGP及网络策略等关键配置。整体体积96.68MB便于离线导入与私有化交付目前已有1083人学习下载。使用者只需导入镜像并应用配置文件即可快速构建一套具备跨节点路由、策略隔离和IP地址管理能力的网络环境大幅降低部署门槛尤其适合多租户、多集群或安全合规要求较高的生产场景。1. 装一次Calico v3.20.6就够你受的镜像、编排文件一个都不能少Kubernetes 装完网络插件才发现集群无法通信这类事我在实验室里碰过不下五回。Calico 作为 Kubernetes 最常见的 CNI 插件之一v3.20.6 是很多还在跑旧版集群的团队长期停留的版本它稳定、够用但部署时有自己的脾气容器镜像和 calico.yaml 编排文件必须配套版本错一位Pod 之间就互相找不到。这篇文章是我实际配置一套模拟项目X环境的完整记录覆盖镜像下载、私有仓库分发、编排文件参数调整和装完之后的验证方式。你照着做从空环境到 Pod 网络互通大概半小时。卡在拉镜像超时、Pod 起不来、IP 池冲突这些问题的人可以直接跳去第 5 章看排错记录。2. 环境准备与版本选择三个会翻车的细节先解决掉2.1 Kubernetes 版本匹配v3.20.6 的边界在哪Calico v3.20.6 官方支持到 Kubernetes v1.24 及以下版本更高版本的集群装上之后 Kubelet 的网络检查可能直接报错。我最初的翻车经历就来自这个版本差某集群跑的是 v1.26我把 Calico 3.20 的 yaml 直接 applyPod 能创建但网络无法连通查不到原因最后翻官方兼容矩阵才确认是 Calico 版本太旧不支持新 K8s 的 Pod 安全策略与 API 变更。套用之前必须确认三点Kubelet 版本、API Server 版本、节点系统架构。检查命令kubectl version --short 2/dev/null || kubelet --version kubectl get nodes -o wide输出里Server Version如果高于 v1.24建议换 v3.25 或 v3.26 版本再回来。内部离线环境如果只有一个镜像包也要先看集群版本再决定是否导入。注意kubectl version --short在新版客户端里可能不生效改用下面这种完整输出kubectl version --outputyaml参数说明--outputyaml会同时打印 client 和 server 的完整版本信息方便对照 Calico 兼容矩阵。加-o wide看节点信息时能看到每台节点的内网 IP、操作系统和内核版本三台机器系统不一致时尤其值得检查。2.2 etcd 还是 Kubernetes API两种数据存储的取舍Calico v3.20.6 同时支持 Kubernetes API 直存和 etcd 存储两种模式。集群网络出问题后优先检查编排文件类型因为你一旦选定了存储模式后面想切换就得从头重建 Calico。我比较常用的模式是 Kubernetes API 数据存储因为大多数集群已经用它做核心数据存放。对应的编排文件是calico.yaml它不要求额外部署 etcd少维护一个组件。而 etcd 模式需要额外管理一套 etcd 集群。两种模式在镜像上完全一样区别只在编排文件内的配置字段存储模式编排文件部署额外组件适用场景Kubernetes APIcalico.yaml无新建集群、规模不大、不想管 etcdetcdcalico-etcd.yamletcd 集群已有 etcd 基础设施、大规模集群2.3 镜像 tag 清单少拉一个镜像整个集群都起不来Calico 的组件不是一个镜像而是完整的一组。只拉 calico-node 或只拉 cni 肯定跑不起来实际部署时至少需要calico/cni、calico/node、calico/kube-controllers三个。如果启用了 IPIP 跨子网通信默认模式就是 IPIP它不需要额外镜像但 pod 内的calico-node进程会更消耗 CPU。这套资源里的镜像 list 基本按官方部署顺序整理# 检查当前节点架构 uname -m # x86_64 对应 amd64aarch64 对应 arm64架构不匹配这个问题尤其隐蔽在一台 ARM 的机器上拉了一份 amd64 镜像导到私有仓库后节点拉取时不会报错但关键命令全部段错误。所以导入前先用uname -m确认架构再核对镜像 manifest 里的 arch 标签。常见做法是只保留与本机一致的架构标签避免仓库里多份镜像占用存储。3. 容器镜像下载与私有仓库分发离线环境的关键一步3.1 镜像清单核对与导入识别全部依赖拿到资源包后先解压看结构。这套资源里的镜像文件一般是 tar 压缩格式我通常在 master 节点上操作。列表会包含若干镜像 tar 文件和一个calico.yaml编排文件。导入前先确认节点上有没有 Docker 或 containerddocker version 2/dev/null || ctr version 2/dev/nullDocker 环境用docker loadcontainerd 环境用ctr -n k8s.io导入。注意 containerd 导入时必须指定命名空间k8s.io是 kubelet 读取镜像的默认命名空间导入到默认命名空间会导致 kubelet 拉取不到镜像。# Docker 导入方式 docker load -i calico-cni-v3.20.6.tar docker load -i calico-node-v3.20.6.tar docker load -i calico-kube-controllers-v3.20.6.tar # containerd 导入方式 ctr -n k8s.io images import calico-cni-v3.20.6.tar参数说明-i指定 tar 文件路径containerd 的-n k8s.io是命名空间参数漏掉会导致 kubelet 看不到镜像。导入完成的镜像通常是calico/cni:v3.20.6或quay.io/calico/cni:v3.20.6格式用docker images | grep calico可以核对。3.2 镜像重打标签解决从 docker.io 到私有仓库的命名迁移机器有外网时我习惯直接把镜像推到内部的 Harbor 或 Registry 仓库这样所有节点统一从私有仓库拉取不依赖公网连通性。操作很简单重打标签再推送# tag 成你的私有仓库地址 docker tag quay.io/calico/cni:v3.20.6 registry.example.com/calico/cni:v3.20.6 docker tag quay.io/calico/node:v3.20.6 registry.example.com/calico/node:v3.20.6 docker tag quay.io/calico/kube-controllers:v3.20.6 registry.example.com/calico/kube-controllers:v3.20.6 # 推送repeat 可加可不加 docker push registry.example.com/calico/cni:v3.20.6 docker push registry.example.com/calico/node:v3.20.6 docker push registry.example.com/calico/kube-controllers:v3.20.6参数说明tag 的格式是仓库地址/项目名/镜像名:版本号。推送前先docker login到目标仓库否则 push 会报权限错误。注意这个环节容易犯的错是只改 cni 和 node 的 tag忘了 kube-controllers导致最后 controllers 镜像依旧从外网拉取节点全部拉取超时。3.3 calico.yaml 文件里的 image 替换推送完镜像还不够编排文件里写死的镜像地址必须改成你的私有仓库地址。v3.20.6 的 calico.yaml 里有三处 image 字段分别对应 cni、node、kube-controllers。全部image:开头的位置都要改。我用 sed 批量替换过多次sed -i s|docker.io/calico/|registry.example.com/calico/|g calico.yaml # 核对是否替换干净 grep -n image: calico.yaml输出应该只剩registry.example.com/...开头的内容。很多人在这一步漏改结果是 calico-node 启动正常cni 插件却一直创建失败查日志才发现容器试图从公网拉镜像却拉不到。注意有些编排文件里镜像地址带quay.io前缀要再跑一遍sed -i s|quay.io/calico/|registry.example.com/calico/|g。3.4 私有仓库证书配置节点拉镜像前的最后一个门槛如果是自建仓库节点拉镜像时必须信任仓库证书。Kubelet 默认拒绝非 https 或未信任证书的仓库。常见做法是把证书放到/etc/docker/certs.d/或/etc/containerd/certs.d/对应目录# Docker 环境 mkdir -p /etc/docker/certs.d/registry.example.com cp ca.crt /etc/docker/certs.d/registry.example.com/ca.crt systemctl restart docker # containerd 环境 mkdir -p /etc/containerd/certs.d/registry.example.com cp ca.crt /etc/containerd/certs.d/registry.example.com/ca.crt systemctl restart containerd这里面最隐蔽的是证书名必须是ca.crt。我之前手误写成registry-ca.crtDocker 完全不看这个文件名依旧拉起失败。先把证书命名搞定否则后续所有镜像拉取全部超时排查起来很绕。4. 部署 calico.yaml 编排文件安装参数逐一拆开说明4.1 网络模式与 IP 池参数默认值不一定适合你的网段Calico v3.20.6 默认走 IPIP 跨界点通信Pod IP 默认段是192.168.0.0/16。但这个段跟很多公司内部网络冲突。我在某套环境上初始部署时没管这个默认值结果 Pod 无法访问公司内网服务器报错全部是连接超时。改 IP 池的操作在calico.yaml的 Deployment 里位置是CALICO_IPV4POOL_CIDR环境变量# 修改后示例 - name: CALICO_IPV4POOL_CIDR value: 10.244.0.0/16这个参数直接决定了所有 Pod 从哪个网段拿地址。改成跟已有业务不冲突的段再继续别等部署完才后知后觉发现冲突。我一般先拿ip route看本机有没有已经占用的地址段再对照CALICO_IPV4POOL_CIDR选。除了 CIDR 之外还有一个IP_AUTODETECTION_METHOD参数默认留空让 Calico 自动选节点网卡但节点的网卡多了之后容易选错建议明确指定。# 指定从哪块网卡探测 IP - name: IP_AUTODETECTION_METHOD value: interfaceeth.*注意eth.*是正则写法如果你机器上的网卡名是ens160或enp1s0需要改成interfaceen.*或者直接写网卡名interfaceeth0。自动探测在这种场景里是黑匣子不如手动指定来得可控。4.2 部署编排文件从 apply 到观察 DaemonSet 状态配置改完后进入正式部署。整个操作不复杂但需要连续观察状态kubectl apply -f calico.yaml这一步会创建 calico 的 DaemonSet、Deployment、ServiceAccount、RBAC 相关资源。apply 完成并不代表网络就通了Calico 的每个节点都要以 Pod 的形式跑起来。观察命令kubectl get pods -n kube-system -l k8s-appcalico-node -o wide等所有calico-nodePod 进入Running状态后再检查 kube-controllerskubectl get pods -n kube-system -l k8s-appcalico-kube-controllers4.3 部署后的关键确认项calicoctl 能用的前提Calico 自带命令行工具 calicoctl用来查看 IP 池、节点状态、BGP 路由。在 v3.20.6 里calicoctl以二进制方式放置在各节点。需要连接 etcd 或 Kubernetes API 才能用。用 Kubernetes API 数据存储方式时需要先配置/etc/calico/calicoctl.cfgapiVersion: projectcalico.org/v3 kind: KubeConfig spec: kubeconfig: /root/.kube/config然后验证calicoctl node status calicoctl get ipPoolcalicoctl get ipPool能看到当前所有 Pod 网段。如果这个命令能正常执行说明 Calico 的数据存储连接是通的后面排查网络故障就有了依据。我一般在这个阶段顺手确认calicoctl node status里每个节点的 BGP 会话都处于up状态。4.4 BGP 模式与 Route Reflector 的取舍跨机房的痛默认 Calico 是全互联模式节点多了之后 BGP 会话数量成平方级增长。节点超过 50 台后建议引入 Route Reflector。不过 v3.20.6 里启用 Route Reflector 需要额外配置这个资源包里的 calico.yaml 默认不含相关组件。小规模环境直接用默认配置即可不需要提前折腾。如果节点数不多但跨机房我建议先观察延迟再决定要不要调整 BGP。跨机房场景中 IPIP 封装的效率损失比同机房大但把 IPIP 关掉可能导致跨机房互通失败。5. 常见问题与排查Calico 部署中我自己踩过的坑5.1 现象calico-node Pod 一直 CrashLoopBackOff日志里报Error querying BIRD原因Calico 启动时 Bird 进程依赖/var/run/calico、/var/lib/calico等宿主目录。如果这些目录不存在或权限不对bird 会拒绝启动。常见于某些 slim 镜像里加了只读根文件系统限制。解决在 calico.yaml 的calico-node容器里确认挂载了宿主目录/var/run/calico、/var/lib/calico和/var/log/calico。如果是安全策略拦截了挂载操作尝试手动创建这些目录再重建 Pod。mkdir -p /var/run/calico /var/lib/calico /var/log/calico kubectl delete pod -n kube-system -l k8s-appcalico-node5.2 现象Pod 创建成功但跨节点访问不通集群 DNS 解析时好时坏原因最常见的是 IP 池网段与宿主机现有路由冲突。比如宿主机所在的192.168.x.x段被设为默认的 Pod 网段数据包被节点本机路由拦截永远走不到 veth 对端。在 master 节点 curl Pod IP 时能通但 worker 节点不通基本可以锁定是这个原因。解决改CALICO_IPV4POOL_CIDR的值然后把所有 Calico 的 DaemonSet Pod 全部重建再把已有的业务 Pod 也重建一遍。旧 Pod 不会自动换 IP所以必须手动删除。kubectl set env daemonset/calico-node -n kube-system CALICO_IPV4POOL_CIDR10.244.0.0/16 kubectl rollout restart daemonset/calico-node -n kube-system kubectl delete pods --all -n your-namespace5.3 现象节点加入集群后calico-node 报timeout waiting for K8s API to report pod CIDR原因未开启 Node 自动分配 Pod 网段。Kubelet 的配置文件中缺少--allocate-node-cidrstrue或者控制器管理器中未配置--allocate-node-cidrstrue --cluster-cidrPod网段。新节点使用kubeadm加入后这条配置不会自动同步导致 Calico 无法从 API 获取该节点的 pod CIDR。解决在 kube-controller-manager 的启动参数里添加--allocate-node-cidrstrue和--cluster-cidr10.244.0.0/16。kubeadm 部署的在/etc/kubernetes/manifests/kube-controller-manager.yaml中改改完后容器会自动重启。重启完再确认节点信息里有 pod CIDRkubectl get node node-name -o jsonpath{.spec.podCIDR}输出如果为空说明还没配好如果有 CIDR再等待 calico-node 自动重试。5.4 现象镜像命令行执行 calicoctl node status报Failed to connect to etcd原因普通calicoctl默认查找系统里是否配置了ETCD_ENDPOINTS没配置的情况下退回去找默认配置。某些版本的 calicoctl 需要显式设置数据存储类型。这套 v3.20.6 资源里的 calico.yaml 没有 configmap 覆盖这部分所以必须准备好calicoctl.cfg文件。解决按前一章的/etc/calico/calicoctl.cfg配置写好如果环境变量里有旧的ETCD_ENDPOINTS配置先清除再重试。unset ETCD_ENDPOINTS export CALICO_DATASTORE_TYPEkubernetes export KUBECONFIG/root/.kube/config calicoctl node status5.5 现象新拉取的镜像被节点用公网地址拉取日志里显示not found原因yaml 里的镜像地址只改了一部分比如只改了 node 镜像的地址但 cni 镜像仍指向quay.io或docker.io。kubelet 在节点上重新拉取时走外网网络不通或仓库无此 tag 就直接失败。解决再检查一遍所有image:行grep -n image: calico.yaml逐行确认不要肉眼扫一遍就完事。grep -n image: calico.yaml | grep -v registry.example.com没有输出说明全部替换干净。这步做干净了后面少受很多罪。6. 装完跑通的验证方法从节点状态到业务流量部署完成并不代表网络真的可用完整验证花不了十分钟我会按顺序做全套。建议你保留这份清单每次配完 Calico 都走一遍。先看静态状态。执行kubectl get pods -n kube-system -l k8s-appcalico-node -o wide所有节点上的 calico-node 都处于 RunningREADY 列是 1/1说明进程层面是健康的。再看 controllers 同样处于 Running说明数据存储链路正常。然后用 calicoctl 验证 BGP 会话calicoctl node status每个节点对应一行状态为up。如果某节点状态是down先检查本节点的 calico-node 日志大概率是网卡探测选错了接口。第二步验证跨节点通信。在任一节点上创建一个测试 Podkubectl run nettest -it --imagebusybox --rm --restartNever -- sh进入 Pod 后查看自己的 IP 并 ping 另一节点上的 Pod IP。ping 通说明跨节点网络没问题。但还得测 DNS。在同一个 Pod 里执行nslookup kubernetes.default.svc.cluster.local能解析出 ClusterIP 说明 kube-dns 的请求能被 Calico 正确转发。这一步如果卡在超时往往是 kube-proxy 的规则或 conntrack 有问题跟 Calico 关系不大但要先确认 CNI 是通的否则后面白查。第三步最接近真实场景部署一个 Deployment其它节点访问它的 ClusterIP。我习惯用模拟项目X环境来测比如起两个不同节点的 Nginx Pod从第三个 Pod 里通过 ClusterIP 访问 Nginx。配置好之后 curl 能返回页面说明service 转发路径完整我最常用这个作为验收信号。第四步观察 native 路由和 tunnel 模式是否如预期工作。当 IPIP 开启时ip addr会多出一个tunl0接口如果关闭了 IPIP就不该有该接口。跨网段 ping Pod IP 时用traceroute看路径是否走了虚拟隧道没走隧道但通了说明配置了正确的 BGP。从那次在模拟项目X环境里配置 Calico v3.20.6 开始我每次配完网络插件都会强制走一遍 Pod 到 Pod、Pod 到 Service 的连通性全链路验证。就算状态全是 Running没有业务流量打一次心里的石头始终落不了地。整套流程下来也就十几分钟但后面省掉的时间是它的好几倍。希望帮到你。本文还有配套的精品资源点击获取