news 2026/10/15 20:14:21

Calico v3.20.6内网部署全攻略:版本匹配、镜像导入与网络配置

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Calico v3.20.6内网部署全攻略:版本匹配、镜像导入与网络配置

简介:Calico 是 Kubernetes 生态中主流的容器网络与网络策略开源方案。这份资源面向集群管理员与运维工程师,针对 v3.20.6 稳定版本,解决离线或内网环境下镜像获取不便、组件配置分散的问题。RAR 压缩包内共 5 个文件,包含 4 个组件镜像包和 1 个核心部署配置,整体约 96.68MB。镜像覆盖节点代理、CNI 插件、策略控制器与卷挂载扩展四类模块:节点代理负责本地路由与策略执行,CNI 插件在 Pod 创建时设置网络接口,控制器监听 Kubernetes API 并同步策略,卷插件保证配置正确挂载到目标 Pod。配置文件则将上述组件串联为完整部署清单,集中声明守护进程集、边界网关协议参数、策略对象等关键项,管理员可通过命令行一次性集成到集群,无需手动调整镜像版本。已有 1083 人学习,适合需要快速初始化生产集群网络、维护多租户隔离策略或进行标准化交付的中高级运维人员。整体结构清晰,开箱即用,能显著降低 Calico 部署排错成本,同时对理解组件协作与网络策略下发机制也有直接帮助。

1. 为什么要盯住 calico v3.20.6:版本锁定与镜像配套一起解决

Kubernetes 集群网络是玄学重灾区。去年我接手一个 K8s 1.24 集群,跨节点 Pod 间歇性不通,查到最后是 CNI 插件 calico 的 yaml 和镜像 tag 对不上——calico.yaml 里写着 v3.20.6,节点镜像却是旧的 v3.20.2,Felix 和 CNI 插件跨 patch 版本不兼容,路由表偶发错乱。节点少时根本看不出来,扩到 30 台就开始翻车。今天要装的是 calico v3.20.6 容器镜像配套 calico.yaml 文件,这两样必须一起用,镜像 tag 与 yaml 中 image 字段严格对齐。适合正用 kubeadm 搭 K8s 1.22~1.26 集群、卡在内网镜像拉取和 calico 部署参数上的开发者。装好它,Pod 网络和 NetworkPolicy 才算真正落地。

2. 部署前准备:版本兼容表、镜像清单与私有仓库三件事

2.1 先确定集群能不能用 v3.20.6

Calico 每个版本都有 K8s 大版本兼容区间。v3.20 系列官方测试覆盖 K8s 1.20~1.26 这一段,我实际线上跑得最稳的是 1.24 和 1.25。拿 v3.20.6 来说,如果集群 K8s 版本低于 1.20,建议直接放弃这个版本,回头找 v3.19 或更早;如果高于 1.26,也不要硬上 v3.20,换 v3.22 以上省心。版本不匹配的坑很隐蔽,calico 能装上,但 CRD schema 不兼容,apiVersion 解析报错,或者 Felix 某些特性识别不了,日志里看不出来,只有路由表行为异常。

部署前用下面命令把 K8s 版本和 calico 二进制的版本都确认一遍:

kubelet --version kubectl version --short | grep server

输出里 server 版本如果落在 1.20~1.26,那 v3.20.6 可以继续走。这里还要提醒一句:别在已有 calico 的集群上直接覆盖 apply 新版本 yaml,尤其从 v3.10 这种老版本跨度升级时,CRD 结构变化很大,旧资源不会自动迁移,路由规则会乱套。

2.2 镜像清单:cni、node、kube-controllers、flexvol 一个不能少

资源包里镜像统一是 docker.io/calico 命名空间下的 v3.20.6 tag。核心四个:

镜像名角色是否必须
calico/cni:v3.20.6Pod 网卡创建、IP 分配必须
calico/node:v3.20.6每节点常驻 Felix 与 BIRD 进程必须
calico/kube-controllers:v3.20.6策略同步、IP 池生命周期必须
calico/pod2daemon-flexvol:v3.20.6FlexVolume 挂载兼容默认 yaml 引用
calico/typha:v3.20.6高并发降低 apiserver 压力可选

