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