
简介面向Kubernetes集群管理员与运维人员的Calico v3.25.0离线镜像包专门解决离线或受限网络环境下Calico网络插件无法在线拉取、安装受阻的问题。资源共3个文件压缩包整体187.24MBtar镜像文件封装了Felix、BIRD、Typha等Calico核心组件的容器镜像yaml文件提供部署所需的资源清单与默认网络策略配置txt文档附带了从镜像导入到插件启用的完整离线安装说明。借助这套离线包用户无需连接外部镜像仓库即可在本地完成Calico的加载与配置实现Pod跨节点通信、基于BGP的高效路由以及细粒度网络安全策略管控保障集群网络功能的稳定运行。资源已有453人学习适合内网部署、生产环境网络受限以及需要快速复制集群网络环境的Kubernetes使用者参考。1. 离线部署 Kubernetes 网络插件calico v3.25.0 离线包能省下哪些事Kubernetes 集群装到一半节点上不了外网所有的docker pull和ctr pull都卡在超时上——这是内网环境里最常见的僵局。calico-image-v3.25.0 离线包就是为这个场景准备的把calico/cni、calico/node、calico/kube-controllers等一组镜像预先save成 tar连同calico.yaml清单一起投放离线节点的容器运行时直接从本地导入不需要访问 docker hub 或 quay.io。v3.25.0 这个版本对应 Kubernetes 1.28 上下的主流集群支持 BGP 和 VXLAN 两种数据面生产环境验证充分比盲目追新版本稳。这篇文章会从拆包、配置、部署到排查走一遍适合正在搭离线集群的运维和 SRE也适合刚接触 Calico 的新手照着操作。2. 先把离线包拆开镜像清点、运行时匹配与导入顺序拿到手先别急着kubectl apply离线包里的东西搞清楚再动。v3.25.0 的离线包通常是一个压缩目录我习惯先解压到/opt/calico-offline按文件类型分组看一遍确认和你的容器运行时对得上。2.1 离线包里的文件结构与镜像清单怎么读一个规范的 calico v3.25.0 离线包大致是下面这种结构calico-v3.25.0-offline/ ├── images/ │ ├── calico-cni.tar │ ├── calico-node.tar │ ├── calico-kube-controllers.tar │ └── calico-pod2daemon-flexvol.tar ├── manifests/ │ └── calico.yaml ├── calicoctl-linux-amd64 └── README.mdimages/目录下每个 tar 对应一个镜像manifests/calico.yaml是官方非 operator 安装方式的完整清单calicoctl是后续验证要用的命令行工具。先做一件事把 tar 里的镜像 tag 全部列出来和calico.yaml里的image:字段一一核对。因为导入时 tag 不一致是离线部署的头号翻车点后面第 5 章会专门展开。用tar命令查看镜像 tar 的原始信息tar -xf /opt/calico-offline/images/calico-node.tar -O manifest.json | python3 -m json.tool这块的关键是确认RepoTags是不是calico/node:v3.25.0而不是带-amd64后缀或latest的变体。很多离线包为了兼容多架构会把 tag 写成带平台的格式导入进 containerd 后名字对不上Pod 就拉不到。2.2 先确认运行时docker 还是 containerd以及带不带 shim导入镜像前要分清楚目标节点用的是哪套容器运行时。现在 kubeadm 搭建的集群默认是 containerd老集群可能是 docker两者导入方式完全不同混用会白白折腾半天。containerd 环境用ctr导入注意命名空间必须和 kubelet 保持一致ctr -n k8s.io images import /opt/calico-offline/images/calico-node.tar ctr -n k8s.io images import /opt/calico-offline/images/calico-cni.tar ctr -n k8s.io images import /opt/calico-offline/images/calico-kube-controllers.tar ctr -n k8s.io images import /opt/calico-offline/images/calico-pod2daemon-flexvol.tar-n k8s.io指定的是 kubelet 使用的工作命名空间如果漏掉这个参数镜像会被导入到default命名空间Kubelet 和 CRI 根本看不到Pod 照样报ErrImagePull。导入后建议立即验证一遍ctr -n k8s.io images list | grep calicodocker 环境的节点就简单了docker load逐个加载然后确认 tagdocker load -i /opt/calico-offline/images/calico-node.tar docker images | grep calico这里有一个细节docker 环境下如果离线包里的镜像 tag 是v3.25.0-amd64哪怕 load 成功calico.yaml里写的v3.25.0依然找不到。这时候要么改 manifest要么docker tag补一个别名两步选其一不要指望 runtime 会自动匹配。常见的做法是先全部 load再用脚本批量打 tag。参数上要注意docker load 不覆盖已有同名镜像的话会保留旧 tag升级场景下需要先清理旧镜像否则 import 的版本可能不是你要的 v3.25.0。3. 改配置再落地IP 池、VXLAN/BGP 模式选择与不踩雷的默认项镜像搞定后别急着把calico.yaml扔上去v3.25.0 的默认配置不一定适配你的集群。IP 池 CIDR 冲突、overlay 模式和物理网络 MTU 是三大高频翻车点。这一章说清楚参数怎么改为什么这么改。3.1 calico.yaml 里最值得改的三处参数先找到清单里的Installation配置段。v3.25.0 的calico.yaml默认把配置写在 ConfigMap 里最需要动的是下面三块。第一处是默认 IP 池的 CIDR。Calico 默认分配192.168.0.0/16给 Pod如果你在用 kubeadm 初始化时指定了--pod-network-cidr10.244.0.0/16或者是云厂商集群里已经存在其他网段这俩直接撞车。改法是在清单里搜192.168.0.0/16替换成你集群的 Pod 网段ipPools: - cidr: 10.244.0.0/16 ipipMode: Never vxlanMode: Always natOutgoing: true mtu: 0ipipMode: Never是为了关掉 IPIP 封装vxlanMode: Always表示所有跨节点流量都走 VXLAN。mtu: 0是自动探测的意思不要手动改成 1500物理网络未必扛得住。这里的逻辑是Pod 网段必须是集群初始化时预留的一旦 Calico 接管后 CIDR 冲突后续加节点会疯狂报Could not assign requested IP address。第二处是 veth 的 MTU 调整。很多物理网络为了兼容 VLAN 会把 MTU 降到 1450 甚至 1400Calico 自动探测的结果未必正确。在calico-node的环境变量里找到FELIX_MTU相关配置- name: FELIX_MTU value: 1450如果底层用的是常见的 1500 以太网这一步可以跳过但虚拟机化环境里经常出现跨节点大包不通查了半天才发现是 MTU 卡了。第三处是多网卡节点的接口自动发现。Calico 会用autodetect找主要网卡如果节点上有eth0docker0br-ex它可能选错。推荐直接指定- name: IP_AUTODETECTION_METHOD value: interfaceeth.*正则eth.*的意思是只用eth开头的物理接口避免把虚拟网卡当成数据面。3.2 VXLAN 和 BGPIPIP怎么选带宽、跨网段和防火墙三个维度v3.25.0 支持两种 overlay 方案。VXLAN 走 UDP 4789 端口封装跨三层网络也能通部署成本低性能略差BGP 直接跑 IPIP 隧道或纯路由性能好但依赖物理网络支持 BGP 协议而且跨网关场景要额外配置。先看对比表维度VXLAN推荐BGP / IPIP 纯路由跨三层网络天然支持需要物理路由配合 BGP防火墙放行统一放行 UDP 4789需要 TCP 179 IP 协议 4性能损耗封包解包有开销纯路由模式下几乎无损配置复杂度低中高对网络设备有要求适用规模50 节点以内足够大规模或需要对接物理网络我一般建议中小规模集群无脑用 VXLAN理由有两个一是大多数自建机房没有可控的 BGP 路由器配合二是排障时 VXLAN 隧道只要看 UDP 通不通BGP 模式下还要排查邻居状态黑匣子比较多。只有当集群规模大到 VXLAN 封装带来明显吞吐损耗或者需要容器 IP 直接暴露给物理网络时才考虑切换到 BGP 模式。需要注意的一个坑是vxlanMode的三个取值Always、CrossSubnet和Never。Never会让同一二层里的节点走纯路由跨子网就无法通信CrossSubnet是只在跨子网时封装同子网走直连性能和连通性最均衡我实际用得最多的是这个。改完之后记得确认calico.yaml里的CALICO_IPV4POOL_VXLAN环境变量和ipPools配置一致这俩是同一份配置的两种表达出现矛盾时以ipPools为准但容易让人犯迷糊。4. 上完镜像推清单kubectl 部署的完整现场操作镜像导入完成配置也调好之后进入真正的部署环节。这一步没有太多玄学但顺序和校验方式有讲究。4.1 用 kubectl 把清单推进集群先 dry-run 再 apply先把calico.yaml从离线包解压到能访问 API Server 的机器上。如果是自签证书的离线集群登录节点后先确认 kubeconfig 可用kubectl get nodes确认返回正常后先做一次 dry-run 检查资源定义是否合法kubectl apply --server-side --dry-runserver -f /opt/calico-offline/manifests/calico.yaml这里用--server-side是 v3.25 官方清单推荐的方式Client-side dry-run 在 CRD 定义不完整时会误报错误。注意calico.yaml里包含大量 CRDfelixconfiguration、ippool、bgpconfiguration等这些资源在kubectl apply时是批量注册的第一次执行后部分 CRD 可能还没被 API Server 完全缓存隔几十秒再跑一次会把状态刷正常。正式安装kubectl create -f /opt/calico-offline/manifests/calico.yaml如果之前已经装过一遍并想覆盖用kubectl apply -f会更平滑create在资源已存在时会直接报错。输出里看到networkpolicy.networking.k8s.io/calico-kube-controllers created这类字样就说明资源注册成功。如果集群里的镜像仓库是私有环境还需要改calico.yaml里的imagePullPolicy和镜像前缀。常见做法是把所有image: calico/xxx替换成内部仓库地址sed -i s|calico/|registry.inside.local/calico/|g calico.yaml注意这一步在导入离线镜像的节点上不是必须的——镜像在本机kubelet 能直接找到。但如果你的集群是多节点务必要让每个节点都完成 2.2 节的镜像导入或者统一走内网仓库否则就会出现部分节点 Pod 能起来、部分节点一直ImagePullBackOff的情况。4.2 十分钟内确认 Calico 三件套的启动状态部署完成后先看 Pod 的状态kubectl get pods -n kube-system -l k8s-appcalico-node -o wide kubectl get pods -n kube-system -l k8s-appcalico-kube-controllers -o wide正常情况下每个节点都有calico-node的Running控制面有三个组件的副本。注意calico-node是 DaemonSet如果某个节点的 Pod 卡在ContainerCreating多半是flexvol挂载失败或者镜像没有导入到该节点先describe看事件kubectl describe pod calico-node-xxxxx -n kube-systemdescribe输出里最值得看的是Events部分。出现Failed to create pod sandbox时要检查 containerd 的 CNI 插件路径出现Unable to find image时虽然镜像导入了但还是拉取失败就要回到第 2 章去核对 tag 和命名空间。接着验证节点是否进入 Readykubectl get nodes如果节点的STATUS还是NotReady而calico-node已经 Running大概率是 felix 还没完成路由下发或 BGP 会话没建立起来这时直接把日志捞出来看一句kubectl logs -n kube-system calico-node-xxxxx | grep -E error|ERROR|BGP|felixerror出现得少、felix的ip处理日志出现得多是好事。如果看到error listing BGP peers多半是证书或 RBAC 问题检查calico-node挂载的 ServiceAccount 权限手动补一个 binding 也可以临时绕过但正规路径是重新 apply 完整清单。这里还有一个容易被忽略的点v3.25.0 的清单默认把资源放在kube-system命名空间下而不是 tigera operator 那种独立calico-system。你在做网络策略隔离时如果按calico-system去查资源会扑空先确认命名空间再往下走。5. 离线部署避坑五条镜像导入与网络配置的实测教训这一章是我自己踩过的坑还有帮别人排查时遇到的高频问题。每一条都是血泪经验照着现象对号入座能省不少时间。5.1 镜像导入后 Pod 一直 ImagePullBackOff现象所有calico-nodePod 的状态是ImagePullBackOffkubectl describe显示Failed to pull image calico/node:v3.25.0但节点上ctr images list明明有同名镜像。原因镜像被导入到了错误的 containerd 命名空间。ctr默认操作的是default命名空间而 Kubelet 通过 CRI 使用的是k8s.io两边不互通Kubelet 看不到。更隐蔽的原因是镜像 manifest 里的 RepoTag 和calico.yaml不一致比如离线包里是v3.25.0-amd64清单里写v3.25.0。解决重新导入到正确命名空间并统一 tag。先删掉错误命名空间里的镜像再执行ctr -n k8s.io images import /opt/calico-offline/images/calico-node.tar如果 tag 对不上用ctr -n k8s.io images tag打别名。从那以后我每次导镜像都先执行一遍ctr -n k8s.io images list | grep calico核对完再往下走。5.2 VXLAN 模式下跨节点 Pod 互 ping 不通现象同一节点上的 Pod 通信正常但跨节点的 Pod 丢包 100%ping卡死。原因UDP 4789 端口被防火墙拦截。VXLAN 把二层帧封装在 UDP 里物理网络没放行这个端口时隧道根本建不起来。另外一个原因是 MTU 设置过大VXLAN 每包多出 50 字节物理链路 MTU 如果是 1500Pod 里实际能用的只有 1450发大包时直接被丢弃。解决先检查防火墙规则iptables -L -n | grep 4789 firewall-cmd --list-ports缺了就放行 UDP 4789。MTU 问题则把 3.1 节说的FELIX_MTU显式配置为1450然后滚动重启calico-node。验证时用小包ping -M do -s 1400能通再增加包体大小逐步定位 MTU 临界值。5.3 多网卡节点上 calico 选了错误的网卡现象calico-node日志里出现大量failed to get IP或Unable to read configPod IP 分配到192.168.x.x但宿主机上实际没有这个网段的地址。原因Calico 默认自动检测网卡时选了docker0或br-ex这类虚拟接口或者在有多个物理网卡的机器上选了管理网而不是数据网。这个行为在虚拟机场景特别隐蔽因为虚拟网卡的名称往往是enp开头正则写错一步就选歪了。解决显式指定接口匹配规则- name: IP_AUTODETECTION_METHOD value: interfaceenp.*|eth.*列规则时要按顺序匹配先命中的就用。如果节点上确实只有一个物理网卡也可以写成first-found但多网卡环境一定用正则。改完重启calico-nodePod查看日志确认用的网卡 MAC 地址和ip link显示一致。5.4 卸载 Calico 之后 iptables 残留导致新网络组件异常现象旧集群卸载 Calico 换用其他 CNI 后新装上 flannel 或 Cilium 的节点无法分配 Pod IP路由表和 NAT 规则混乱。原因Calico 在数据面会写大量 iptables 规则和路由条目直接删除 DaemonSet 不会自动清理这些残留。calico-node容器退出时虽然触发过 felix 的清理逻辑但如果节点直接无法访问 API Server清理不彻底旧的cali-前缀规则就留在了 iptables 里。解决卸载后手工清理每条节点的残留ip route | grep cali iptables-save | grep cali路由中有cali的条目逐条删除iptables 规则里的cali-链可以整链删除iptables -F cali-FORWARD iptables -D FORWARD -j cali-FORWARD还有tunl0和vxlan.calico这些虚拟接口也需要ip link del清一遍否则新 CNI 依赖的常规接口检查会异常。这个坑我在迁移 Cilium 时踩过一次后来规范起见卸载前先跑一遍/etc/cni/net.d/下的配置文件备份确认新 CNI 安装后再动手删除旧数据。5.5 etcd 存储还是 Kubernetes API 存储版本不匹配最容易翻车现象手工搭建的集群里calico-nodePod 起来了但一直报Failed to connect to etcd或者频繁重启。原因v3.25.0 官方清单默认用 Kubernetes API 作为 datastore 类型也就是所有网络配置存在 K8s CRD 里。如果离线包里的清单被改成 etcd 模式但集群本身没有部署 etcd 集群或者 etcd endpoints 地址写错Calico 既连不上 API Server 又会去连一个不存在的 etcd直接死循环。解决v3.25.0 推荐用kubernetesdatastore在calico.yaml里确认datastoreType: kubernetes只要保持了默认就不需要单独部署 etcd。如果你确实要对接外部 etcd确认 endpoints 地址没有http://前缀错误并且etcd-key、etcd-cert这些 Secret 都存在对应命名空间。这个配置在老的 Calico 版本里是正常选项但 v3.25 里已经是少数派配置新手不要轻易开。6. 部署完的一小时验证链路、路由与后续维护习惯部署结束不等于工作结束。节点 Ready 之后的第一个小时内我会按固定顺序把数据面验证一遍。先用calicoctl看节点状态./calicoctl node status输出里重点看IPv4 BGP status这行up表示 BGP 会话正常。但注意在纯 VXLAN 模式下BGP 状态可能不是关键指标因为数据面走的是 VXLAN 隧道而不是 BGP 表项。这时候更可靠的验证方式是直接检查容器之间的连通性和宿主机路由kubectl get pods -n kube-system -l k8s-appcalico-node -o wide ip route | grep 10.244从路由表里能看到10.244.x.x dev vxlan.calico条目说明 VXLAN 隧道已经建立。然后挑两个节点上的 Pod互相pingPod IP同时在大包下验证 MTUping -M do -s 1400 10.244.1.23这一步过了基本说明数据面没问题。如果只有小包能通、大包不通按 5.2 节继续调 MTU。接下来我会花一点时间看 felix 的日志确认没有反复刷errorkubectl logs -n kube-system calico-node-xxxxx | grep -c ERROR正常数量应该是 0 或个位数日志里大量INFO才是对的。会看到IPv4 becoming up和BGP session established这类标志性文本。维护层面的习惯也值得说一句。v3.25.0 之后的 Calico 升级路径是直接用新版本的镜像替换旧 tag离线包里镜像文件做好版本目录管理每次升级前先把calico.yaml的 diff 列出来重点看 CRD 有没有新增字段。我会在每台节点上留一个sha256sum校验文件导入镜像前先校验包完整再动生产这能拦住一大半的搬运损坏问题。从那以后我每次离线部署完都会把这个步骤当成强制动作上线前花十分钟验证比事后翻日志找回损失划算得多。希望帮到你。本文还有配套的精品资源点击获取