默认 calico.yaml 不启用 typha,所以一般导入前四个镜像就够。资源包里的镜像压缩文件解压后,可以先在任意一台节点上查看清单:

tar -tf calico-images.tar | head -20

确认是否存在 cni、node、kube-controllers、flexvol 这几个 tag。缺了哪个,后面部署时就会卡在 ErrImagePull。老手习惯是把这步当成强制检查,因为镜像打包环节漏 tag 太常见了。

2.3 私有仓库开通:containerd 的 hosts.toml 写法

K8s 1.24 以上默认运行时是 containerd,没有 docker。我的做法是先在内网起一个 registry,把镜像推到私有仓库,再让节点从这个仓库拉取。containerd 1.7 以上推荐用 hosts.toml 方式配置,在 /etc/containerd/certs.d/ 下按仓库域名建目录:

mkdir -p /etc/containerd/certs.d/registry.local:5000 cat > /etc/containerd/certs.d/registry.local:5000/hosts.toml <<'EOF' server = "http://registry.local:5000" [host."http://registry.local:5000"] capabilities = ["pull", "resolve"] skip_verify = true EOF systemctl restart containerd

这里 server 写的是 http,因为内网仓库多数没配 TLS。capabilities 只给了 pull 和 resolve,没给 push,意思是节点只从这个仓库拉镜像,不做推送。skip_verify 只建议在内网可信环境开,公网仓库别这么干。

改完 hosts.toml 有个检查技巧:在任意节点执行 crictl pull registry.local:5000/calico/cni:v3.20.6,能成功拉下来就说明 containerd 配置没问题。

2.4 两种导入姿势:docker load 与 ctr -n k8s.io

如果集群节点上还保留着 docker,很多人习惯先 docker load 再推送私有仓库:

docker load -i calico-images.tar docker tag docker.io/calico/cni:v3.20.6 registry.local:5000/calico/cni:v3.20.6 docker push registry.local:5000/calico/cni:v3.20.6

但注意:docker load 导入的镜像是进 docker 的 moby 命名空间,containerd 的 k8s.io 命名空间看不到它。纯粹只有 containerd 的节点,要用 ctr 导入:

ctr -n k8s.io images import calico-images.tar ctr -n k8s.io images list | grep calico

参数 -n k8s.io 最关键,不加这个命名空间,导入的镜像 CRI 还是拉不到。资源包如果只给 tar 包,这两种方式按节点环境二选一,然后统一推进私有仓库,calico.yaml 里的镜像地址全部改成 registry.local:5000/calico/xxx:v3.20.6。

2.5 解压落位:calico.yaml 先检查资源数量

资源包里的 calico.yaml 是整理好的完整 manifest,包含 Namespace、ConfigMap、DaemonSet、Deployment、ServiceAccount、CRD 等。拿到手先解压并确认 yaml 的合法性:

tar -xf calico-v3.20.6-bundle.tar kubectl apply --dry-run=client -f calico.yaml

dry-run 只做客户端校验,不会真的写资源。输出没有 error 才继续。这里有个经验:v3.20.6 的 calico.yaml 里 CRD 数量在 10 个左右,资源总数大概 30+,如果 apply 时报no matches for kind,多半是 yaml 被截断或者版本被改过,直接换原始文件重来。

3. 部署 calico.yaml:改网段、换镜像、apply 三步走

3.1 calico.yaml 的结构先看一遍

Calico 的 manifest 是一整个大文件,里面 ClusterRole、DaemonSet、Deployment 都在一起。v3.20.6 的 calico.yaml 里,calico-node 是一个 DaemonSet,calico-kube-controllers 是一个 Deployment。核心配置在 kube-system 命名空间下的 calico-config 这个 ConfigMap 里。

打开文件先搜 env:

grep -n "name: CALICO_\|name: FELIX_\|name: IP_AUTODETECTION" calico.yaml | head -30

