戰(zhàn))
我這次要分享的是在 ARM64 平臺上用 openEuler 系統(tǒng)配合 iSula 容器引擎把一套 Kubernetes 集群從零開始搭起來的完整過程。不是說搭建本身有多難而是這套組合比較特殊網(wǎng)上能搜到的資料大多數(shù)是 x86 架構(gòu) Ubuntu/CentOS Docker 的組合真正針對 ARM64 openEuler iSula 的實(shí)戰(zhàn)內(nèi)容非常少。如果你手頭正好是這類環(huán)境這篇文章會幫你省下至少一整個周末的踩坑時間。先交代一下背景我是在一批準(zhǔn) ARM 架構(gòu)的服務(wù)器上做的部署系統(tǒng)裝的是 openEuler要求統(tǒng)一使用 iSula 作為容器運(yùn)行時上層跑 Kubernetes。這個需求并不罕見很多國產(chǎn)化替代、邊緣計算、信創(chuàng)場景都會遇到。但問題是這套組合涉及到的兼容性細(xì)節(jié)非常多從內(nèi)核參數(shù)到容器運(yùn)行時插件的配置再到鏡像架構(gòu)的拉取策略任何一個環(huán)節(jié)沒有對齊最后集群都會以各種詭異的方式“半死不活”。這篇文章我會把整個部署鏈路拆開講清楚決策前的架構(gòu)判斷、openEuler 系統(tǒng)的初始配置、iSula 的正確安裝方式、kubelet 與 iSula 之間的 CRI 插件打通、用 kubeadm 拉集群、常見坑的完整排查思路以及集群跑起來之后的驗(yàn)證和維護(hù)建議。每一步都有具體的命令和配置也有我在實(shí)際環(huán)境中遇到的報錯和對應(yīng)的處理思路。文章會比較長但保證每一段都是你復(fù)制粘貼就能用的干貨。1. 部署之前先把三個決策想清楚很多人上手就裝結(jié)果裝了三天還在折騰。我不建議這么干。在敲第一條命令之前有三件事必須想清楚為什么選這套組合、架構(gòu)上有沒有隱藏的兼容性坑、CRI 的鏈路要怎么打通。這三件事想明白了后面的操作其實(shí)就是流程化執(zhí)行。1.1 為什么 openEuler iSula 值得選先說 openEuler。這是一個面向服務(wù)器場景的 Linux 發(fā)行版從內(nèi)核到用戶態(tài)工具鏈都做了不少企業(yè)級優(yōu)化對 ARM64 的支持也明顯比很多“順手支持 ARM”的系統(tǒng)要好。它不是那種社區(qū)里幾個人攢出來的玩具發(fā)行版而是有完整的軟件倉庫、更新體系和運(yùn)維工具的。在需要做國產(chǎn)化、合規(guī)化驗(yàn)收的環(huán)境里openEuler 往往是“說了算”的那個選項(xiàng)這沒什么好回避的。再說 iSula。它是與 openEuler 同生態(tài)的容器引擎套件包含了容器運(yùn)行時、鏡像構(gòu)建工具等組件。對于純?nèi)萜鬟\(yùn)行這個需求來說iSula 的設(shè)計思路是輕量和高效常駐內(nèi)存開銷比 Docker 那一套要小不少。在資源受限的邊緣節(jié)點(diǎn)上這個差異是可以感知到的。更關(guān)鍵的是iSula 提供了 CRI Plug這是一個把容器運(yùn)行時接入 Kubernetes CRI 標(biāo)準(zhǔn)的橋梁。沒有這個插件Kubernetes 根本沒辦法統(tǒng)一管理 iSula 創(chuàng)建的容器。所以這套組合的核心邏輯是系統(tǒng)層用 openEuler 保證底座的穩(wěn)定性和生態(tài)兼容容器層用 iSula 提供輕量運(yùn)行時Kubernetes 通過 CRI 標(biāo)準(zhǔn)來調(diào)度和管理它。三層各自的職責(zé)清晰集成方式也有官方路徑可走不像有些組合需要靠第三方 hack 才能跑通。1.2 ARM64 架構(gòu)兼容性是第一步檢查項(xiàng)很多人覺得既然 kubeadm 支持 ARM64那直接裝就行。理論上確實(shí)是這樣但實(shí)際會遇到很多隱性問題。最典型的就是鏡像架構(gòu)。Kubernetes 控制面組件、CoreDNS、網(wǎng)絡(luò)插件這些鏡像多數(shù)都發(fā)布了 multi-arch 版本但也有不少第三方插件或者某個特定 tag 的鏡像只有 amd64 版本。如果你的節(jié)點(diǎn)是 ARM64拉下來一個 amd64 的鏡像容器起來就是exec format error表現(xiàn)出來就是 Pod 反復(fù) CrashLoopBackOff。所以第一步不是裝軟件而是先確認(rèn)你的環(huán)境uname -m cat /etc/os-release nproc free -h我會用上面這幾條命令拿到最基礎(chǔ)的架構(gòu)、系統(tǒng)版本、CPU 和內(nèi)存信息。接下來還要確認(rèn)內(nèi)核版本和必要模塊uname -r modprobe br_netfilter cat /proc/sys/net/bridge/bridge-nf-call-iptablesARM64 平臺上內(nèi)核默認(rèn)不一定加載了br_netfilter模塊IPv4 轉(zhuǎn)發(fā)也可能沒有開啟這些不提前處理好后面 flannel 或者 Calico 的 Pod 網(wǎng)絡(luò)一定起不來。別問我怎么知道的我在第一套環(huán)境里就栽在這上面網(wǎng)絡(luò)插件 Pod 卡在ContainerCreating一整夜。最后一個要確認(rèn)的是 SELinux 的狀態(tài)。openEuler 默認(rèn)開啟了 SELinux而 iSula 與 SELinux 的配合關(guān)系比較微妙。你可以用getenforce查看當(dāng)前狀態(tài)如果是Enforcing要么提前規(guī)劃好策略要么臨時切到Permissive。對于內(nèi)網(wǎng)測試環(huán)境我建議先切 Permissive 跑通全流程后續(xù)再按安全要求收緊。生產(chǎn)環(huán)境怎么做要結(jié)合安全規(guī)范和運(yùn)維策略來決定不要把測試環(huán)境的做法直接搬到生產(chǎn)。還有一點(diǎn)容易被忽略主機(jī)名的規(guī)劃。Kubernetes 集群內(nèi)的節(jié)點(diǎn)主機(jī)名不能重復(fù)而且不能有大寫字母。你最好在部署前就把所有節(jié)點(diǎn)的主機(jī)名統(tǒng)一改成類似node-01、node-02這種格式并把它們的 IP 和主機(jī)名映射寫進(jìn)/etc/hosts。如果你不管后面 kubeadm join 時經(jīng)常會出現(xiàn) TLS 證書里的主機(jī)名和實(shí)際主機(jī)名對不上報錯信息會讓你查半天。2. 從裸機(jī)到可用集群的完整搭建鏈路2.1 系統(tǒng)準(zhǔn)備內(nèi)核參數(shù)、交換分區(qū)與主機(jī)名openEuler 默認(rèn)安裝完之后有幾項(xiàng)系統(tǒng)參數(shù)是需要調(diào)整的。每一條都要弄明白為什么調(diào)不然過兩周回頭看配置文件會有種“這段代碼是誰寫的”的困惑。第一關(guān)閉交換分區(qū)。Kubernetes 官方建議將 swap 關(guān)閉因?yàn)?kubelet 在 swap 開啟的情況下無法穩(wěn)定地做內(nèi)存管理。雖然新版本提供了--fail-swap-onfalse參數(shù)可以繞過但生產(chǎn)環(huán)境不建議這么干。處理方式swapoff -a sed -i /swap/s/^/#/ /etc/fstab第二設(shè)置內(nèi)核網(wǎng)絡(luò)參數(shù)。Kubernetes 的 Pod 網(wǎng)絡(luò)依賴 iptables 對網(wǎng)橋流量的處理。如果不開啟橋接流量的 iptables 過濾集群內(nèi) Service 的 DNAT 規(guī)則可能不生效表現(xiàn)就是跨 Pod 訪問不通。配置方法cat EOF | tee /etc/modules-load.d/k8s.conf br_netfilter nf_conntrack overlay EOF cat EOF | tee /etc/sysctl.d/k8s.conf net.bridge.bridge-nf-call-iptables 1 net.bridge.bridge-nf-call-ip6tables 1 net.ipv4.ip_forward 1 vm.swappiness 0 EOF sysctl --system第三主機(jī)名規(guī)劃。我在這套環(huán)境里用的命名規(guī)則是master-01、node-01這種簡單好記。每個節(jié)點(diǎn)執(zhí)行hostnamectl set-hostname master-01 echo 192.168.1.10 master-01 /etc/hosts這里有個細(xì)節(jié)kubeadm 初始化時會生成證書證書里的 CN 和 SAN 包含主機(jī)名和 IP。如果你之后改了主機(jī)名證書就會對不上導(dǎo)致 API Server 無法訪問。所以我們提前把所有規(guī)劃都定死后面不輕易變動。2.2 安裝 iSula不要裝成一個“殘缺版 Docker”openEuler 的官方軟件源里就有 iSula 的安裝包直接用包管理器安裝即可dnf install -y isula isula-build裝完之后先啟動 isuladsystemctl enable --now isulad systemctl status isulad這里我要多說一句安裝本身很簡單真正容易出問題的是“你以為 iSula 裝好了其實(shí)它并沒有完整地接入 Kubernetes”。isulad 是一個獨(dú)立的容器運(yùn)行時服務(wù)它自己有一套管理容器的命令入口isula 命令但它默認(rèn)不主動去監(jiān)聽 Kubernetes 發(fā)來的請求。要讓 kubelet 通過 CRI 標(biāo)準(zhǔn)調(diào)用它需要讓 isulad 開啟 CRI 支持并通過 criplug 這個組件把 CRI 的 socket 暴露出來。所以不要學(xué) Docker 時代的習(xí)慣裝完運(yùn)行時先 docker pull 一下試試就去搞 kubeadm。我們需要確認(rèn) isulad 的 CRI 插件服務(wù)狀態(tài)systemctl status criplug.socket正常的話會顯示active (listening)。如果沒起來大概率是配置文件里的路徑或者 sock 文件權(quán)限不對這個我們下一節(jié)細(xì)說。2.3 criplug 配置kubelet 能連上 isulad 的橋梁這一段是整個部署過程中“文檔里查不到”的內(nèi)容也是很多人卡住最久的地方。iSula 與 Kubernetes 的對接是通過criplug這個插件完成的。它的物理形態(tài)是一個 systemd 服務(wù)和一個 socket 文件。默認(rèn)情況下這個插件在安裝 isula 之后就會裝上但它需要滿足幾個條件才能正常工作。首先確保 socket 被正確創(chuàng)建。默認(rèn)路徑是/var/run/criplug.sock。這個名字不是系統(tǒng)本來就有的是 criplug 自己監(jiān)聽出來的。你可以用ls -l /var/run/criplug.sock看看有沒有這個文件。如果沒有重啟一下 criplug 服務(wù)systemctl restart criplug.socket systemctl restart criplug其次確認(rèn) kubelet 調(diào)用的 CRI socket 路徑一致。kubeadm 默認(rèn)去找 Docker 的 socket默認(rèn)/var/run/dockershim.sock或者 containerd 的/var/run/containerd/containerd.sock這對 iSula 是不適用的。我們需要在 kubeadm 初始化時明確指定kubeadm init --cri-socketunix:///var/run/criplug.sock ...如果你的環(huán)境里開了防火墻還要確認(rèn)本機(jī)的 TCP 和 Unix socket 訪問沒有被攔截。很多時候不是技術(shù)問題是安全策略擋了路。最后驗(yàn)證 iSula 的 CRI 接口是否響應(yīng)crictl --runtime-endpoint unix:///var/run/criplug.sock info如果這條命令能正確返回運(yùn)行時信息說明 CRI 鏈路已經(jīng)通了。到這一步kubelet 才真正“看得見” iSula 管理的容器。2.4 kubeadm 初始化版本、鏡像、時區(qū)一并搞定安裝 kubeadm、kubelet、kubectl 這些組件比較直接從 openEuler 的 Kubernetes 軟件源或者網(wǎng)上大家常用的源拉就行dnf install -y kubeadm kubelet kubectl systemctl enable --now kubelet這里最值得操作的是 kubeadm 的配置文件。很多人都直接kubeadm init一把梭但在這套組合里必須明確寫入 CRI socket否則初始化會直接失敗報錯信息會告訴你找不到 runtime# kubeadm-config.yaml apiVersion: kubeadm.k8s.io/v1beta4 kind: ClusterConfiguration kubernetesVersion: v1.28.5 networking: podSubnet: 10.244.0.0/16 serviceSubnet: 10.96.0.0/12 --- apiVersion: kubeadm.k8s.io/v1beta4 kind: InitConfiguration nodeRegistration: criSocket: unix:///var/run/criplug.sock執(zhí)行初始化kubeadm init --configkubeadm-config.yaml --cri-socketunix:///var/run/criplug.sockARM64 平臺還需要提前關(guān)注一個問題pause 鏡像的架構(gòu)。kubeadm 初始化時要拉取pause鏡像作為每個 Pod 的“根容器”如果你用的鏡像倉庫里只有 amd64 版本初始化就會失敗。建議提前確認(rèn)你指定的 pause 鏡像是否支持 arm64或者準(zhǔn)備一個私有鏡像倉庫手動把 arm64 版本的鏡像推上去。初始化成功后會生成一串kubeadm join命令務(wù)必存好。如果要拼接 worker 節(jié)點(diǎn)就用這串命令加上同樣的--cri-socket參數(shù)去執(zhí)行。2.5 網(wǎng)絡(luò)插件選 flannel 還是 Calico 要按架構(gòu)來kubeadm 初始化完成之后控制面節(jié)點(diǎn)會進(jìn)入 NotReady 狀態(tài)因?yàn)檫€沒有網(wǎng)絡(luò)插件。我在這套 ARM64 環(huán)境里先嘗試了 flannel因?yàn)樗溺R像相對精簡配置也直觀。但很快發(fā)現(xiàn) flannel 的鏡像在網(wǎng)絡(luò)受限的環(huán)境中拉取速度慢而且對內(nèi)核模塊的依賴也需要額外確認(rèn)。后來切換到了 Calico整體更穩(wěn)定資源占用也可以接受。如果你只是測試環(huán)境flannel 夠用如果面向生產(chǎn)Calico 的靈活性和網(wǎng)絡(luò)策略支持更好。以 Calico 為例kubectl apply -f https://raw.githubusercontent.com/projectcalico/calico/v3.27/manifests/calico.yaml注意 yaml 里的鏡像地址。因?yàn)榫W(wǎng)絡(luò)原因國內(nèi)環(huán)境經(jīng)常拉不到 Calico 官方倉庫的鏡像需要提前改鏡像。有私有倉庫的環(huán)境建議直接sed替換成私有倉庫地址sed -i s#docker.io/#registry.internal/# calico.yaml網(wǎng)絡(luò)插件 Pod 的狀態(tài)是判斷集群健康度的關(guān)鍵指標(biāo)。不要只看 Pod 變成 Running 就算完還要確認(rèn)每個節(jié)點(diǎn)上的 CNI 配置文件已經(jīng)生成到位。如果你發(fā)現(xiàn)calico-nodePod 報了Error排查的時候一定要看節(jié)點(diǎn)上的內(nèi)核是否加載了nf_conntrack等模塊。這些模塊在 ARM64 的 openEuler 上默認(rèn)未必加載而 Calico 的 felix 需要它們來管理 iptables 規(guī)則。3. 部署中真正折磨人的三個坑這一節(jié)我想把我在部署過程中遇到的最棘手的三個問題完整復(fù)盤一遍不只是給結(jié)論而是把整個排查鏈路展示出來。因?yàn)楹芏鄦栴}你上網(wǎng)搜不到任何記錄只能靠排查思路來破局。3.1 報錯“exec format error”鏡像架構(gòu)與節(jié)點(diǎn)不匹配現(xiàn)象某個 Pod 創(chuàng)建之后一直 CrashLoopBackOffkubectl logs沒有任何輸出kubectl describe拉到的事件也只是正常的 Kill、BackOff。查了 Confirm 階段的日志才發(fā)現(xiàn)問題。排查過程先看 Pod 里容器的啟動命令是什么。有些鏡像的入口腳本帶有架構(gòu)判斷我們這次用的鏡像看起來是 multi-arch但里面的 binary 實(shí)際上只有 amd64 版本。手動在這個節(jié)點(diǎn)上用crictl pull拉取同一鏡像再用crictl run跑了一下報錯信息明確指向了架構(gòu)不匹配。確認(rèn)問題后替換為正確支持 arm64 的鏡像 tag或者重新構(gòu)建。還有個隱藏坑有時候鏡像名稱沒有帶架構(gòu)后綴倉庫會根據(jù)請求的架構(gòu)返回對應(yīng)的 manifest但如果倉庫服務(wù)端不支持按架構(gòu)分發(fā)所有節(jié)點(diǎn)都會拿到同一個 amd64 鏡像。所以遇到exec format error先不要懷疑是不是權(quán)限問題、配置問題先把鏡像的架構(gòu)標(biāo)簽和節(jié)點(diǎn)架構(gòu)對照一遍用二進(jìn)制級別的確認(rèn)來代替猜。一條命令就能確認(rèn)docker manifest inspect 鏡像名 | grep architecture如果手里沒有 docker也可以用crictl和skopeo這類工具??傊却_認(rèn)鏡像的 manifest 列表里到底有沒有 arm64 這一項(xiàng)沒有就別裝了。3.2 節(jié)點(diǎn)狀態(tài) Ready 但 Pod 一直 Pendingcgroup 驅(qū)動不一致現(xiàn)象kubeadm 初始化成功網(wǎng)絡(luò)插件也安裝了但所有 Pod包括控制面的 Pod全部卡在 Pending節(jié)點(diǎn)狀態(tài)明明是 Ready。我當(dāng)時的排查鏈路可以整理成四步首先懷疑的是資源不足。kubectl describe node看可分配資源CPU 和內(nèi)存都充足tolerance 也允許調(diào)度排除。接著懷疑 kubelet 沒有正確上報狀態(tài)。查看systemctl status kubelet一切正常。再懷疑調(diào)度器問題查看了 scheduler 日志也沒有發(fā)現(xiàn)異常。最后實(shí)在沒招了去翻了 isulad 的系統(tǒng)日志發(fā)現(xiàn)它在與 kubelet 通信時不斷在報錯。最終定位kubelet 默認(rèn)使用systemd作為 cgroup 驅(qū)動而 isulad 默認(rèn)可能使用的不是systemd兩者不一致導(dǎo)致 kubelet 無法準(zhǔn)確獲取容器的狀態(tài)進(jìn)而無法正常對 Pod 做資源統(tǒng)計和調(diào)度決策。解決辦法有兩類統(tǒng)一讓 iSula 使用 systemd cgroup 驅(qū)動。在 isulad 的配置文件通常是/etc/isulad/daemon.json中設(shè)置cgroup-manager: systemd然后重啟 isulad?;蛘叻催^來讓 kubelet 使用容器運(yùn)行時默認(rèn)的 cgroup driver。但這樣不太好因?yàn)槎鄶?shù)的監(jiān)控和運(yùn)維組件默認(rèn)會去看 systemd 的 cgroup 樹。這個坑為什么難排查因?yàn)樗皇侵苯訄箦e而是讓所有 Pod 處于 Pending 狀態(tài)表面看起來一切正常但調(diào)度器就是不愿意把 Pod 放上去。如果你也遇到類似情況優(yōu)先看看 kubelet 和容器運(yùn)行時的 cgroup 驅(qū)動是不是同一個這一步檢查成本極低排除成本極高。3.3 網(wǎng)絡(luò)插件起不來缺失的的內(nèi)核模塊現(xiàn)象Calico 的calico-nodePod 在某個節(jié)點(diǎn)上始終是CrashLoopBackOff日志里提示缺少某些 iptables 相關(guān)的支持。排查過程先查看該節(jié)點(diǎn)的內(nèi)核模塊列表lsmod | grep br_netfilter發(fā)現(xiàn)沒有加載。在架構(gòu)為 ARM64 的 openEuler 上br_netfilter和nf_conntrack默認(rèn)可能不在已加載模塊列表里。手動modprobe br_netfilter再重啟 Calico Pod狀態(tài)恢復(fù)但這只是臨時方案因?yàn)楣?jié)點(diǎn)重啟后又會丟。最后通過/etc/modules-load.d/k8s.conf文件把它們固定下來再執(zhí)行sysctl --system加載參數(shù)。這個坑我覺得很值得寫出來ARM64 環(huán)境的內(nèi)核模塊加載策略跟傳統(tǒng) x86 發(fā)行版確實(shí)有差異不要想當(dāng)然認(rèn)為“標(biāo)準(zhǔn)內(nèi)核就帶這些”每一臺節(jié)點(diǎn)都要實(shí)際檢查一遍。把模塊加載和系統(tǒng)參數(shù)固化到配置文件的方案至少保證節(jié)點(diǎn)重啟后還能正常加入集群不會出現(xiàn)“集群白天好好的晚上一重啟就廢了”的尷尬局面。4. 集群跑通之后怎么驗(yàn)證和維護(hù)4.1 功能驗(yàn)證三板斧集群搭完不是終點(diǎn)要證明它能干活至少做三件事第一跑一個簡單的無狀態(tài)應(yīng)用kubectl create deployment nginx-test --imagenginx:alpine kubectl scale deployment nginx-test --replicas3 kubectl get pods -o wide如果 Pod 分布在多個節(jié)點(diǎn)上說明調(diào)度正常。然后檢查 Service 的聯(lián)通性kubectl expose deployment nginx-test --port80 --typeNodePort kubectl get svc nginx-test curl http://任意節(jié)點(diǎn)IP:NodePort第二步驗(yàn)證 DNS 解析。在集群內(nèi)創(chuàng)建一個測試 Pod進(jìn)入后nslookupKubernetes 的 Service 名稱如果解析正常說明 CoreDNS 工作正常這是集群內(nèi)部服務(wù)發(fā)現(xiàn)的基礎(chǔ)。第三步驗(yàn)證跨節(jié)點(diǎn)通信。讓 Pod 分布在兩個不同節(jié)點(diǎn)上從一個 Pod 直接 ping 另一個 Pod 的 IP或者通過 Service 的 ClusterIP 訪問。只有這些打通了才能說網(wǎng)絡(luò)插件真的合格了。4.2 證書過期與 etcd 備份提醒kubeadm 簽發(fā)的證書默認(rèn)有效期是 1 年。這個時間說長不長說短不短但如果不提前做規(guī)劃到時間點(diǎn)集群會突然之間不可用。建議在集群部署完成的那一刻起就在日歷上標(biāo)注證書到期日提前 2-4 周安排更新。查看證書有效期kubeadm certs check-expiration更新命令kubeadm certs renew all kubeadm init phase kubeconfig --configkubeadm-config.yaml systemctl restart kubelet再一個不能拖的事情是 etcd 備份。我見過太多人覺得單節(jié)點(diǎn)集群不用備 etcd結(jié)果一次誤操作把核心資源刪了之后無從恢復(fù)。kubeadm 控制面組件和 etcd 都跑在容器里etcd 的數(shù)據(jù)目錄默認(rèn)掛載在宿主機(jī)的/var/lib/etcd建議用定時任務(wù)把整個目錄做快照cp -r /var/lib/etcd /backup/etcd-$(date %F)條件允許的話盡量用 etcd 自帶的 snapshot 接口做一致性快照etcdctl snapshot save /backup/etcd-snapshot-$(date %F).db4.3 日常運(yùn)維常用命令對照表在跑這套集群維護(hù)了幾個月之后我總結(jié)了一套自己的“巡檢清單”。這張表建議收藏尤其是剛接觸 iSula 的朋友場景Docker 習(xí)慣命令openEuler iSula 命令查看所有容器docker ps -aisula ps -a查看容器詳情docker inspectisula inspect進(jìn)入容器docker exec -itisula exec -it查看日志直接看容器內(nèi)進(jìn)程docker logsisula logs查看 Pod 對應(yīng)的容器狀態(tài)kubectl describe podcrictl --runtime-endpoint unix:///var/run/criplug.sock ps清理臨時鏡像docker image pruneisula image prune 需要根據(jù) isula 版本確認(rèn)集群巡檢時我常用的順序是kubectl get nodes -o wide先看節(jié)點(diǎn)狀態(tài)和版本是否統(tǒng)一kubectl get pods -A -o wide看全局 Pod 狀態(tài)是否有非 Running 項(xiàng)systemctl status isulad和journalctl -u isulad --no-pager | tail -50看容器引擎自身的健康狀況df -h /var/lib注意 isulad 默認(rèn)存儲路徑的空間使用率這是最容易不知不覺打滿的隱患。我得說一句大實(shí)話在 ARM64 平臺上Kubernetes 集群跑起來只是開始真正的維護(hù)難點(diǎn)在于“檢查項(xiàng)和 x86 環(huán)境的差異點(diǎn)”。舉個例子x86 環(huán)境你可能從來不用關(guān)心內(nèi)核加載了哪些模塊但在 ARM64 的 openEuler 上這些差異會被放大。所以在巡檢時一定要把架構(gòu)相關(guān)的檢查項(xiàng)單獨(dú)列出來每次都確認(rèn)一遍。5. 最后分享一個省心小技巧在連續(xù)搭了三套同樣的環(huán)境之后我養(yǎng)成一個習(xí)慣把整套部署過程沉淀成一個標(biāo)準(zhǔn)化的腳本和一份檢查清單。腳本負(fù)責(zé)裝軟件、改配置、拉鏡像檢查清單負(fù)責(zé)在每執(zhí)行完一個階段后用那幾條我上面反復(fù)強(qiáng)調(diào)的關(guān)鍵命令去驗(yàn)證狀態(tài)。這樣做的原因是手動敲命令部署一次可能只要兩小時其中最耗時間的部分并不是敲命令本身而是卡在某個坑里沒有頭緒地排查。腳本化之后這個時間可以壓縮到 20 分鐘以內(nèi)。另一個值得做的是鏡像倉庫的提前準(zhǔn)備。如果你所在的內(nèi)網(wǎng)訪問外網(wǎng)有限提前準(zhǔn)備好了 arm64 相關(guān)的所有鏡像并推到私有倉庫部署時會省掉無數(shù)等待時間。我甚至?xí)?pause、coredns、calico 這些組件的鏡像全部固化到一個離線鏡像包里用 iSula 自帶的鏡像導(dǎo)入命令批量導(dǎo)入。這一步做完之后后續(xù)擴(kuò)容新節(jié)點(diǎn)時就會非常順滑不再需要在網(wǎng)絡(luò)上反復(fù)等待。每次給新環(huán)境裝這套集群我都會被同事吐槽“你怎么又要重來一遍”但恰恰是這種不厭其煩的重復(fù)讓我把整套流程里的所有不確定因素都變成了已知項(xiàng)?,F(xiàn)在再遇到 ARM64 openEuler iSula 的環(huán)境我基本不需要看文檔了因?yàn)榭佣疾绕搅?。這篇文章的內(nèi)容就是這些坑和應(yīng)對辦法的完整記錄希望它也能幫你把這條路走平。