首页 / 资讯中心 / 文章详情

K8s部署Nacos集群:StatefulSet与Headless避坑

K8s部署Nacos集群:StatefulSet与Headless避坑 ★ FEATURED ARTICLE
1. 先把架构想明白再抄官方 YAML官方文档给的那套 k8s 部署 nacos 集群的清单我第一次照着贴的时候三个 Pod 全起来了控制台也能进但服务注册死活不通。后来才发现问题根本不在 YAML 上而在于我没搞清楚 Nacos 2.x 的端口模型和集群成员是怎么互相发现的。所以这篇不打算从kubectl apply开始讲而是先把这个集群在 K8s 里到底长什么样说清楚你再回头看那几份清单会顺很多。先把定位讲明白Nacos 是注册中心和配置中心二合一的东西集群模式下它自己也是有状态的——每个节点持有相同的元数据视图通过一致性协议做数据同步底层数据落到外置数据库。在 k8s 上部署 nacos 集群本质上是把一个有状态、需要稳定网络标识、需要互相发现的进程塞进一个默认无状态、Pod 名字会变、IP 会漂的编排系统里。这两者的矛盾点就是你后面所有配置项的来源。适合谁看已经能跑通单机版 Nacos、手上有个可用 K8s 集群、准备往生产环境推的兄弟。如果你连 StatefulSet 和 Deployment 的区别都还没搞清楚建议先补这一课再回来不然下面讲的为什么用 Headless Service你会觉得是废话。1.1 官方文档方案的本质一个最小可运行闭环官方那套清单的思路非常朴素——用 StatefulSet 保证三个副本有稳定的nacos-0/1/2这样带序号的 Pod 名用 Headless Service 给每个 Pod 一个固定的 DNS 记录然后通过环境变量NACOS_SERVERS把这几个 DNS 名拼成一串告诉每个节点。节点启动时读这个变量生成内部的cluster.conf然后互相建连、选主、同步数据。这个设计的好处是足够简单不依赖任何外部组件。它没有用 Operator没有用自定义资源就是最原生的 K8s 对象组合。对运维来说这其实是好事——出问题的时候你能直接kubectl describe pod看到全部真相不用去猜某个 Operator 的控制器在背后做了什么。注意官方清单里的镜像是nacos/nacos-server:latest这类 tag千万别直接上生产。tag 漂移导致的昨天好好的今天挂了是最冤枉的故障版本号必须钉死到小版本。但它也有明显的边界这套清单默认你已经有外置 MySQL默认你的网络环境所有 Pod 之间可以自由互通默认你不需要考虑跨可用区、反亲和、资源配额。它解决的是能不能跑起来不是能不能长期跑。这也是我后面要单独拿一章讲生产化改造的原因——抄完官方文档只是起点中间还差着一层工程化的东西。1.2 三个绕不开的硬前提缺一个就起不来第一个前提是外置数据库。Nacos 集群模式下必须用外置 MySQL不能各节点用自己的内嵌 Derby。原因很直白集群模式下数据要共享三个 Pod 各写各的本地库配置根本对不上。官方镜像支持通过SPRING_DATASOURCE_PLATFORMmysql加一组MYSQL_SERVICE_*变量切过去但前提是这个库已经建好、表结构已经初始化。第二个前提是Headless Service 必须先于 StatefulSet 存在。这个坑我踩过有次脚本顺序写反了StatefulSet 先 applyPod 起来了但域名解析不出来节点之间互相找不到日志里一直刷连接超时。因为 StatefulSet 的serviceName字段只是声明我要用哪个 Headless Service它不会帮你去创建。你kubectl get svc看不到那个-headless的 ServicePod 的 DNS 就是空的。第三个前提是端口全开且可达。Nacos 1.x 时代只需要 88482.x 引入 gRPC 之后变成了三个口8848 走 HTTP控制台和 OpenAPI、9848 走客户端 gRPC2.x 的 SDK 长连接、9849 走服务端 gRPC集群节点之间同步数据。很多人部署完发现控制台能看到节点但客户端注册不上去九成是 9848 没通。另外如果你的环境里还混着 1.x 的客户端7848 这个 Raft 端口也得留着。1.3 副本数与存储的现实取舍官方示例给 3 副本这个数字不是随便定的。Nacos 集群的选主逻辑基于多数派3 个节点允许挂 1 个还能正常工作2 个节点反而比 1 个更脆弱——任何一台出问题整个集群就不可写。所以要么 1单机仅开发环境要么 3 起步不要搞 2 副本这种别扭配置。存储这块很多人有个误解觉得 Nacos 有数据就得挂大容量 PVC。实际上集群模式下配置数据和服务注册数据全在 MySQL 里Pod 本地只有日志和临时文件。官方清单里挂的是emptyDir到/home/nacos/logs我认为这个选择是对的——日志属于可丢弃数据真要排查问题就接到集中日志系统去没必要为日志上 PVC反而增加了调度约束和成本。资源方面我给个起步参考每副本 requests 给 1 核 2Gilimits 给 2 核 4Gi。Nacos 是 JVM 应用堆内存必须显式限制否则容器里它会按宿主机内存算默认值很容易被 OOMKill。这个我会在第三节的环境变量部分细说。2. 环境准备命名空间、数据库、镜像三件事动手之前先把这三件事做完能省掉后面 80% 的反复调试。我见过太多人一边 apply 一边改 YAML最后自己都不知道哪次改动起了作用。准备工作做扎实后面就是一个线性流程。2.1 命名空间与基础资源的落地我习惯给中间件单独开命名空间不要和应用挤在default里。理由有两个一是资源配额和网络策略好做隔离二是删除重建的时候不会误伤别的服务。命令很简单kubectl create namespace nacos kubectl config set-context --current --namespacenacos把当前 context 的默认命名空间切过去后面所有命令都不用带-n这是个小习惯但能少打很多字也避免漏写-n导致资源建错地方。数据库密码不建议明文写在 YAML 里尤其这些清单会进 Git 仓库。先建一个 Secretkubectl create secret generic nacos-db-secret \ --from-literalmysql-passwordYourStrongPassw0rd \ --from-literalauth-token$(head -c 32 /dev/urandom | base64) \ --from-literalauth-identity-keynacos-identity \ --from-literalauth-identity-valueA1b2C3d4E5f6G7h8auth-token是 Nacos 开启鉴权后用于 JWT 签名的密钥官方要求 Base64 编码后至少 32 字节直接用head -c 32 /dev/urandom | base64生成就够。auth-identity-key/value是服务端之间的身份标识对集群内所有节点必须完全一致否则节点之间通信会被拒绝——这个是很多人开鉴权之后集群起不来的直接原因。2.2 外置 MySQL 的建库建表数据库这块我给的建议是不要手写建表语句直接用镜像自带的脚本。Nacos 的镜像里/home/nacos/conf目录下就带着 MySQL 建表脚本不同小版本文件名可能叫mysql-schema.sql或nacos-mysql.sql进去ls一眼就知道。docker run --rm nacos/nacos-server:v2.2.3 ls /home/nacos/conf | grep -i sql docker run --rm nacos/nacos-server:v2.2.3 cat /home/nacos/conf/mysql-schema.sql nacos-schema.sql然后建库、导表CREATE DATABASE nacos_config DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; CREATE USER nacos% IDENTIFIED BY YourStrongPassw0rd; GRANT ALL PRIVILEGES ON nacos_config.* TO nacos%; FLUSH PRIVILEGES;mysql -h your-mysql-host -u nacos -p nacos_config nacos-schema.sql有几个细节值得单独拎出来说。字符集必须是utf8mb4用utf8存配置里的特殊字符比如某些 emoji 或者四字节汉字会直接报错截断。MySQL 8.0 的话连接参数里必须带allowPublicKeyRetrievaltrue和useSSLfalse否则驱动会卡在认证阶段表现是 Pod 一直重启但日志里只有一行含糊的Communications link failure。还有一个容易忽略的点这个库是三个 Nacos 节点共用的所以连接数要给够。三个节点各配一个连接池默认池子就不小MySQL 的max_connections如果只有 100跑一段时间就会看到Too many connections。我的经验值是给 Nacos 专用实例留 300 以上或者干脆给它一个独立的小实例不跟业务库混。2.3 镜像固定与配置目录约定镜像 tag 一定要钉到具体版本我一般用v2.2.3这种带小版本号的。不要用latest也不要用2.2这种只到次版本的——次版本内的补丁升级偶尔会带行为变化生产环境要的是确定性。Nacos 镜像内部的目录约定也值得先熟悉一下后面挂配置文件会用到路径用途是否需要挂载/home/nacos/conf主配置目录含application.properties通常用 ConfigMap 覆盖单个文件/home/nacos/logs运行日志建议挂 emptyDir 或直接不挂/home/nacos/data本地数据目录集群模式无需持久化/home/nacos/target应用包不要动这里有个实操心得不要整个conf目录用 ConfigMap 覆盖。ConfigMap 挂载会把这个目录变成只读镜像里其他必需的配置文件比如logback.xml如果没在你的 ConfigMap 里就会全部消失启动直接失败。正确做法是只挂单个文件用subPath。这个坑我印象很深第一次搞的时候整目录挂上去Pod 起来就报找不到 logback 配置查了半天以为是镜像问题。3. 逐份拆解清单文件每个字段为什么在这儿这一节是全文的核心。官方清单不长但每一行都值得问一句为什么。我把关键的几份拆开讲你照着改的时候心里有底。3.1 两个 ServiceHeadless 和普通的分工先看 Headless ServiceapiVersion: v1 kind: Service metadata: name: nacos-headless spec: clusterIP: None selector: app: nacos ports: - name: http port: 8848 targetPort: 8848 - name: client-rpc port: 9848 targetPort: 9848 - name: raft-rpc port: 9849 targetPort: 9849clusterIP: None就是 Headless 的标志它不做负载均衡不为 Service 分配虚拟 IP而是把 DNS 查询直接解析到后端每个 Pod 的 IP 上。配合 StatefulSet每个 Pod 会拿到nacos-0.nacos-headless.nacos.svc.cluster.local这样的稳定域名。这就是集群成员互相发现的基石——Pod IP 会变但这个名字永远指向第 0 号节点。端口命名也有讲究。K8s 要求多端口 Service 的每个端口必须有名字这个name后面在 Ingress 或者某些网络插件里会被引用最好按协议语义起名别都叫port-1、port-2。普通 Service 则是给外部访问用的apiVersion: v1 kind: Service metadata: name: nacos-client spec: type: ClusterIP selector: app: nacos ports: - name: http port: 8848 targetPort: 8848 - name: client-rpc port: 9848 targetPort: 9848它带负载均衡集群内其他应用通过nacos-client.nacos.svc.cluster.local:8848访问控制台和 OpenAPI通过 9848 建立 gRPC 长连接。注意这里没有9849——那是节点之间的内部通信用不需要暴露给业务方。注意如果你的业务应用和 Nacos 在同一个 K8s 集群里客户端配置的 serverAddr 应该写这个普通 Service 的名字而不是三个 Pod 的域名。写 Pod 域名的话一旦某个节点挂了客户端会一直往死节点上重连。3.2 StatefulSet 的关键字段逐条过StatefulSet 是这套部署的重头戏我按重要性排一下apiVersion: apps/v1 kind: StatefulSet metadata: name: nacos spec: serviceName: nacos-headless replicas: 3 podManagementPolicy: Parallel selector: matchLabels: app: nacos template: metadata: labels: app: nacos spec: terminationGracePeriodSeconds: 30 containers: - name: nacos image: nacos/nacos-server:v2.2.3 imagePullPolicy: IfNotPresent ports: - containerPort: 8848 - containerPort: 9848 - containerPort: 9849 env: - name: MODE value: cluster - name: NACOS_SERVERS value: nacos-0.nacos-headless.nacos.svc.cluster.local:8848 nacos-1.nacos-headless.nacos.svc.cluster.local:8848 nacos-2.nacos-headless.nacos.svc.cluster.local:8848 - name: SPRING_DATASOURCE_PLATFORM value: mysql - name: MYSQL_SERVICE_HOST value: mysql.database.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 valueFrom: secretKeyRef: name: nacos-db-secret key: mysql-password - name: MYSQL_SERVICE_DB_PARAM value: characterEncodingutf8connectTimeout3000socketTimeout5000autoReconnecttrueuseSSLfalseallowPublicKeyRetrievaltrueserverTimezoneAsia/Shanghai - name: NACOS_AUTH_ENABLE value: true - name: NACOS_AUTH_TOKEN valueFrom: secretKeyRef: name: nacos-db-secret key: auth-token - name: JVM_XMS value: 2g - name: JVM_XMX value: 2g - name: JVM_XMN value: 1gserviceName必须指向那个 Headless Service这是给 Pod 分配稳定 DNS的开关。podManagementPolicy: Parallel是我强烈建议加的——默认是OrderedReady会严格按 0、1、2 的顺序一个个起每个都要等前一个 Ready 才起下一个。Nacos 三个节点本来就是要互相发现才能 Ready 的串行启动会导致第 0 个节点一直等不到另外两个卡在那里很久。改成Parallel让三个同时起它们自己会重试建连速度快很多。terminationGracePeriodSeconds: 30是给优雅下线留时间。Nacos 节点退出前要把自己从集群里摘掉、把注册的服务实例做下线处理太快被 kill 会导致客户端短时间拿到失效实例。MYSQL_SERVICE_DB_PARAM这个变量经常被忽略但它很关键。里面的useSSLfalse和allowPublicKeyRetrievaltrue是针对 MySQL 8.0 的serverTimezone必须显式指定不指定的话时区错乱会导致配置的修改时间显示成 8 小时前排查问题的时候很误导。3.3 JVM 与探针最容易出事的两块JVM 参数我建议显式给死。Java 在容器里默认按宿主机的 CPU 和内存来算堆大小你的 Pod limit 是 4Gi但宿主机是 64Gi它可能就按 16Gi 的堆去申请然后直接被 OOMKill。规则很简单JVM_XMX设成容器内存 limit 的 50%~60%JVM_XMS和JVM_XMX给一样大避免运行期扩堆JVM_XMN给堆的 1/2 到 1/3。探针这块Nacos 2.x 提供了专门的健康检查端点startupProbe: tcpSocket: port: 8848 initialDelaySeconds: 30 periodSeconds: 10 failureThreshold: 30 readinessProbe: httpGet: path: /nacos/v1/console/health/readiness port: 8848 initialDelaySeconds: 10 periodSeconds: 10 timeoutSeconds: 5 failureThreshold: 3 livenessProbe: httpGet: path: /nacos/v1/console/health/liveness port: 8848 initialDelaySeconds: 60 periodSeconds: 20 timeoutSeconds: 5 failureThreshold: 3startupProbe用 tcpSocket 探测 8848 端口通不通failureThreshold给到 30 意思是最多容忍 5 分钟启动时间。这不是保守Nacos 冷启动确实慢尤其开了鉴权、连数据库首次建连接池的时候两分钟以上很常见。livenessProbe的initialDelaySeconds一定要比startupProbe的总时长留出余量否则会出现启动探针还在跑存活探针已经把容器杀了的反复重启循环。我见过有人两个探针都写 10 秒延迟结果 Pod 一直在 CrashLoopBackOff日志里啥也没有——因为根本没到打印日志的阶段就被杀了。4. 完整实操从 apply 到集群自检准备工作齐了现在走一遍完整流程。我把顺序列出来这个顺序不能乱。4.1 按依赖顺序创建资源# 1. 数据库 Secret前面已建确认一下 kubectl get secret nacos-db-secret # 2. Headless Service 必须先建 kubectl apply -f nacos-headless-svc.yaml kubectl get svc nacos-headless # 3. 普通 Service kubectl apply -f nacos-client-svc.yaml # 4. 如果自定义了 application.properties先建 ConfigMap kubectl create configmap nacos-custom-config \ --from-fileapplication.properties./application.properties # 5. 最后才是 StatefulSet kubectl apply -f nacos-statefulset.yaml # 6. 观察启动过程 kubectl get pods -l appnacos -w第 6 步的-w会实时刷新你会看到三个 Pod 几乎同时进入ContainerCreating然后陆续变成Running但READY列可能还是0/1。别急这时候去 tail 日志看启动进度kubectl logs -f nacos-0正常的启动日志大概长这样先打印数据库连接初始化然后是Nacos started successfully in cluster mode最后出现nacos is starting with cluster。如果卡在Waiting for datasource或者一直刷ConnectException直接跳到第五节的问题排查。4.2 三个副本 Ready 之后的验证动作Pod 全部1/1 Running只说明容器活着不代表集群真的组建成功了。我一般做三层验证第一层看成员列表。从任意一个 Pod 里查kubectl exec -it nacos-0 -- curl -s \ http://127.0.0.1:8848/nacos/v1/ns/operator/servers?accessToken${TOKEN}返回的 JSON 里servers数组应该有三个元素每个元素的state是UPaddress是各自的 Pod IP。如果只有一个或者有节点state是DOWN说明集群没完全组建。第二层看数据库有没有写入。去 MySQL 里查SELECT COUNT(*) FROM config_info; SELECT * FROM config_info LIMIT 1;随便在控制台新建一个配置然后确认这条记录落到了数据库里。这一步能验证数据确实是共享的而不是各写各的本地缓存。第三层做一次故障演练。手动删掉一个 Podkubectl delete pod nacos-1观察另外两个节点的日志应该能看到成员变更的记录然后nacos-1被重建、重新加入集群。整个过程业务侧的配置读取不应该报错。这个演练很重要很多人只在三个都活着的状态下测过真出故障的时候才知道集群到底有没有容错能力。4.3 控制台暴露与客户端接入控制台访问有两种常见做法。集群内部使用的话kubectl port-forward最省事kubectl port-forward svc/nacos-client 8848:8848然后浏览器开http://127.0.0.1:8848/nacos默认账号密码是nacos/nacos——这个必须第一时间改开了鉴权还用默认密码等于没开。需要给外部访问的话可以用 NodePort 或 Ingress。但这里有个大坑必须提醒Ingress 只能代理 HTTP 的 8848代理不了 gRPC 的 9848。原因是 Nacos 2.x 客户端连上 8848 之后服务端会返回一个 gRPC 地址让客户端去连 9848如果你的入口只转了 HTTP客户端拿到地址之后连不上表现为配置能读、服务注册失败。正确做法是要么用 LoadBalancer 类型的 Service 同时暴露 8848 和 9848要么在 Ingress 层用支持 TCP/gRPC 转发的方案单独配一条 9848 的规则。我一般倾向后者但配置复杂度高一些。如果是内网环境、应用和 Nacos 都在同一个 K8s 集群那就别折腾外部入口了直接用 ClusterIP 的内部域名最省心也最安全。客户端接入验证写个最小的测试Properties props new Properties(); props.put(serverAddr, nacos-client.nacos.svc.cluster.local:8848); props.put(namespace, public); props.put(username, your-user); props.put(password, your-pass); NamingService naming NacosFactory.createNamingService(props); naming.registerInstance(demo-service, 10.0.0.1, 8080); System.out.println(naming.getAllInstances(demo-service));能打印出实例列表说明注册中心链路完全通了。如果这里超时九成是 9848 的问题去看客户端日志里有没有Client not connected或者server is DOWN。5. 踩坑记录那些官方文档不会写的问题这部分是我认为整篇文章最有价值的地方。官方的排查章节写得比较概括但实际现场遇到的坑往往更具体。5.1 节点互相发现失败的三类原因域名拼错或命名空间没对上。NACOS_SERVERS里写的是完整 FQDN如果你的 Nacos 不在nacos命名空间那nacos-headless.nacos.svc.cluster.local就是错的。要么改成实际命名空间要么用短域名nacos-headless——短域名在同命名空间内可以解析跨命名空间就不行了。我建议还是写全省得后面挪位置的时候又出问题。Headless Service 的 selector 和 Pod 标签不匹配。这个特别隐蔽因为 Service 建成功了kubectl get svc也正常只是kubectl get endpoints nacos-headless是空的。Pod 的 label 里app: nacos必须和 Service 的 selector 完全一致差一个字母都不行。DNS 解析被网络策略拦了。有些集群默认开了 NetworkPolicyPod 之间默认不通。测试方法很简单进 Pod 里nslookup nacos-headless或者ping nacos-0.nacos-headless解析不出来就是 DNS 问题能解析但 ping 不通就是网络策略问题。5.2 数据库相关的三类报错与定位数据库问题占了 Nacos 启动失败的绝大多数我把常见的三类整理成表报错关键词根本原因处理方式Communications link failure网络不通或端口错进 Pod 用nc -zv mysql-host 3306验证连通性Public Key Retrieval is not allowedMySQL 8.0 认证方式连接参数加allowPublicKeyRetrievaltrueuseSSLfalseTable nacos_config.config_info doesnt exist建表脚本没执行或执行到了别的库重新确认MYSQL_SERVICE_DB_NAME和脚本导入的库一致Access denied for user账号权限或密码错检查 Secret 里的密码注意 YAML 里的特殊字符要转义Too many connections连接池总和超 MySQL 上限调大max_connections或减小各节点池大小这里我要单独说Table doesnt exist这个。它出现的原因往往不是你没建表而是建表脚本导入到了错误的库。很多人mysql -u root schema.sql的时候没带库名默认进了mysql系统库然后 Nacos 怎么都找不到表。导入的时候一定带上nacos_config这个库名或者先USE nacos_config;。注意建表脚本里的库名和你的实际库名必须一致。有些版本的脚本开头带CREATE DATABASE nacos_config;和USE nacos_config;如果你建的库叫别的名字这两行会把它导到nacos_config里去然后你的连接配置指向另一个空库照样找不到表。5.3 探针、内存与启动慢的连锁反应前面提过探针配置这里讲实际表现。一个典型的故障链是这样的livenessProbe设得太激进Nacos 冷启动超过 60 秒探针失败三次容器被杀K8s 重启它又超时又杀最后CrashLoopBackOffkubectl logs只能看到上一次启动的日志看起来像是启动到一半就没了。排查这种问题的方法先kubectl describe pod看 Events会明确写Liveness probe failed和Killing container。区分清楚是应用真的挂了还是探针太严这两者的处理方式完全不同。内存问题也一样。如果 Pod 频繁被 OOMKilldescribe里看Reason: OOMKilled两个方向查一是JVM_XMX是不是没设或者设得比 limit 还大二是 Nacos 在集群刚建立的时候会有一次全量数据同步内存瞬时冲高limits 给得太紧就会被打死。我的做法是JVM_XMX设为 limit 的一半剩下的一半留给堆外内存、元空间和线程栈这样一般不会再 OOM。5.4 常见问题速查表把上面这些和另外几个高频问题汇总成一张表出问题的时候直接对照现象优先排查点快速验证命令Pod 一直 Pending资源不足或 PVC 未绑定kubectl describe pod nacos-0看 EventsPod Running 但 Ready 0/1readiness 探针失败kubectl exec进容器curl健康端点控制台能进服务注册失败9848 端口不通客户端日志搜Client not connected集群成员只有 1 个NACOS_SERVERS或 DNSkubectl exec里ping其他节点域名配置修改后其他节点不生效数据库连接各连各的查 MySQL 里config_info的md5字段启动日志刷No such fileconf 目录被整目录挂载检查 volumeMounts 是否用了 subPath鉴权开启后节点互相拒绝token 或 identity 不一致对比三个 Pod 的 env最后那条节点互相拒绝值得多说一句。NACOS_AUTH_TOKEN是三个节点共用的签名密钥NACOS_AUTH_IDENTITY_KEY/VALUE是节点身份标识这三者只要有一个不一致节点之间的内部请求就会被 403。用 Secret 统一注入是最稳的做法千万别在 YAML 里手动写三份。6. 生产化改造把 demo 变成能长期跑的东西官方清单跑通之后还有一些工程化的东西要补。这一节讲的是我实际推生产时加的东西不是必须但每一条都对应过真实故障。6.1 反亲和与节点分布默认情况下三个 Pod 可能全被调度到同一台节点上。这台机器一挂整个集群就没了三副本白搭。加个反亲和affinity: podAntiAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 100 podAffinityTerm: labelSelector: matchLabels: app: nacos topologyKey: kubernetes.io/hostname用preferred而不是required是有意的。required在三节点集群里如果只有两台物理机可用第三个 Pod 会一直 Pending。preferred是软约束尽量分散实在分散不了也能起来。当然如果你的节点数足够用required更能保证可用性。更现代的做法是用topologySpreadConstraintstopologySpreadConstraints: - maxSkew: 1 topologyKey: topology.kubernetes.io/zone whenUnsatisfiable: ScheduleAnyway labelSelector: matchLabels: app: nacos这个能跨可用区打散比单纯的节点反亲和更进一步。跨 AZ 部署的代价是节点之间的网络延迟会高一些Nacos 的同步频率不算高一般能接受。6.2 扩缩容与滚动升级的注意点扩容到 5 个节点直接改replicas: 5然后把NACOS_SERVERS更新成五个域名apply之后会滚动重启。注意这里的顺序——先改NACOS_SERVERS再改 replicas或者一起改。如果你只改 replicas 不改变量新起来的两个节点不知道自己该连谁老节点也不知道有新成员集群就分裂了。缩容反过来要小心。从 5 缩到 3直接改 replicas 会把最后两个 Pod 删掉但它们还在NACOS_SERVERS列表里剩下的节点会一直尝试连接已经消失的地址日志刷错误。正确顺序是先把NACOS_SERVERS改成 3 个、滚动重启然后再缩 replicas。虽然最终状态一样但中间过程干净。滚动升级用RollingUpdate策略配maxUnavailable: 1保证升级过程中至少有 2 个节点在线集群不会失去多数派。升级镜像之前务必确认目标版本和当前版本的数据库表结构兼容——跨大版本升级比如 1.x 到 2.x需要额外的数据迁移步骤不能直接换镜像了事。6.3 备份、监控与日志备份这块由于数据都在 MySQLNacos 本身几乎不需要备份什么。要备的是数据库用常规的 MySQL 备份方案就行。唯一要注意的是备份时的一致性——mysqldump加--single-transaction避免备份期间有配置写入导致数据不一致。监控我建议盯这几个指标指标含义告警阈值建议JVM 堆使用率内存压力持续 80%集群节点数成员健康 3 立即告警配置长连接数客户端连接规模接近服务端上限数据库连接池活跃数池是否打满持续 90%请求 P99 延迟服务质量按业务容忍度定Nacos 本身有 Prometheus 格式的指标端点Pod 上加个 annotation 让采集器自动发现就行。日志方面容器 stdout 只是启动阶段的一部分业务日志在/home/nacos/logs下按天切分。如果你不挂 PVC 也不接日志收集这些日志重启就没了。我的做法是挂emptyDir加一个轻量的日志采集 sidecar或者用节点级的日志代理统一采集具体看你们现有的日志体系。最后分享一个我自己的教训。我们第一次上生产的时候三个节点跑得好好的过了两周突然有一天服务注册大面积超时。排查了半天发现是 MySQL 的连接数被打满了——那段时间业务扩了一批应用每个应用连 Nacos 的长连接数涨上来Nacos 自己到数据库的连接池也跟着涨最后把数据库的连接上限吃满。加了一条连接数监控告警之后这类问题就能提前发现了。所以别觉得跑起来了就完事能跑和能扛是两码事监控和容量规划要跟着一起做。
阅读完成 · 觉得有帮助?
咨询建站