重点看 CALICO_IPV4POOL_CIDR、CALICO_NETWORKING_BACKEND、IP_AUTODETECTION_METHOD 这三个环境变量的当前值。默认模板里 IP 池写的是 192.168.0.0/16,网络后端是 vxlan,IP 探测方式是 first-found。这三个参数几乎决定了一个集群网络能否跑通,下面一一说明改法。

3.2 IP 池:默认 192.168.0.0/16 必须先检查

Calico 默认 Pod 网段是 192.168.0.0/16,这个网段和大量云厂商 VPC 内网、公司办公网冲突。冲突的后果是 Pod 出口流量在节点上就被静态路由劫走,跨网段连接超时,而且很难排查,因为 calico 组件全部 Running。

改法是直接编辑 calico.yaml,把 CALICO_IPV4POOL_CIDR 的值替换成你规划好的网段,比如 10.244.0.0/16:

sed -i 's#192.168.0.0/16#10.244.0.0/16#' calico.yaml grep -n "CALICO_IPV4POOL_CIDR" calico.yaml

IP 池选择建议避开:宿主机网段、Service CIDR(默认 10.96.0.0/12)、云 VPC 主网段。规划一个大网段比如 10.244.0.0/16,后续扩节点不用改。这个值一旦集群跑起来就基本不能改,想改只能删掉旧 IPPool 再重建,影响面很大。所以部署前宁可花十分钟想清楚。

3.3 网卡探测策略:first-found 的不确定性

IP_AUTODETECTION_METHOD 默认是 first-found,意思是 Felix 启动时拿节点上第一个非 loopback 网卡的 IP 作为本机 IP。这个策略在双网卡节点上是坑:管理网卡和业务网卡顺序不稳定,跨节点 VXLAN 隧道可能建在错误的 IP 上。

我的做法是改成 interface 匹配规则,只选业务网卡前缀:

sed -i 's#value: "first-found"#value: "interface=eth.*"#' calico.yaml

如果网卡名不规则,也可以用 can-reach 方式,让 calico 探测能到达某个网关的网卡:

- name: IP_AUTODETECTION_METHOD value: "can-reach=172.16.0.1"

can-reach 的值填节点默认网关,探测到能通的那张网卡就是业务网卡。这个参数对多网卡环境非常关键,选错网卡时 Calico 组件也能启动,但 Pod 跨节点不通,看 calico-node 日志会看到 node 的 IP 和实际业务网段对不上。

3.4 VXLAN 还是 BGP:v3.20.6 的默认值和取舍

v3.20.6 的 calico.yaml 默认 CALICO_NETWORKING_BACKEND 是 vxlan。VXLAN 模式下,跨子网 Pod 流量走 UDP 封装,对底层网络设备没有特殊要求,三层可达就能跑。BGP 模式(值设为 bird)则依赖 BGP 协议,同子网走直连路由,性能更好,但对网络设备和节点路由表有侵入性。

选型建议如下:

场景推荐后端原因
云 VPC、隔离网络VXLAN无需网络设备配合
物理机房、纯二层BGP延迟低,直连转发
混合多子网VXLAN cross-subnet同子网直连,跨子网封装

Calico v3.20.6 的 VXLAN 还有 cross-subnet 模式,同子网走二层直连、跨子网才封装,兼顾性能与兼容性。配置方式是在 IPPool 的 yaml 里设置:

apiVersion: projectcalico.org/v3 kind: IPPool metadata: name: default-ipv4-ippool spec: vxlanMode: CrossSubnet

默认模板不用动 CALICO_IPV4POOL_IPIP,保持 Never 即可。IPIP 和 VXLAN 混用是新手常犯的错误,两个后端同时开会导致路由优先级混乱。

3.5 批量替换镜像地址:sed 一次改完

镜像推进私有仓库后,calico.yaml 里所有镜像地址要替换。资源包里镜像原始地址是 docker.io/calico/xxx:v3.20.6,用 sed 批量替换:

sed -i 's#docker.io/calico#registry.local:5000/calico#g' calico.yaml grep -n "image:" calico.yaml | head -20

