☰
Calico v3.20.6部署实战:Kubernetes网络插件镜像与编排详解
2026/10/15 20:15:46 网站建设 项目流程

简介:面向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 直接 apply,Pod 能创建但网络无法连通,查不到原因,最后翻官方兼容矩阵才确认是 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 --output=yaml

参数说明:--output=yaml会同时打印 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无新建集群、规模不大、不想管 etcd
etcdcalico-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 对应 amd64,aarch64 对应 arm64

架构不匹配这个问题尤其隐蔽:在一台 ARM 的机器上拉了一份 amd64 镜像,导到私有仓库后,节点拉取时不会报错,但关键命令全部段错误。所以导入前先用uname -m确认架构,再核对镜像 manifest 里的 arch 标签。常见做法是只保留与本机一致的架构标签,避免仓库里多份镜像占用存储。

3. 容器镜像下载与私有仓库分发:离线环境的关键一步

3.1 镜像清单核对与导入:识别全部依赖

拿到资源包后先解压看结构。这套资源里的镜像文件一般是 tar 压缩格式,我通常在 master 节点上操作。列表会包含若干镜像 tar 文件和一个calico.yaml编排文件。导入前先确认节点上有没有 Docker 或 containerd:

docker version 2>/dev/null || ctr version 2>/dev/null

Docker 环境用docker load,containerd 环境用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.crt,Docker 完全不看这个文件名,依旧拉起失败。先把证书命名搞定,否则后续所有镜像拉取全部超时,排查起来很绕。

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: "interface=eth.*"

注意eth.*是正则写法,如果你机器上的网卡名是ens160或enp1s0,需要改成interface=en.*或者直接写网卡名interface=eth0。自动探测在这种场景里是黑匣子,不如手动指定来得可控。

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-app=calico-node -o wide

等所有calico-nodePod 进入Running状态后,再检查 kube-controllers:

kubectl get pods -n kube-system -l k8s-app=calico-kube-controllers

4.3 部署后的关键确认项:calicoctl 能用的前提

Calico 自带命令行工具 calicoctl,用来查看 IP 池、节点状态、BGP 路由。在 v3.20.6 里,calicoctl以二进制方式放置在各节点。需要连接 etcd 或 Kubernetes API 才能用。用 Kubernetes API 数据存储方式时,需要先配置/etc/calico/calicoctl.cfg:

apiVersion: projectcalico.org/v3 kind: KubeConfig spec: kubeconfig: /root/.kube/config

然后验证:

calicoctl node status calicoctl get ipPool

calicoctl 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-app=calico-node

5.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_CIDR=10.244.0.0/16 kubectl rollout restart daemonset/calico-node -n kube-system kubectl delete pods --all -n <your-namespace>

5.3 现象:节点加入集群后,calico-node 报timeout waiting for K8s API to report pod CIDR

原因:未开启 Node 自动分配 Pod 网段。Kubelet 的配置文件中缺少--allocate-node-cidrs=true,或者控制器管理器中未配置--allocate-node-cidrs=true --cluster-cidr=<Pod网段>。新节点使用kubeadm加入后,这条配置不会自动同步,导致 Calico 无法从 API 获取该节点的 pod CIDR。

解决:在 kube-controller-manager 的启动参数里添加--allocate-node-cidrs=true和--cluster-cidr=10.244.0.0/16。kubeadm 部署的在/etc/kubernetes/manifests/kube-controller-manager.yaml中改,改完后容器会自动重启。重启完再确认节点信息里有 pod CIDR:

kubectl 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_TYPE=kubernetes export KUBECONFIG=/root/.kube/config calicoctl node status

5.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-app=calico-node -o wide

所有节点上的 calico-node 都处于 Running,READY 列是 1/1,说明进程层面是健康的。再看 controllers 同样处于 Running,说明数据存储链路正常。然后用 calicoctl 验证 BGP 会话:

calicoctl node status

每个节点对应一行,状态为up。如果某节点状态是down,先检查本节点的 calico-node 日志,大概率是网卡探测选错了接口。

第二步验证跨节点通信。在任一节点上创建一个测试 Pod:

kubectl run nettest -it --image=busybox --rm --restart=Never -- 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,没有业务流量打一次,心里的石头始终落不了地。整套流程下来也就十几分钟,但后面省掉的时间是它的好几倍。希望帮到你。

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

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

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

立即咨询