
簡介這份資源面向需要在 Kubernetes 上部署 Nacos 集群的運維與后端開發(fā)人員尤其適合剛接觸 K8s 編排、希望跳過繁瑣配置直接跑通集群的初學(xué)者。它把 Nacos 集群部署拆解為按執(zhí)行順序排列的極簡腳本覆蓋數(shù)據(jù)庫配置、Headless Service、StatefulSet、Service 以及 Ingress 暴露等關(guān)鍵環(huán)節(jié)省去大量手工調(diào)試成本。壓縮包共 6 個文件以 5 個 yaml 清單為主分別承擔(dān)數(shù)據(jù)庫連接、無頭服務(wù)、有狀態(tài)副本集、服務(wù)暴露與外部訪問入口等職責(zé)另附 1 個 txt 說明文件整體僅約 3KB輕量易讀。目前已有 761 人學(xué)習(xí)下載說明該方案在實際部署場景中具備一定參考價值。讀者可據(jù)此快速搭建可用的 Nacos 集群環(huán)境理解各資源對象的先后依賴關(guān)系并在此基礎(chǔ)上按需調(diào)整副本數(shù)、存儲與域名配置減少從零編寫清單的試錯時間。1. 從一堆散裝 YAML 到能扛住重啟的 Nacos 集群這套腳本到底在解決什么很多人第一次在 k8s 上部署 Nacos都是先kubectl apply一個官方示例跑起來看到 Pod 是 Running 就以為完事了。結(jié)果服務(wù)一重啟配置丟了節(jié)點一擴容集群選主亂了生產(chǎn)環(huán)境一壓測注冊中心直接腦裂。問題的根子不在 Nacos 本身而在于那堆散裝的 YAML 沒有把「集群」兩個字當(dāng)回事——StatefulSet 的穩(wěn)定網(wǎng)絡(luò)標(biāo)識、持久化存儲的掛載路徑、MySQL 外置數(shù)據(jù)源的連接池參數(shù)、JVM 堆內(nèi)存與容器 limit 的匹配關(guān)系任何一項沒對齊集群就是紙糊的。這篇筆記要拆的就是一套能直接抄作業(yè)的 k8s Nacos 集群部署腳本與 YAML 組合。它解決的不是「能不能跑起來」而是「跑起來之后能不能扛住滾動更新、節(jié)點故障和配置熱更新」。適合已經(jīng)會用 kubectl、懂一點 StatefulSet 和 Service 概念但還沒在生產(chǎn)環(huán)境把 Nacos 集群真正落地的后端或運維工程師。如果你正在搜 k8s 部署教程、nacos 集群部署腳本或者糾結(jié) consul 和 nacos 的區(qū)別到底該選哪個下面的內(nèi)容會從 YAML 的每一段參數(shù)講起把踩過的坑和驗證方法一并交代清楚。2. 為什么 Nacos 集群在 k8s 上必須用 StatefulSet 而不是 Deployment2.1 從 Nacos 的集群尋址機制倒推工作負(fù)載選型Nacos 集群節(jié)點之間需要互相感知靠的是cluster.conf里寫死的節(jié)點列表或者環(huán)境變量nacos.member.list指定的地址。每個節(jié)點啟動時要知道其他節(jié)點的 IP 或域名才能組成 Raft 集群完成選主和數(shù)據(jù)同步。Deployment 創(chuàng)建的 Pod 名字是隨機哈希重啟后 IP 變了、名字也變了cluster.conf根本沒法維護(hù)一個穩(wěn)定的成員列表。StatefulSet 給每個 Pod 分配固定的序號和穩(wěn)定的 DNS 域名比如nacos-0.nacos-headless.default.svc.cluster.local這樣cluster.conf里寫域名就能長期有效節(jié)點重啟后重新注冊到同一個域名上集群成員關(guān)系不會亂。另一個關(guān)鍵點是存儲。Nacos 默認(rèn)用內(nèi)嵌 Derby 數(shù)據(jù)庫單機沒問題集群模式下必須外置 MySQL。但即便如此每個 Nacos 節(jié)點本地還有data目錄用于存儲 Raft 日志和快照。如果用 Deployment 加 emptyDirPod 一漂移日志就沒了節(jié)點重新加入集群時可能因為日志缺失導(dǎo)致數(shù)據(jù)不一致。StatefulSet 配合 volumeClaimTemplates 給每個 Pod 掛一塊獨立的 PVCRaft 日志和本地緩存才能持久化這是集群穩(wěn)定性的底線。2.2 一個最小可用的 StatefulSet YAML 骨架與逐段拆解下面這份 YAML 是我在多個環(huán)境里收斂出來的骨架去掉了花哨的 sidecar只保留 Nacos 集群運行必需的部分。注意看serviceName、podManagementPolicy和volumeClaimTemplates這三處它們是 StatefulSet 區(qū)別于 Deployment 的核心。apiVersion: apps/v1 kind: StatefulSet metadata: name: nacos namespace: middleware spec: serviceName: nacos-headless # 必須指向 Headless Service否則 Pod 沒有穩(wěn)定 DNS replicas: 3 # 集群節(jié)點數(shù)生產(chǎn)建議 3 或 5 podManagementPolicy: Parallel # 并行啟動加快集群組建速度 selector: matchLabels: app: nacos template: metadata: labels: app: nacos spec: affinity: podAntiAffinity: # 反親和盡量把 Pod 打散到不同節(jié)點 preferredDuringSchedulingIgnoredDuringExecution: - weight: 100 podAffinityTerm: labelSelector: matchLabels: app: nacos topologyKey: kubernetes.io/hostname containers: - name: nacos image: nacos/nacos-server:v2.3.2 # 版本按需替換不要用 latest env: - name: MODE value: cluster # 必須顯式聲明集群模式 - name: NACOS_SERVERS value: nacos-0.nacos-headless.middleware.svc.cluster.local:8848 nacos-1.nacos-headless.middleware.svc.cluster.local:8848 nacos-2.nacos-headless.middleware.svc.cluster.local:8848 - name: SPRING_DATASOURCE_PLATFORM value: mysql # 使用外置 MySQL - name: MYSQL_SERVICE_HOST value: mysql.middleware.svc.cluster.local - name: MYSQL_SERVICE_PORT value: 3306 - name: MYSQL_SERVICE_DB_NAME value: nacos_config - name: MYSQL_SERVICE_USER value: nacos - name: MYSQL_SERVICE_PASSWORD value: nacos_password - name: JVM_XMS value: 2g # 堆初始值與 limit 保持比例 - name: JVM_XMX value: 2g # 堆最大值建議不超過 limit 的 70% - name: JVM_XMN value: 1g # 新生代約為 Xmx 的一半 ports: - containerPort: 8848 # 主服務(wù)端口 - containerPort: 9848 # gRPC 端口2.x 必須暴露 - containerPort: 9849 # gRPC 端口2.x 必須暴露 volumeMounts: - name: nacos-data mountPath: /home/nacos/data # Raft 日志和本地緩存 - name: nacos-logs mountPath: /home/nacos/logs # 日志持久化方便排查 readinessProbe: tcpSocket: port: 8848 initialDelaySeconds: 30 periodSeconds: 10 livenessProbe: tcpSocket: port: 8848 initialDelaySeconds: 60 periodSeconds: 20 volumeClaimTemplates: - metadata: name: nacos-data spec: accessModes: [ReadWriteOnce] storageClassName: standard # 按集群實際 StorageClass 替換 resources: requests: storage: 10Gi - metadata: name: nacos-logs spec: accessModes: [ReadWriteOnce] storageClassName: standard resources: requests: storage: 5Gi這份 YAML 里最容易被忽略的是NACOS_SERVERS環(huán)境變量。Nacos 2.x 官方鏡像支持用這個變量直接生成cluster.conf省去手動掛 ConfigMap 的麻煩。但要注意變量里的域名必須和 Headless Service 的命名規(guī)則完全一致格式是pod-name.service-name.namespace.svc.cluster.local。如果 namespace 寫錯或者 serviceName 對不上節(jié)點之間就互相找不到日志里會一直刷failed to connect to server。podManagementPolicy: Parallel是為了讓三個 Pod 同時啟動而不是等前一個 Ready 再起下一個。Nacos 集群需要多數(shù)節(jié)點在線才能完成選主串行啟動會導(dǎo)致第一個 Pod 一直卡在選主階段直到第二個 Pod 起來才能繼續(xù)白白拉長部署時間。并行啟動配合就緒探針能讓集群更快進(jìn)入可用狀態(tài)。資源限制方面JVM_XMS和JVM_XMX建議設(shè)成一樣避免堆動態(tài)伸縮帶來的性能抖動。JVM_XMN設(shè)為Xmx的一半左右這是 Nacos 官方推薦的配比。如果容器 limit 設(shè)了 4Gi堆最大給 2.5Gi 到 3Gi 比較穩(wěn)妥留出堆外內(nèi)存給 gRPC 和 Netty 的直接緩沖區(qū)。見過太多因為堆內(nèi)存超過 limit 導(dǎo)致 Pod 被 OOMKilled 的案例重啟后集群重新選主業(yè)務(wù)側(cè)注冊列表瞬間清空這就是典型的「翻車」現(xiàn)場。3. Headless Service 與 MySQL 外置數(shù)據(jù)源的 YAML 配置細(xì)節(jié)3.1 Headless Service 的 YAML 寫法與 DNS 驗證方法StatefulSet 的serviceName指向的 Headless Service 必須單獨創(chuàng)建它的clusterIP: None是硬性要求。沒有這行k8s 會給 Service 分配一個虛擬 IPPod 的 DNS 解析就變成負(fù)載均衡地址而不是具體的 Pod 域名StatefulSet 的穩(wěn)定網(wǎng)絡(luò)標(biāo)識就失效了。apiVersion: v1 kind: Service metadata: name: nacos-headless namespace: middleware labels: app: nacos spec: clusterIP: None # Headless Service 的關(guān)鍵標(biāo)志 selector: app: nacos ports: - name: server port: 8848 targetPort: 8848 - name: grpc-client port: 9848 targetPort: 9848 - name: grpc-server port: 9849 targetPort: 9849創(chuàng)建完 Service 后可以起一個臨時 Pod 用nslookup驗證 DNS 解析是否正常。命令如下kubectl run -it --rm debug --imagebusybox:1.36 --restartNever -n middleware -- nslookup nacos-0.nacos-headless.middleware.svc.cluster.local如果返回的 IP 是具體某個 Pod 的地址說明 Headless Service 生效了。如果返回的是 Service 的 ClusterIP 或者解析失敗就要檢查 Service 的clusterIP字段是否真的設(shè)成了None以及 Pod 的 label 是否和 Service 的 selector 匹配。這個驗證步驟花不了一分鐘但能省掉后面排查集群成員發(fā)現(xiàn)失敗的好幾個小時。3.2 外置 MySQL 的庫表初始化與連接池參數(shù)調(diào)優(yōu)Nacos 集群模式必須用外置數(shù)據(jù)庫官方推薦 MySQL 5.7 或 8.0。初始化 SQL 在 Nacos 發(fā)行包的conf/mysql-schema.sql里直接導(dǎo)入即可。但導(dǎo)入之前數(shù)據(jù)庫的字符集要設(shè)成utf8mb4排序規(guī)則用utf8mb4_general_ci否則配置內(nèi)容里有中文或特殊字符時會報錯。CREATE DATABASE nacos_config DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; CREATE USER nacos% IDENTIFIED BY nacos_password; GRANT ALL PRIVILEGES ON nacos_config.* TO nacos%; FLUSH PRIVILEGES;連接池參數(shù)在 Nacos 的application.properties里控制但用官方鏡像時可以通過環(huán)境變量覆蓋。關(guān)鍵參數(shù)有三個db.pool.config.maximumPoolSize、db.pool.config.minimumIdle和db.pool.config.connectionTimeout。默認(rèn)最大連接數(shù)是 50對于三個 Nacos 節(jié)點、每個節(jié)點并發(fā)讀寫配置的場景建議調(diào)到 100 左右。最小空閑連接保持 10 到 20避免頻繁創(chuàng)建連接的開銷。連接超時設(shè) 3000 毫秒太短容易在數(shù)據(jù)庫抖動時誤判太長會拖慢故障轉(zhuǎn)移。# 在 StatefulSet 的 env 里追加 - name: DB_POOL_CONFIG_MAXIMUM_POOL_SIZE value: 100 - name: DB_POOL_CONFIG_MINIMUM_IDLE value: 20 - name: DB_POOL_CONFIG_CONNECTION_TIMEOUT value: 3000這里有個血淚經(jīng)驗MySQL 的max_connections也要同步調(diào)大。三個 Nacos 節(jié)點各 100 個連接加上其他業(yè)務(wù)如果 MySQL 默認(rèn)的 151 個連接數(shù)沒改Nacos 啟動到一半就會報Too many connections然后節(jié)點反復(fù)重啟集群永遠(yuǎn)湊不齊多數(shù)派。改完 MySQL 參數(shù)記得重啟數(shù)據(jù)庫或者動態(tài)生效別只改配置文件忘了 reload。3.3 用初始化腳本自動導(dǎo)入 SQL 并校驗表結(jié)構(gòu)如果不想手動導(dǎo)入 SQL可以在部署 Nacos 之前跑一個 Job用 MySQL 客戶端鏡像自動執(zhí)行初始化腳本。這樣整個部署流程就能完全腳本化適合放進(jìn) CI/CD 流水線。apiVersion: batch/v1 kind: Job metadata: name: nacos-db-init namespace: middleware spec: template: spec: containers: - name: mysql-client image: mysql:8.0 command: - bash - -c - | mysql -h mysql.middleware.svc.cluster.local -u root -p$MYSQL_ROOT_PASSWORD -e CREATE DATABASE IF NOT EXISTS nacos_config DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; mysql -h mysql.middleware.svc.cluster.local -u root -p$MYSQL_ROOT_PASSWORD nacos_config /sql/nacos-schema.sql env: - name: MYSQL_ROOT_PASSWORD valueFrom: secretKeyRef: name: mysql-root-secret key: password volumeMounts: - name: sql-script mountPath: /sql volumes: - name: sql-script configMap: name: nacos-sql-configmap restartPolicy: OnFailure這個 Job 的關(guān)鍵是把nacos-schema.sql放進(jìn) ConfigMap然后掛載到容器里執(zhí)行。執(zhí)行完成后可以用kubectl logs job/nacos-db-init -n middleware查看輸出確認(rèn)沒有報錯。之后再部署 StatefulSetNacos 啟動時就能直接連上已經(jīng)建好表的數(shù)據(jù)庫省去啟動階段的建表邏輯集群組建速度會快不少。4. 集群部署腳本的編排順序與滾動更新策略4.1 用 Shell 腳本串聯(lián) Namespace、Secret、Service、StatefulSet 的創(chuàng)建順序手動一個個kubectl apply容易漏文件也不方便重復(fù)執(zhí)行。我一般會寫一個deploy-nacos.sh按依賴順序把 YAML 文件串起來。腳本里加上set -e任何一步失敗就停住避免帶著錯誤狀態(tài)繼續(xù)往下走。#!/bin/bash set -euo pipefail NAMESPACEmiddleware SCRIPT_DIR$(cd $(dirname ${BASH_SOURCE[0]}) pwd) echo 創(chuàng)建 Namespace kubectl apply -f ${SCRIPT_DIR}/00-namespace.yaml echo 創(chuàng)建 MySQL 連接 Secret kubectl apply -f ${SCRIPT_DIR}/01-mysql-secret.yaml echo 初始化 Nacos 數(shù)據(jù)庫 kubectl apply -f ${SCRIPT_DIR}/02-db-init-job.yaml kubectl wait --forconditioncomplete job/nacos-db-init -n ${NAMESPACE} --timeout120s echo 創(chuàng)建 Headless Service kubectl apply -f ${SCRIPT_DIR}/03-headless-service.yaml echo 部署 Nacos StatefulSet kubectl apply -f ${SCRIPT_DIR}/04-nacos-statefulset.yaml echo 等待集群就緒 kubectl rollout status statefulset/nacos -n ${NAMESPACE} --timeout300s echo 部署完成檢查 Pod 狀態(tài) kubectl get pods -n ${NAMESPACE} -l appnacos -o wide這個腳本里kubectl wait和kubectl rollout status是兩個關(guān)鍵等待點。前者確保數(shù)據(jù)庫初始化 Job 跑完再部署 Nacos后者確保 StatefulSet 的所有 Pod 都進(jìn)入 Ready 狀態(tài)再返回。沒有這兩個等待腳本執(zhí)行完立刻去訪問 Nacos很可能因為集群還沒選主完成而返回 503。4.2 StatefulSet 的 RollingUpdate 策略與 Pod 中斷預(yù)算Nacos 集群默認(rèn)的滾動更新策略是RollingUpdate但 StatefulSet 的更新順序是從序號最大的 Pod 開始逐個替換。對于三節(jié)點集群更新順序是 nacos-2、nacos-1、nacos-0。這個過程中只要多數(shù)節(jié)點在線集群就能正常提供服務(wù)。但如果不加 PodDisruptionBudget節(jié)點維護(hù)時可能一次性驅(qū)逐多個 Pod導(dǎo)致集群失去多數(shù)派。apiVersion: policy/v1 kind: PodDisruptionBudget metadata: name: nacos-pdb namespace: middleware spec: minAvailable: 2 # 至少保持 2 個 Pod 可用 selector: matchLabels: app: nacosminAvailable: 2意味著任何自愿中斷比如節(jié)點排水最多只能同時影響一個 Pod。對于三節(jié)點集群這保證了任意時刻至少有兩個節(jié)點在線Raft 多數(shù)派不會丟。如果是五節(jié)點集群可以設(shè)成 3。這個 PDB 在集群日常運維中非常有用尤其是 k8s 節(jié)點需要升級或重啟的時候沒有它驅(qū)逐操作可能直接把 Nacos 集群打掛。4.3 驗證集群選主狀態(tài)與配置寫入的完整命令部署完成后怎么確認(rèn)集群真的組成了而不是三個孤立的單機最直接的方法是看 Nacos 的集群管理接口。先隨便進(jìn)一個 Pod用 curl 調(diào)/nacos/v1/ns/operator/servers接口。kubectl exec -it nacos-0 -n middleware -- curl -s http://localhost:8848/nacos/v1/ns/operator/servers返回的 JSON 里會列出所有節(jié)點的 IP、狀態(tài)和擴展信息。如果三個節(jié)點都出現(xiàn)在列表里并且state是UP說明集群成員發(fā)現(xiàn)正常。如果只看到一個節(jié)點或者某個節(jié)點狀態(tài)是DOWN就要去查那個節(jié)點的日志重點看cluster.conf生成的內(nèi)容和NACOS_SERVERS環(huán)境變量是否一致。再進(jìn)一步可以寫一條配置然后從另一個節(jié)點讀出來驗證數(shù)據(jù)同步。# 在 nacos-0 上寫配置 kubectl exec -it nacos-0 -n middleware -- curl -X POST http://localhost:8848/nacos/v1/cs/configs -d dataIdtest.yamlgroupDEFAULT_GROUPcontentkey: value # 在 nacos-1 上讀配置 kubectl exec -it nacos-1 -n middleware -- curl -s http://localhost:8848/nacos/v1/cs/configs?dataIdtest.yamlgroupDEFAULT_GROUP如果 nacos-1 能讀到key: value說明 Raft 日志復(fù)制和數(shù)據(jù)庫持久化都正常。讀不到的話先檢查 MySQL 里config_info表有沒有數(shù)據(jù)再檢查節(jié)點之間的 9848 端口是否互通。Nacos 2.x 的 gRPC 通信依賴 9848 和 9849 端口如果 NetworkPolicy 或者防火墻沒放行節(jié)點之間能 ping 通但數(shù)據(jù)同步不了這種問題最隱蔽。5. 部署 Nacos 集群時最容易翻車的五個地方5.1 現(xiàn)象Pod 一直 CrashLoopBackOff日志報No DataSource set原因環(huán)境變量SPRING_DATASOURCE_PLATFORM沒設(shè)成mysql或者 MySQL 連接信息不完整。Nacos 啟動時檢測不到外置數(shù)據(jù)源又因為MODEcluster不允許回退到內(nèi)嵌 Derby直接啟動失敗。解決檢查 StatefulSet 里SPRING_DATASOURCE_PLATFORM、MYSQL_SERVICE_HOST、MYSQL_SERVICE_PORT、MYSQL_SERVICE_DB_NAME、MYSQL_SERVICE_USER、MYSQL_SERVICE_PASSWORD這六個變量是否全部設(shè)置且值正確。特別注意密碼里如果有特殊字符要確認(rèn) Secret 的 base64 編碼沒有引入換行符。5.2 現(xiàn)象集群三個 Pod 都 Running但注冊的服務(wù)列表為空原因Nacos 節(jié)點之間沒有組成集群每個節(jié)點各自為政。常見原因是NACOS_SERVERS里的域名解析失敗或者 Headless Service 的clusterIP沒有設(shè)成None。解決進(jìn) Pod 執(zhí)行nslookup nacos-1.nacos-headless.middleware.svc.cluster.local確認(rèn)能解析到具體 IP。如果解析到的是 Service 的 ClusterIP回去檢查 Headless Service 的 YAMLclusterIP: None必須存在。另外確認(rèn)NACOS_SERVERS里的 namespace 和實際部署的 namespace 一致大小寫敏感。5.3 現(xiàn)象滾動更新時業(yè)務(wù)側(cè)出現(xiàn)大量服務(wù)下線告警原因StatefulSet 更新時Pod 被終止前沒有足夠的時間把注冊的服務(wù)摘除或者 PDB 沒設(shè)導(dǎo)致多個 Pod 同時被驅(qū)逐。解決給 Nacos 容器加preStop鉤子在終止前先調(diào)用下線接口再 sleep 一段時間等流量摘除。lifecycle: preStop: exec: command: - bash - -c - | curl -X DELETE http://localhost:8848/nacos/v1/ns/instance?serviceName...ip${POD_IP}port... sleep 10同時確認(rèn) PDB 的minAvailable至少是replicas - 1三節(jié)點集群設(shè) 2五節(jié)點設(shè) 3。這樣滾動更新時最多影響一個 Pod業(yè)務(wù)側(cè)感知不到明顯抖動。5.4 現(xiàn)象Nacos 節(jié)點頻繁 OOMKilled重啟后集群重新選主原因JVM 堆內(nèi)存設(shè)置超過了容器 limit或者堆外內(nèi)存gRPC 直接緩沖區(qū)占用過高。Nacos 2.x 的 gRPC 通信比 1.x 的 HTTP 長輪詢更吃堆外內(nèi)存。解決把JVM_XMX降到容器 limit 的 60% 到 70%。比如 limit 是 4GiJVM_XMX設(shè) 2.5Gi 到 3Gi。同時監(jiān)控 Pod 的container_memory_working_set_bytes如果接近 limit要么調(diào)大 limit要么調(diào)小堆。另外JVM_XMN不要超過JVM_XMX的一半否則新生代過大導(dǎo)致老年代過小Full GC 頻繁。5.5 現(xiàn)象配置熱更新不生效客戶端一直拿到舊值原因Nacos 2.x 的配置推送依賴 gRPC 長連接如果客戶端和服務(wù)端之間的 9848 端口被 NetworkPolicy 阻斷或者客戶端版本和服務(wù)端版本不匹配推送通道建立不起來。解決確認(rèn)客戶端到 Nacos 的 9848 端口連通telnet nacos-headless.middleware.svc.cluster.local 9848能通。檢查客戶端 SDK 版本Nacos 2.3.x 服務(wù)端建議客戶端用 2.2.x 及以上。如果用的是 Spring Cloud Alibaba確認(rèn)spring.cloud.nacos.config.extension-configs的 refresh 屬性沒有設(shè)成 false。最后看服務(wù)端日志里有沒有push fail關(guān)鍵字有的話就是連接層的問題。6. 用 initContainer 做配置預(yù)檢與集群健康度自愈6.1 initContainer 在 Nacos 啟動前校驗 MySQL 連通性和表結(jié)構(gòu)Nacos 主容器啟動前可以加一個 initContainer 做前置檢查。這樣如果數(shù)據(jù)庫沒準(zhǔn)備好Pod 會卡在 Init 階段而不是反復(fù)重啟主容器日志也更干凈。initContainers: - name: check-mysql image: mysql:8.0 command: - bash - -c - | until mysql -h mysql.middleware.svc.cluster.local -u nacos -p$MYSQL_PASSWORD -e SELECT 1 FROM nacos_config.config_info LIMIT 1; do echo 等待 MySQL 和 nacos_config 表就緒... sleep 5 done env: - name: MYSQL_PASSWORD valueFrom: secretKeyRef: name: nacos-mysql-secret key: password這個 initContainer 會一直重試直到config_info表可查詢。SELECT 1 FROM ... LIMIT 1比SELECT 1更嚴(yán)格它要求表必須存在且有權(quán)限訪問。如果表還沒建說明數(shù)據(jù)庫初始化 Job 沒跑完或者失敗了這時候卡在 Init 階段比主容器 CrashLoop 更容易定位問題。6.2 用 livenessProbe 的 exec 探針檢測集群選主狀態(tài)默認(rèn)的 TCP 探針只能檢測端口是否監(jiān)聽不能判斷節(jié)點是否真的加入了集群??梢愿挠?exec 探針調(diào) Nacos 的集群健康接口檢查當(dāng)前節(jié)點是否在集群成員列表里。livenessProbe: exec: command: - bash - -c - | curl -s http://localhost:8848/nacos/v1/ns/operator/servers | grep -q $(hostname -i) initialDelaySeconds: 60 periodSeconds: 20 failureThreshold: 3這個探針的邏輯是獲取集群成員列表然后 grep 當(dāng)前 Pod 的 IP。如果當(dāng)前節(jié)點不在列表里說明它掉出了集群探針失敗kubelet 會重啟這個 Pod。重啟后 Pod 會重新加入集群比一直僵死在那里強。注意hostname -i在容器里返回的是 Pod IP和 Nacos 注冊的 IP 一致。如果網(wǎng)絡(luò)插件有特殊配置導(dǎo)致 IP 不一致可以把hostname -i換成環(huán)境變量POD_IP通過 downward API 注入。6.3 一個自愈腳本檢測到集群節(jié)點數(shù)不足時自動擴容Nacos 集群的節(jié)點數(shù)最好是奇數(shù)3 或 5。如果因為節(jié)點故障導(dǎo)致在線節(jié)點數(shù)少于多數(shù)派集群會進(jìn)入只讀狀態(tài)??梢詫懸粋€ CronJob 定期檢查集群節(jié)點數(shù)少于閾值時自動擴容 StatefulSet。#!/bin/bash # check-nacos-cluster.sh EXPECTED3 CURRENT$(kubectl exec -n middleware nacos-0 -- curl -s http://localhost:8848/nacos/v1/ns/operator/servers | grep -o ip | wc -l) if [ $CURRENT -lt $EXPECTED ]; then echo 集群節(jié)點數(shù)不足當(dāng)前 $CURRENT期望 $EXPECTED觸發(fā)擴容 kubectl scale statefulset nacos -n middleware --replicas$EXPECTED else echo 集群節(jié)點數(shù)正常$CURRENT fi這個腳本可以放進(jìn) CronJob 每五分鐘跑一次。但要注意擴容 StatefulSet 會創(chuàng)建新的 Pod新 Pod 需要時間加入集群。如果是因為網(wǎng)絡(luò)分區(qū)導(dǎo)致節(jié)點數(shù)不足盲目擴容可能加重問題。所以這個自愈策略更適合節(jié)點被誤刪或驅(qū)逐的場景網(wǎng)絡(luò)層面的故障還是要靠監(jiān)控告警人工介入。6.4 驗證自愈效果手動刪除一個 Pod 觀察集群恢復(fù)部署完自愈邏輯后可以手動刪一個 Pod 驗證效果。kubectl delete pod nacos-1 -n middlewareStatefulSet 控制器會立刻重建nacos-1新 Pod 啟動后通過NACOS_SERVERS環(huán)境變量重新加入集群。觀察kubectl get pods -n middleware -w新 Pod 應(yīng)該在 30 秒到 1 分鐘內(nèi)進(jìn)入 Ready。同時用之前的集群成員接口確認(rèn)三個節(jié)點都回來了。如果新 Pod 啟動后一直不加入集群檢查 PVC 是否被正確掛載以及nacos-1的域名解析是否正常。這套自愈機制的核心思路是把「集群健康」當(dāng)成一個可觀測、可干預(yù)的狀態(tài)而不是部署完就不管了。Nacos 集群在 k8s 上跑最大的挑戰(zhàn)不是初始部署而是長期運行中的節(jié)點故障、滾動更新和資源競爭。把 initContainer、exec 探針和自愈腳本組合起來能擋掉大部分常見的集群異常。我自己的習(xí)慣是每次調(diào)整 Nacos 的 YAML 之后先刪一個 Pod 看看恢復(fù)速度再觸發(fā)一次滾動更新看看業(yè)務(wù)側(cè)有沒有抖動。這兩個動作花不了十分鐘但能提前暴露大部分配置問題。希望幫到你。本文還有配套的精品資源點擊獲取