替换后确认 imagePullPolicy。内网私有仓库场景,建议把 Always 改成 IfNotPresent,避免节点每次重建 Pod 都去仓库校验,减少启动延迟:

sed -i 's#imagePullPolicy: Always#imagePullPolicy: IfNotPresent#g' calico.yaml

这里有个细节:如果私有仓库的镜像 tag 是对的,IfNotPresent 完全够用;镜像 tag 是 latest 才必须用 Always,而 calico v3.20.6 这种固定版本 tag 没必要 Always。

3.6 apply 和回滚

准备工作完成后正式部署:

kubectl apply -f calico.yaml kubectl get pods -n kube-system | grep calico

观察几分钟,calico-node 的 pod 应该逐渐变成 Running 和 Ready。如果发现哪个组件状态不对,先别急着删,看日志定位:

kubectl logs -n kube-system calico-node-xxxxx -c calico-node --tail=100

如果要回滚,资源包场景下最稳妥的做法是清理全部 calico 资源,恢复干净状态:

kubectl delete -f calico.yaml kubectl delete crd felixconfigurations.crd.projectcalico.org bgpconfigurations.crd.projectcalico.org kubectl delete crd ippools.crd.projectcalico.org networkpolicies.crd.projectcalico.org

crd 删除这步很多人会漏。calico.yaml 自带的 CRD 如果不删,再次 apply 旧版本 yaml 时结构不一致会报错。完整删完,再 apply 新版本,相当于后悔药:重装之前把残骸扫干净,避免旧 CRD 污染新配置。

4. 启动后的配置检查:网络策略、MTU 与 Typha 取舍

4.1 启动检查三件套

calico 部署完不是识别 Ready 就算完,我习惯做三件事:看进程、看路由、看 felix 状态。先看进程:

kubectl get pods -n kube-system -l k8s-app=calico-node -o wide

然后进到任意一个 calico-node 里看 BIRD 路由信息。v3.20.6 的 VXLAN 模式可以用:

kubectl exec -n kube-system calico-node-xxxxx -- ip route | grep 10.244

路由表里能看到指向其他节点的 vxlan 路由,说明隧道已经建立。再看 felix 日志是否有 warning 级以上的异常:

kubectl logs -n kube-system calico-node-xxxxx -c calico-node | grep -i "error\|warn"

这三步都过,网络面才算真正起来。如果路由表里只有本机 Pod 网段没有跨节点路由,多半是 IP 探测选错了网卡,回头改 IP_AUTODETECTION_METHOD。

4.2 网络策略:Calico NetworkPolicy 的独立命名空间

v3.20.6 的 calico.yaml 自带 projectcalico.org/v3 的 CRD,和 K8s 官方的 networking.k8s.io/v1 NetworkPolicy 是两套东西,可以同时存在。Calico 的 NetworkPolicy 字段更细,支持动作和协议级别规则。

默认命名空间没有策略时,流量是全部放行的。但很多人在装好 calico 后立刻套默认拒绝策略,误伤 kube-system。正确的做法是先建一个只作用于业务命名空间的 baseline 策略,例如放行所有目标端口为 80 的入站流量:

apiVersion: projectcalico.org/v3 kind: NetworkPolicy metadata: name: allow-http namespace: shop spec: selector: app == 'web' ingress: - action: Allow protocol: TCP destination: ports: - 80

这个策略只作用于 shop 命名空间里带 app=web 标签的 Pod,不会碰 kube-system。我一般把这类策略和 calico.yaml 分开存放,单独 apply,避免混在大 bundle 里导致后续维护困难。

4.3 MTU 设置:VXLAN 的 50 字节开销怎么算

Calico 在 VXLAN 模式下,宿主机网卡 MTU 1500 时,Pod 网卡 MTU 应该减掉 VXLAN 封装头 50 字节,也就是 1450。v3.20.6 默认 calico.yaml 里 FELIX_MTU 如果是 0 表示自动,但自动探测在多网卡或 Overlay 网络上不一定准。

我的做法是指定明确值:

sed -i 's#name: FELIX_MTU#name: FELIX_MTU\n value: "1450"#' calico.yaml

