:鏡像包與 calico.yaml 配套使用指南)
簡介本資源面向在 Kubernetes 集群中部署與運維容器網(wǎng)絡(luò)的工程師提供 Calico v3.20.6 所需的容器鏡像與核心部署清單幫助解決離線環(huán)境或內(nèi)網(wǎng)集群無法直接拉取鏡像、網(wǎng)絡(luò)策略難以落地的問題。壓縮包共 5 個文件包含 4 個 tar 鏡像包與 1 個 yaml 配置文件整體約 96.68MB鏡像分別對應(yīng)節(jié)點代理、CNI 插件、控制器以及 FlexVol 掛載插件yaml 則用于定義 DaemonSet、CNI 配置、策略控制器與 BGP 參數(shù)等部署對象。已有 1084 人學(xué)習(xí)下載說明該版本在社區(qū)中具備一定參考價值。讀者可借助這套材料完成 Calico 的離線導(dǎo)入與集群集成理解各組件在 Pod 網(wǎng)絡(luò)分配、跨節(jié)點路由和網(wǎng)絡(luò)策略執(zhí)行中的分工并據(jù)此搭建可復(fù)用的容器網(wǎng)絡(luò)實驗環(huán)境為多租戶隔離與安全通信場景提供實踐基礎(chǔ)。1. 從一次 Pod 跨節(jié)點不通說起calico v3.20.6 離線包到底裝了什么上個月幫一個朋友排查環(huán)境兩個節(jié)點上的 Pod 互相 ping 不通kubectl get pods -n kube-system一看 calico-node 全是 Running但calicoctl node status里 BGP 鄰居死活建不起來。折騰半天發(fā)現(xiàn)是鏡像版本和 yaml 里的 image 字段對不上——他手動改了 tag結(jié)果拉的是另一個小版本的鏡像。這種玄學(xué)問題在離線環(huán)境里尤其常見因為你沒法隨手docker pull一個來試。這次要拆的這個資源就是解決這類問題的calico v3.20.6 版本的容器鏡像包外加配套的 calico.yaml 部署文件。它面向的是那些 Kubernetes 集群沒法直連公網(wǎng)、或者內(nèi)網(wǎng) registry 還沒同步 calico 鏡像的場景。你拿到的是一個已經(jīng)鎖定版本的組合——鏡像和 yaml 是配套的不用自己去猜 tag、不用去翻 release notes 對版本。適合誰正在搭離線 K8s 集群的人、需要固定 calico 版本做驗證的人、以及被版本漂移坑過一次、想把手頭環(huán)境釘死的人。下面我從這個包的結(jié)構(gòu)開始一路講到怎么把它塞進集群、怎么驗證、以及幾個我踩過的坑。2. 拆開這個包鏡像清單與 calico.yaml 的對應(yīng)關(guān)系2.1 鏡像包里到底有幾個 tarcalico 不是單個二進制它是一組組件的集合。v3.20.6 這個版本核心鏡像通常包括calico/node、calico/cni、calico/kube-controllers如果用到 typha 做 datastore 代理還會有calico/typha。離線包一般會把這些打成獨立的 tar 文件或者一個大的 tar 里包含多層。你拿到手第一件事不是急著docker load而是先列一下內(nèi)容確認(rèn)沒有缺件。# 查看離線包里的 tar 文件列表確認(rèn)組件齊全 tar -tf calico-v3.20.6-images.tar | grep -E \.tar$ # 如果是分開的 tar直接看目錄 ls -lh *.tar邏輯說明tar -tf只列出內(nèi)容不解壓避免污染當(dāng)前目錄。參數(shù)上沒什么特別的關(guān)鍵是看輸出里有沒有node、cni、kube-controllers這三個核心件。如果只有 node 一個那說明這個包是殘缺的部署到一半會卡在 CNI 插件初始化。2.2 calico.yaml 里哪些字段和鏡像直接掛鉤打開 calico.yaml搜image:這個關(guān)鍵字你會看到 DaemonSet、Deployment 里引用的鏡像地址。v3.20.6 的 yaml 里默認(rèn)寫的是docker.io/calico/node:v3.20.6這種形式。離線環(huán)境里你要么把鏡像 load 進本地 docker 后不改 yaml 直接跑前提是節(jié)點上 docker 能識別這個 tag要么把 yaml 里的地址改成你的內(nèi)網(wǎng) registry 地址。# calico.yaml 中 DaemonSet 的容器定義片段示意 containers: - name: calico-node image: docker.io/calico/node:v3.20.6 env: - name: DATASTORE_TYPE value: kubernetes邏輯說明DATASTORE_TYPE設(shè)為kubernetes表示用 K8s API 做 datastore這是大多數(shù)中小集群的默認(rèn)選擇。如果你改成etcd那還得額外配 etcd 端點v3.20.6 里這個字段的取值就這兩種別寫別的。參數(shù)上image字段的 tag 必須和離線包里的鏡像 tag 完全一致差一個字符都會導(dǎo)致 ImagePullBackOff。2.3 版本鎖定帶來的好處與代價鎖定 v3.20.6 意味著你不用面對跨大版本的 API 變更。calico 從 v3.20 到 v3.21 有一些 CRD 字段的調(diào)整離線環(huán)境里一旦 yaml 和鏡像版本錯位kube-controllers 可能起不來日志里報failed to sync之類的錯。代價是這個版本的一些新特性你用不上比如后續(xù)版本對 eBPF 數(shù)據(jù)面的增強。但如果你只是要一個穩(wěn)定跑通的 CNI這個版本足夠。提示不要試圖用 v3.20.6 的 yaml 去配 v3.21 的鏡像反過來也不行。CRD 定義在 yaml 里是寫死的版本錯位時 apply 可能不報錯但運行時行為會詭異。3. 把鏡像塞進集群load、tag、push 三步走3.1 在能聯(lián)網(wǎng)的機器上 load 并重打 tag如果你拿到的是 tar 包第一步是在一臺有 docker 的機器上把鏡像 load 進去。這臺機器可以是你的跳板機也可以是集群的某個節(jié)點。load 完之后docker images應(yīng)該能看到calico/node等條目。這時候如果你要用內(nèi)網(wǎng) registry就得重新打 tag。# 加載離線鏡像包 docker load -i calico-v3.20.6-images.tar # 確認(rèn)加載結(jié)果 docker images | grep calico # 重新打 tag指向內(nèi)網(wǎng) registry docker tag calico/node:v3.20.6 registry.internal:5000/calico/node:v3.20.6 docker tag calico/cni:v3.20.6 registry.internal:5000/calico/cni:v3.20.6 docker tag calico/kube-controllers:v3.20.6 registry.internal:5000/calico/kube-controllers:v3.20.6邏輯說明docker load會保留原鏡像的 repository 和 tag所以 load 完不用猜名字。docker tag是給同一個鏡像 ID 再貼一個標(biāo)簽不占額外空間。參數(shù)上registry.internal:5000換成你自己的 registry 地址和端口別照抄。3.2 push 到內(nèi)網(wǎng) registry 并驗證tag 打完就 push。push 完之后在集群的任意一個節(jié)點上docker pull一下確認(rèn)能拉下來。這一步別省我見過 registry 權(quán)限沒配好、push 成功但 pull 403 的情況。# 推送鏡像到內(nèi)網(wǎng) registry docker push registry.internal:5000/calico/node:v3.20.6 docker push registry.internal:5000/calico/cni:v3.20.6 docker push registry.internal:5000/calico/kube-controllers:v3.20.6 # 在集群節(jié)點上驗證拉取 docker pull registry.internal:5000/calico/node:v3.20.6邏輯說明push 和 pull 用的是同一套認(rèn)證如果 push 成功但 pull 失敗多半是 registry 的存儲后端或者證書有問題。參數(shù)上如果你的 registry 用的是自簽證書節(jié)點上的 docker 需要配insecure-registries否則 pull 會報 x509 錯誤。3.3 改 calico.yaml 里的 image 地址鏡像就位后把 calico.yaml 里所有image:字段改成內(nèi)網(wǎng) registry 的地址??梢杂?sed 批量替換但替換完要肉眼掃一遍確認(rèn)沒有漏網(wǎng)的。# 批量替換鏡像地址先備份 cp calico.yaml calico.yaml.bak sed -i s|docker.io/calico/|registry.internal:5000/calico/|g calico.yaml # 確認(rèn)替換結(jié)果 grep image: calico.yaml邏輯說明sed的-i是原地修改所以先cp備份。替換模式里用了|做分隔符因為地址里有/用/做分隔符會沖突。參數(shù)上g表示全局替換不加的話每行只替換第一個匹配。注意如果你的集群節(jié)點上 docker 已經(jīng)能識別docker.io/calico/node:v3.20.6這個 tag比如你 load 到了每個節(jié)點那不改 yaml 也能跑。但生產(chǎn)環(huán)境不建議這么做節(jié)點多了之后手動 load 容易漏。4. 部署與驗證從 apply 到 BGP 鄰居建立4.1 apply 之前先確認(rèn) CRD 不會沖突如果你的集群之前裝過其他版本的 calico或者殘留了 calico 的 CRD直接 apply 新的 yaml 可能會報already exists。穩(wěn)妥的做法是先看看現(xiàn)有的 CRD。# 查看現(xiàn)有 calico CRD kubectl get crd | grep calico # 如果有殘留先刪除確認(rèn)沒有業(yè)務(wù)依賴再操作 kubectl delete crd $(kubectl get crd | grep calico | awk {print $1})邏輯說明kubectl get crd列出所有自定義資源定義grep calico過濾出 calico 相關(guān)的。awk {print $1}取第一列也就是 CRD 名字。參數(shù)上刪除 CRD 會連帶刪除對應(yīng)的自定義資源所以執(zhí)行前確認(rèn)沒有業(yè)務(wù)在用。4.2 apply calico.yaml 并觀察 Pod 狀態(tài)apply 之后calico-node 是以 DaemonSet 形式跑的每個節(jié)點一個 Pod。calico-kube-controllers 是 Deployment通常一個副本。# 應(yīng)用 calico 部署文件 kubectl apply -f calico.yaml # 觀察 Pod 啟動情況 kubectl get pods -n kube-system -w邏輯說明-w是 watch 模式實時刷新。calico-node 啟動需要一點時間因為它要初始化 CNI 配置、建立 BGP 會話。如果超過兩分鐘還是 ContainerCreating去看 describe。4.3 用 calicoctl 驗證節(jié)點狀態(tài)Pod 跑起來不代表網(wǎng)絡(luò)通了。最直接的驗證是看 BGP 鄰居狀態(tài)。你需要先有 calicoctl 這個二進制版本最好和 calico 一致。# 查看節(jié)點狀態(tài)和 BGP 鄰居 calicoctl node status # 預(yù)期輸出里每個節(jié)點應(yīng)該顯示 Established邏輯說明calicoctl node status會列出本節(jié)點和其他節(jié)點的 BGP 會話狀態(tài)。如果顯示Connect或者Active說明 BGP 沒建起來。參數(shù)上calicoctl 需要能訪問 datastore默認(rèn)走 K8s API所以要在能訪問集群的機器上跑。4.4 跑一個跨節(jié)點 Pod 驗證連通性最后一步起兩個 Pod 分別調(diào)度到不同節(jié)點互相 ping。這是最實在的驗證。# 創(chuàng)建測試 Pod kubectl run test-pod-1 --imagebusybox --restartNever -- sleep 3600 kubectl run test-pod-2 --imagebusybox --restartNever -- sleep 3600 # 查看 Pod IP 和所在節(jié)點 kubectl get pods -o wide # 從一個 Pod ping 另一個 kubectl exec -it test-pod-1 -- ping test-pod-2-ip邏輯說明--restartNever讓 Pod 不會自動重啟方便清理。-o wide顯示 Pod IP 和節(jié)點名。ping 通說明 calico 的跨節(jié)點路由生效了。參數(shù)上busybox 鏡像小適合做測試但注意它默認(rèn)沒有 ping 命令的某些選項簡單 ping 夠用。5. 避坑與排查那些讓我重裝過集群的瞬間5.1 坑一鏡像 tag 和 yaml 不一致導(dǎo)致 ImagePullBackOff現(xiàn)象calico-node Pod 一直卡在 ImagePullBackOffdescribe 里報manifest unknown或not found。原因yaml 里寫的 tag 是v3.20.6但離線包里的鏡像 tag 可能是v3.20.6-amd64或者別的后綴也可能是你 push 到 registry 時改了 tag 但忘了同步改 yaml。解決docker images確認(rèn)本地鏡像的準(zhǔn)確 tag然后grep image: calico.yaml逐行核對。改完重新 apply。5.2 坑二節(jié)點上 iptables 規(guī)則殘留導(dǎo)致新 Pod 不通現(xiàn)象calico-node 顯示 RunningBGP 也 Established但新建的 Pod 就是不通。原因之前裝過其他 CNI 或者舊版 calicoiptables 里殘留了 FORWARD 鏈的 DROP 規(guī)則。解決iptables -L FORWARD -n看看有沒有異常的 DROP。如果有清理掉舊規(guī)則或者重啟節(jié)點讓 calico 重新刷。我一般會在部署前先iptables-save備份一份出問題好回滾。5.3 坑三MTU 不匹配導(dǎo)致大包被丟現(xiàn)象小包 ping 通但 curl 大文件或者跑 HTTP 請求時卡住。原因calico 默認(rèn)的 MTU 是 1440但如果你的節(jié)點網(wǎng)絡(luò) MTU 是 1500且中間有隧道封裝實際可用 MTU 會更小。解決在 calico.yaml 的calico-node環(huán)境變量里加FELIX_IPINIPMTU或者FELIX_VXLANMTU根據(jù)你用的封裝模式調(diào)整。v3.20.6 里這兩個變量都支持。5.4 坑四kube-controllers 報錯但 Pod 是 Running現(xiàn)象calico-kube-controllers 的 Pod 狀態(tài)是 Running但日志里一直在刷failed to sync。原因通常是 RBAC 權(quán)限不夠或者 ServiceAccount 沒綁對。離線環(huán)境里如果 yaml 里的 RBAC 部分被裁剪過就會這樣。解決kubectl logs -n kube-system kube-controllers-pod看具體報錯。如果是權(quán)限問題檢查 ClusterRoleBinding 是否完整。5.5 坑五節(jié)點重啟后 calico-node 起不來現(xiàn)象節(jié)點維護重啟后calico-node 一直 CrashLoopBackOff。原因節(jié)點上的 CNI 配置文件/etc/cni/net.d/里的 conflist 文件損壞或者 calico 的 datastore 連接信息丟失。解決刪掉/etc/cni/net.d/下的 calico 相關(guān)文件讓 calico-node 重新生成。同時檢查/var/lib/calico/下的節(jié)點標(biāo)識文件是否還在。提示每次動 calico 之前calicoctl get nodes和calicoctl get ippools各存一份出問題能快速對比。6. 進階把 v3.20.6 的 IPPool 調(diào)優(yōu)和版本回退技巧6.1 調(diào)整 IPPool 的塊大小和封裝模式默認(rèn)的 IPPool 是192.168.0.0/16塊大小 26 位。如果你的集群節(jié)點多、Pod 密度高這個塊大小可能不夠用。v3.20.6 支持通過 calicoctl 修改 IPPool。# ippool.yaml apiVersion: projectcalico.org/v3 kind: IPPool metadata: name: default-ipv4-ippool spec: cidr: 10.244.0.0/16 blockSize: 24 ipipMode: CrossSubnet natOutgoing: true# 應(yīng)用 IPPool 配置 calicoctl apply -f ippool.yaml # 查看當(dāng)前 IPPool calicoctl get ippool -o yaml邏輯說明blockSize: 24表示每個節(jié)點分到 /24 的塊能容納 254 個 Pod比默認(rèn)的 /26 大四倍。ipipMode: CrossSubnet表示只在跨子網(wǎng)時走 IPIP 隧道同子網(wǎng)直接路由減少封裝開銷。參數(shù)上natOutgoing: true讓 Pod 訪問集群外時做 SNAT這個一般都要開。6.2 用 calicoctl 做版本回退的檢查點如果你從 v3.20.6 往上升級或者從別的版本降回來最怕的是 datastore 里的數(shù)據(jù)格式不兼容。我的習(xí)慣是在動版本之前先把關(guān)鍵資源導(dǎo)出成 yaml 存著。# 導(dǎo)出關(guān)鍵資源作為回退檢查點 calicoctl get ippools -o yaml backup-ippools.yaml calicoctl get nodes -o yaml backup-nodes.yaml calicoctl get felixconfigurations -o yaml backup-felix.yaml邏輯說明-o yaml輸出完整資源定義包含 metadata 和 spec?;赝藭r如果發(fā)現(xiàn)新版本寫入了不兼容的字段可以用這些備份對比差異。參數(shù)上felixconfigurations是全局配置升級時容易被改單獨存一份。6.3 一個驗證 calico 數(shù)據(jù)面是否真正生效的小技巧很多人看 Pod Running 就以為網(wǎng)絡(luò)好了其實不一定。我習(xí)慣用一個更直接的辦法在節(jié)點上抓包看 Pod 發(fā)出的包有沒有被正確封裝。# 在節(jié)點上抓 IPIP 或 VXLAN 包 tcpdump -i any -n proto 4 or udp port 4789 -c 20邏輯說明proto 4是 IPIP 協(xié)議號udp port 4789是 VXLAN 默認(rèn)端口。如果跨節(jié)點 Pod 通信時能看到這些包說明封裝生效了。參數(shù)上-c 20抓 20 個包就停避免刷屏。這個辦法比看日志直觀尤其適合排查“看起來通但實際不通”的玄學(xué)問題。6.4 版本鎖定的長期維護習(xí)慣從那以后我每次部署離線 calico都會強制走一遍先docker images核對 tag再grep image:核對 yaml然后calicoctl node status確認(rèn) BGP最后跨節(jié)點 ping 一次。這套流程走下來基本不會再出現(xiàn)版本錯位導(dǎo)致的翻車。v3.20.6 這個版本雖然不算新但勝在穩(wěn)定配套的 yaml 和鏡像只要對得上跑起來很省心。如果你手頭正好有這套資源按上面的步驟走一遍應(yīng)該能少踩幾個我踩過的坑。希望幫到你。本文還有配套的精品資源點擊獲取