MTU 不对的现象很典型:小包通,大包不通。ping 加上 -s 1500 就丢包,普通 ping 正常。遇到这种情况先查 Pod 内和宿主机的 MTU 差值是不是 50。如果底层网络本身是 9000 jumbo frame,那就把 FELIX_MTU 设成 8950,规则不变,永远是底层 MTU 减 50。

4.4 Typha 要不要开:v3.20.6 高密度集群的取舍

默认 calico.yaml 不部署 typha,所以大多数场景下不用动。但如果一个集群 node 数量超过 50,或者 apiserver 压力已经偏高,calico-node 大量连接 apiserver 监控资源会造成明显负载。这时候建议补一个 typha Deployment。

默认 yaml 里 typha 相关配置是注释状态,资源包如果有单独的 typha.yaml 可以单独 apply。部署后要把 calico-node 的启动参数加上 --typha-socket-filename,并在白名单里去掉只剩 typha。没有 typha 的集群不要强行补,配置不到位反而会让 node 找不到 typha 而重启。50 节点以内,默认不加 typha 是合理的。

5. 避坑与排查:5 个真实踩坑记录,从现象到修复

5.1 docker load 了但 containerd 拉不到镜像

现象:节点上有 docker,执行 docker load 成功,但 kubectl 创建 calico pod 时一直 ErrImagePull,事件里报 manifest unknown 或 image not found。

原因:docker load 把镜像导入到了 moby 命名空间,而 kubelet 通过 CRI 调用 containerd 的是 k8s.io 命名空间。两边在同一个 containerd 进程里但命名空间隔离,互相看不见。

解决:改用 ctr -n k8s.io images import 重新导入,或者绕开本地导入,直接把镜像推到私有仓库,让 containerd 按仓库地址拉取。从那以后我要求装 calico 前先统一镜像来源,不混用导入方式。

5.2 双网卡节点跨 Pod 不通

现象:calico 组件全部 Running,同节点 Pod 互通,跨节点 Pod 不通,ping 超时。

原因:节点两张网卡,IP_AUTODETECTION_METHOD 的 first-found 选到了管理网卡的 IP,VXLAN 隧道建立在管理网段上,业务网卡收不到封装包。

解决:把 IP_AUTODETECTION_METHOD 改成 interface=eth.* 或 can-reach=172.16.0.1 形式,重建 calico-node。日志里确认 node IP 属于业务网段后才能继续。

5.3 网络策略误伤 CoreDNS

现象:业务 Pod 创建成功,但域名解析全部超时,nslookup 无响应,calico 组件无异常。

原因:手动 apply 了 default deny 策略,没放行 kube-system 命名空间,CoreDNS 的流量被策略拦截。

解决:检查当前生效的 NetworkPolicy:

kubectl get networkpolicies -A kubectl get networkpolicy -n kube-system

为 kube-system 补一条放行策略,或者在默认拒绝策略里显式放行 53 端口 UDP/TCP。这是把策略和网络插件混在一起最常见的事故。

5.4 新旧 IP 池并存导致路由冲突

现象:某次调整 Pod 网段后,新 Pod 分配到新网段,但部分节点访问旧网段 Pod 路由跳转异常,网络时通时断。

原因:旧 IPPool 的 CRD 没有删除,Calico 同时保留新旧两个池,Felix 生成了冲突的路由规则。

解决:删除旧 IPPool 后重建 calico-node。

kubectl get ippools.crd.projectcalico.org kubectl delete ippools.crd.projectcalico.org old-pool-name

删除 IP 池前确认池内没有运行中的 Pod,不然这些 Pod 会失联。更稳的做法是先把旧池的 Pod 驱逐到新池,再执行删除。

5.5 calico-node CrashLoopBackOff:先看 calico-config

现象:calico-node 启动即退出,反复重启,日志报 Failed to create Calico client,找不到 calico-config 或 cluster information 无法获取。

原因:calico.yaml 没有完整 apply,或者之前清理时把 ConfigMap 删了,calico-node 启动时拿不到集群配置。

解决:不要只 apply DaemonSet,把完整 calico.yaml 一次性 apply,确认 ConfigMap 存在:

kubectl get configmap -n kube-system calico-config

如果 ConfigMap 存在但内容异常,检查 data 字段里 etcd_endpoints 或 kubernetes_service_host 是否为空。v3.20.6 默认走 kubernetes 模式,不需要 etcd,但配置缺失或格式错误会直接启动失败。

6. 装完怎么验证跑通:从 Pod 状态到跨节点互访

装完 calico 不能只看组件状态,要实际打流量验证。我会按下面顺序走一遍,整个流程十分钟内搞定。

先确认节点和组件:

kubectl get nodes -o wide kubectl get pods -n kube-system -l k8s-app=calico-node -o wide

所有 node 应该 Ready,而且每个节点都有一个 calico-node 在 Running。注意查看 calico-node 所在节点分布,确保没有某个节点漏了 pod。

然后创建两个测试 Pod,分别调度到不同节点。用如下命令确认节点分布:

kubectl run test-a --image=busybox -- sleep 3600 kubectl get pods -o wide

如果两个 Pod 落在同一节点,用节点亲和或 cordon 处理,确保它们在不同节点上。跨节点测试才是 Calico 真正生效的标志。进入其中一个 Pod,ping 另一个 Pod 的 IP,再从另一端回 ping:

kubectl exec -it test-a -- ping -c 5 <test-b-ip> kubectl exec -it test-b -- ping -c 5 <test-a-ip>

两边都通,说明 VXLAN 隧道和路由表工作正常。接着验证 Service 网络。创建一个 Deployment 和 Service,从同命名空间另一个 Pod 访问 ClusterIP:

kubectl create deployment nginx --image=nginx kubectl expose deployment nginx --port 80 kubectl run curl-test --image=curlimages/curl -- sleep 3600 kubectl exec -it curl-test -- curl -I http://<cluster-ip>

能返回 HTTP 200,说明 kube-proxy 和 calico 的配合没有问题。最后验证网络策略确实生效,写一条禁止某 Pod 访问的规则并实际测试通断:

apiVersion: projectcalico.org/v3 kind: NetworkPolicy metadata: name: deny-from-test-a spec: selector: app == 'nginx' ingress: - action: Deny source: selector: run == 'test-a'

把这条策略 apply 后,再从 test-a curl 一次 nginx 服务,应该超时。验证完把测试资源清理掉:

kubectl delete pod test-a test-b curl-test kubectl delete deployment nginx kubectl delete service nginx kubectl delete networkpolicy deny-from-test-a

从那以后,每装完一套 calico,我都强制把这一套流程走一遍,组件检查、跨节点互通、ClusterIP 访问、策略拦截缺一不可。只有这四步全过,才算真正跑通,而不是停留在 Pod Running 的假象里。希望这套验证流程也能帮你少走弯路。

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

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

手写微型Vue:深入响应式系统与虚拟DOM实现

三年前我第一次把 Vue 的响应式原理图背得滚瓜烂熟&#xff0c;觉得 Proxy、依赖收集、虚拟 DOM 这些东西我算是懂了。直到有一次在代码评审里被问到“一次状态变更后&#xff0c;从 setValue 到页面重绘&#xff0c;中间到底发生了哪几步”&#xff0c;我发现自己只能说出个大…

作者头像 李华
网站建设 2026/10/15 20:11:24

ROS TF坐标变换核心机制与多传感器系统实战避坑指南

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/15 20:09:58

MyBatis-Plus自动填充实战:从时间戳到多租户的数据治理基石

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views …

作者头像 李华
网站建设 2026/10/15 20:09:42

Celery分布式任务队列实战:原理、配置与踩坑全解析

做后端开发这几年&#xff0c;我最烦的就是“同步阻塞”带来的一堆烂摊子。用户注册完&#xff0c;验证邮件卡了十来秒&#xff1b;后台导出一份报表&#xff0c;请求一直转圈&#xff1b;每天凌晨要跑的统计任务&#xff0c;总得人肉定闹钟去服务器敲命令。后来把 Celery 用起…

作者头像 李华