news 2026/10/28 3:43:44

Nacos集群K8s部署:StatefulSet与cluster.conf

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
Nacos集群K8s部署:StatefulSet与cluster.conf

简介:面向容器平台运维人员及刚接触 Nacos 集群部署的读者,这套按执行顺序整理的极简 YAML 配置清单,可用于降低 Nacos 在 K8s 中落地的门槛,减少复杂参数与配置组合带来的操作负担。压缩包共 6 个文件,以 5 个 YAML 清单和 1 个 txt 说明为主,整体约 3KB;清单覆盖数据库配置、无头服务、有状态副本、服务暴露及访问入口等关键环节,便于按顺序创建并逐项核对。已有 766 人学习,适合快速搭建实验环境或参考配置结构的场景。读者可从中获得可直接参考的部署脚本、配置拆分方式和基础排错入口,理解集群各组件在部署与运行中的组织关系;初学者也能据此快速梳理各清单之间的依赖,完成基础部署验证,并调整常见参数与访问方式,节省从零搜集资料和反复调试的成本。

1. 一次把副本数改成 3 的上线,先教会我看 cluster.conf

k8s nacos 集群部署脚本 yaml 这类东西,仓库里一搜一大把,能直接拿来跑通的却不多。某次给一个模拟项目做中间件交付,我把单机版 Nacos 的 yaml 里replicas从 1 改成 3 就推上测试环境,三个 Pod 齐刷刷 Running,控制台里却只有一个节点在线,注册上去的服务隔几分钟掉一次,日志里反复刷节点 DOWN 的记录。问题不在副本数,而在集群模式的三个前提:外部 MySQL、一致的 cluster.conf、稳定的 headless 域名,单机版 yaml 一个都没给。这份笔记按我实际交付的顺序走:先把版本和存储定死,再落 MySQL,再逐段拆 Nacos 的 StatefulSet,最后给出验证动作。适合正在把 Nacos 从单机迁到 K8s 集群、或者第一次写这套 yaml 的人照着抄。

2. 装前把环境钉死:K8s 1.25+、StorageClass 与 MySQL 8.0

装之前先花十分钟确认环境,比装完之后查日志便宜太多。Nacos 集群模式的失败,一半以上不是 Nacos 本身的问题,是集群节点之间域名解析不到、PVC 挂不上、MySQL 连不通。这一章把三项前置条件逐条钉死,每一条都给一条验证命令,跑通了再往下走。

2.1 版本对照:K8s 1.25+ 与 Nacos 2.3.2 的搭配

我把常用组合列在下面,镜像 tag 一律写死,不用 latest。Nacos 2.x 引入 gRPC 之后端口从 1 个变成 3 个,老版本的 yaml 直接拿来会漏端口,这是最常见的移植翻车点。

组件我固定用的版本说明
Kubernetes1.25 ~ 1.271.24 之后移除了 dockershim,容器运行时统一到 containerd,老的 kubelet 配置要重写
Nacos2.3.22.x 需额外暴露 9848/9849,镜像 tag 写死到补丁号
MySQL8.0.34初始化后不要再改lower_case_table_names
JDK镜像内置(8 或 11)不自己换基础镜像,避免 JVM 参数位置错

K8s 版本低于 1.20 的集群我不建议硬上。headless Service 的 Pod 域名格式是pod-name.service-name.namespace.svc.cluster.local,老集群里clusterDomain被改成非cluster.local的不少,写死域名的 cluster.conf 会全部解析失败。先确认一下:

# 查看集群版本与 DNS 域,后面拼 cluster.conf 要用到 kubectl version --short kubectl -n kube-system get cm coredns -o yaml | grep -A2 kubernetes

第二条命令输出里的kubernetes cluster.local in-addr.arpa就是集群域。如果你的集群域不是cluster.local,后面所有 FQDN 都要替换,这一步不做,Pod 全部 Running 也组不成集群。我一般会把这个域名记在 yaml 顶部的注释里,交付给别人时少一轮问答。

2.2 存储:StatefulSet 必须有一个能动态供给的 StorageClass

Nacos 的数据主要落在 MySQL,但/home/nacos/data和/home/nacos/logs两个目录我仍然建议挂 PVC。data 目录存的是协议相关的元数据,logs 目录是排障时的黑匣子,Pod 重建后日志丢了,等于把现场一起删了。

# 确认集群里有默认 StorageClass,且支持动态供给 kubectl get sc kubectl -n middleware get pvc

输出里带(default)的那一行就是默认存储类。没有默认 StorageClass 的话,volumeClaimTemplates里必须显式写storageClassName,否则 PVC 会一直 Pending,StatefulSet 的 Pod 卡在 ContainerCreating,kubectl describe pod里能看到waiting for a volume to be created。我用过 NFS 类型的动态供给,也用过块存储的 CSI,两者对 Nacos 没差别,因为真正的一致性数据在 MySQL,本地盘只放日志和临时文件,给 10Gi 够用很久。

提示:块存储类多数是 ReadWriteOnce,三个副本会被调度到不同节点,每个 Pod 各申请一块盘,互不干扰;如果误用 ReadWriteMany 的共享盘挂到三个 Pod 上,日志会互相覆盖,排查时看到的时间线是错乱的。

2.3 命名空间、Secret 与镜像拉取的前置动作

先建命名空间,再把数据库密码收进 Secret,yaml 里只引用 key,不写明文。这一步看着琐碎,但交付时直接把 yaml 丢进 Git 仓库,明文密码就是一颗定时炸弹。

# 1. 建独立命名空间,中间件不跟业务混部 kubectl create namespace middleware # 2. 数据库密码进 Secret,yaml 里只引用 key kubectl -n middleware create secret generic nacos-db \ --from-literal=password='ChangeMe_2024' # 3. 私有仓库要先建拉取凭证,公共镜像可跳过 kubectl -n middleware create secret docker-registry regcred \ --docker-server=registry.example.internal \ --docker-username=deployer \ --docker-password='***'

三条命令对应三件事:隔离、脱敏、拉镜像。--from-literal的 key 名要和后面 StatefulSet 里secretKeyRef.key对齐,写错了 Pod 会在启动阶段报CreateContainerConfigError,报错信息只告诉你 secret 找不到,不会告诉你是哪个 key 写错。私有仓库那条如果镜像来自公共源可以跳过,但imagePullSecrets字段建议先在 yaml 里注释保留,迁到内网环境时直接打开。

3. 先把 MySQL 8.0 立起来:Nacos 的元数据不能塞在 Pod 里

Nacos 集群模式强制要求外部数据库,内置 derby 只支持单机。这一章按「建库建表 → 起 StatefulSet → 调连接数」的顺序走,MySQL 先跑通,Nacos 才有地方写配置和实例列表。我习惯把 MySQL 也放同一个命名空间,用 headless Service 暴露,Nacos 通过固定域名连过去,Pod 重建不影响连接串。

3.1 建库建表:字符集和 lower_case_table_names 先定死

建表 SQL 不要从网上抄老版本,用你下载的 Nacos 发行包conf/mysql-schema.sql,版本之间的表结构有差异。库和账号按下面这段建:

-- 库名与字符集:utf8mb4 是必须的,配置内容里会有中文和特殊符号 CREATE DATABASE nacos DEFAULT CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci; -- 应用账号,不要用 root 连 Nacos CREATE USER 'nacos'@'%' IDENTIFIED BY 'ChangeMe_2024'; GRANT ALL PRIVILEGES ON nacos.* TO 'nacos'@'%'; FLUSH PRIVILEGES;

导入表结构用一条重定向,注意-i参数不能少,否则 stdin 传不进容器:

# 从宿主机把 SQL 灌进 mysql-0,执行完用 SHOW TABLES 确认 kubectl -n middleware exec -i mysql-0 -- \ mysql -uroot -p"${MYSQL_ROOT_PASSWORD}" nacos < mysql-schema.sql kubectl -n middleware exec -it mysql-0 -- \ mysql -uroot -p"${MYSQL_ROOT_PASSWORD}" -e "USE nacos; SHOW TABLES;"

第二条命令至少要看到config_info、config_info_beta、his_config_info、users、roles这几张表,少一张就说明 SQL 版本和 Nacos 版本对不上,后面写配置时会报Table doesn't exist。

注意:MySQL 8 初始化完成后lower_case_table_names就不能改了,改了会直接起不来。Linux 上默认是 0(区分大小写),保持默认即可,不要为了"兼容"手动调成 1。

3.2 MySQL 的 StatefulSet:参数写在 args 里,别写死在镜像里

MySQL 用 StatefulSet 起单副本就够,Nacos 的并发压力主要在配置读取,元数据写入量很小。核心是把字符集、连接数这些启动参数放进args,方便以后改。

apiVersion: apps/v1 kind: StatefulSet metadata: name: mysql namespace: middleware spec: serviceName: mysql-headless # 必须有 headless,Pod 域名才稳定 replicas: 1 selector: matchLabels: app: mysql template: metadata: labels: app: mysql spec: containers: - name: mysql image: mysql:8.0.34 args: - --character-set-server=utf8mb4 - --collation-server=utf8mb4_general_ci - --max_connections=1000 # Nacos 三副本各自带连接池,默认 151 不够 - --default-time-zone=+08:00 # 时区不设,配置的 gmt_modified 会差 8 小时 env: - name: MYSQL_ROOT_PASSWORD valueFrom: secretKeyRef: name: mysql-root key: password ports: - containerPort: 3306 readinessProbe: exec: command: ["mysqladmin", "ping", "-h", "127.0.0.1"] initialDelaySeconds: 20 periodSeconds: 10 volumeMounts: - name: data mountPath: /var/lib/mysql volumeClaimTemplates: - metadata: name: data spec: accessModes: ["ReadWriteOnce"] storageClassName: nfs-client resources: requests: storage: 20Gi

几个参数值得单独说。--max_connections=1000是按三副本估算的:每个 Nacos 节点的连接池上限通常在 20 到 50 之间,加上运维手工连进去排查的连接,151 很快被打满,表现是 Nacos 日志里报Too many connections,服务注册开始间歇性失败。--default-time-zone=+08:00不设的话,配置列表里的修改时间会比实际时间早八小时,排查"配置什么时候被改的"时会被带偏。

serviceName: mysql-headless必须对应一个已存在的 headless Service,否则 StatefulSet 创建时不会报错,但 Pod 的 DNS 记录缺失,Nacos 连不上。headless Service 的定义很简单:

apiVersion: v1 kind: Service metadata: name: mysql-headless namespace: middleware spec: clusterIP: None # None 就是 headless,Pod 直接用 <pod>.<svc> 访问 selector: app: mysql ports: - port: 3306 targetPort: 3306

clusterIP: None这一行是关键,写成普通 Service 也能连,但只能走 Service 的虚拟 IP 做负载均衡,单副本场景没区别。之所以还是坚持 headless,是为了让连接串写成mysql-0.mysql-headless.middleware.svc.cluster.local,跳过一次 iptables 转发,MySQL 这种长连接场景更稳。

3.3 账号权限与连接数:三个容易忽略的取值

第一是账号的 host 段。'nacos'@'%'里的%在 K8s 里指的是 Pod IP 段,Pod 重建后 IP 会变,所以不能用'nacos'@'10.244.1.5'这种固定 IP 授权。第二是GRANT的范围,只给nacos.*,不要图省事给*.*。第三是连接超时,MySQL 默认wait_timeout是 8 小时,Nacos 的 Druid 连接池有保活机制,一般不用改,但如果你的环境里放了网络策略会切断空闲连接,可以把wait_timeout调到 3600 并让 Nacos 的MYSQL_SERVICE_DB_PARAM带上connectTimeout=3000&socketTimeout=60000。

验证 MySQL 这一层是否真的可用,不要只看 Pod 是不是 Running,直接连一条:

# 用 Nacos 的业务账号连一次,能出结果才算通 kubectl -n middleware run mysql-check --rm -it --image=mysql:8.0.34 --restart=Never -- \ mysql -h mysql-0.mysql-headless.middleware.svc.cluster.local -unacos -p'ChangeMe_2024' \ -e "SELECT COUNT(*) FROM nacos.config_info;"

这条命令是临时 Pod,跑完自动删除。能返回一个数字,说明域名、账号、权限、库表四层都通了,可以进入 Nacos 的部署。返回Access denied是账号或密码问题,返回Unknown database是库名写错,卡住不动多半是网络策略挡了 3306。

4. 拆 Nacos 集群 YAML:StatefulSet、Headless Service 与 cluster.conf

这一章是整套脚本的核心。Nacos 在 K8s 上组集群,靠的是三个东西同时成立:三个副本互相知道对方地址(cluster.conf 或 NACOS_SERVERS)、共用同一个 MySQL、对外暴露的端口不漏 9848 和 9849。下面按调度、配置生成、Service 分层、探针四段拆。

4.1 三个副本怎么排:反亲和让它们分散到不同节点

三个 Pod 挤在同一台节点上,节点一挂集群直接失去多数派,控制台页面都打不开。用软反亲和按主机名打散,再用topologySpreadConstraints兜底,比硬反亲和对滚动更新友好。

apiVersion: apps/v1 kind: StatefulSet metadata: name: nacos namespace: middleware spec: serviceName: nacos-headless replicas: 3 podManagementPolicy: Parallel # 三个一起起,别一个个等,集群组队更快 selector: matchLabels: app: nacos template: metadata: labels: app: nacos spec: affinity: podAntiAffinity: preferredDuringSchedulingIgnoredDuringExecution: - weight: 100 podAffinityTerm: topologyKey: kubernetes.io/hostname labelSelector: matchLabels: app: nacos topologySpreadConstraints: - maxSkew: 1 topologyKey: kubernetes.io/hostname whenUnsatisfiable: ScheduleAnyway # 节点不够时仍然允许调度,别把 Pod 挂起 labelSelector: matchLabels: app: nacos containers: - name: nacos image: nacos/nacos-server:v2.3.2 env: - name: MODE value: cluster # 默认是 standalone,不写这行等于白部署 - name: PREFER_HOST_MODE value: hostname # 用域名而不是 IP 注册到集群 - 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 - name: MYSQL_SERVICE_HOST value: mysql-0.mysql-headless.middleware.svc.cluster.local - name: MYSQL_SERVICE_DB_NAME value: nacos - name: MYSQL_SERVICE_USER value: nacos - name: MYSQL_SERVICE_PASSWORD valueFrom: secretKeyRef: name: nacos-db key: password - name: MYSQL_SERVICE_DB_PARAM value: "characterEncoding=utf8&connectTimeout=3000&socketTimeout=60000&autoReconnect=true" - name: JVM_XMS value: 2g - name: JVM_XMX value: 2g - name: JVM_XMN value: 1g ports: - containerPort: 8848 name: client-http - containerPort: 9848 name: client-grpc # 客户端 gRPC,2.x 必开 - containerPort: 9849 name: server-grpc # 集群间同步,2.x 必开

MODE=cluster是整份 yaml 里最容易被漏的一行,镜像默认按单机模式启动,三个 Pod 各自维护自己的内存注册表,控制台看着有三个节点,实际注册的实例各存各的,客户端拿到的服务列表永远不全。PREFER_HOST_MODE=hostname配合NACOS_SERVERS里的域名,避免了 Pod 重建换 IP 后集群成员列表失效。端口这块,8848 是 HTTP 主端口,9848 是给客户端用的 gRPC(8848+1000),9849 是节点之间同步用的(8848+1001),少一个 9849,节点之间握手就失败,日志里能看到failed to connect to server。

4.2 cluster.conf 的两种生成方式:ConfigMap 挂载与 initContainer 拼装

Nacos 2.x 认NACOS_SERVERS环境变量,但有些场景还是要有cluster.conf文件,比如端口不是 8848,或者要跳过 DNS 直连 IP。两种方式我都用过,按团队习惯选。

第一种是 ConfigMap 挂载,节点固定、域名固定的交付环境最省事:

apiVersion: v1 kind: ConfigMap metadata: name: nacos-cluster-conf namespace: middleware data: cluster.conf: | 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

挂载时用subPath只覆盖这一个文件,避免把 conf 目录整个盖掉导致application.properties丢失:

volumeMounts: - name: cluster-conf mountPath: /home/nacos/conf/cluster.conf subPath: cluster.conf volumes: - name: cluster-conf configMap: name: nacos-cluster-conf

第二种是 initContainer 拼装,副本数经常变的环境用这个,改replicas之后不用手改 ConfigMap:

#!/bin/bash # 按 StatefulSet 的 Ordinal 序号拼出集群成员,写进 cluster.conf set -e OUT=/home/nacos/conf/cluster.conf : > "${OUT}" for i in $(seq 0 $((REPLICAS - 1))); do echo "nacos-${i}.nacos-headless.${POD_NAMESPACE}.svc.cluster.local:8848" >> "${OUT}" done cat "${OUT}" # 打到 init 日志里,出问题直接看上一容器

脚本里REPLICAS和POD_NAMESPACE通过env的valueFrom.fieldRef注入,fieldRef能取到metadata.namespace,副本数则从 Downward API 取不到,一般用 ConfigMap 存一个数字变量传进去。这段脚本的价值在于它把"集群成员列表"从手工维护变成了推导值,kubectl scale之后新 Pod 起来会自动带上正确成员,不用回头改配置。

4.3 Service 分三层:headless、client、console 各管一段

一套 Nacos 集群至少要三个 Service,混用一个会出现"控制台能开、客户端连不上"的玄学现象。

apiVersion: v1 kind: Service metadata: name: nacos-headless namespace: middleware spec: clusterIP: None # 给 StatefulSet 提供稳定的 Pod 域名 selector: app: nacos ports: - name: http port: 8848 - name: client-grpc port: 9848 - name: server-grpc port: 9849 --- apiVersion: v1 kind: Service metadata: name: nacos-client namespace: middleware spec: type: ClusterIP # 业务侧注册与发现走这个 selector: app: nacos ports: - name: http port: 8848 targetPort: 8848 - name: client-grpc port: 9848 targetPort: 9848 --- apiVersion: v1 kind: Service metadata: name: nacos-console namespace: middleware spec: type: NodePort # 只给人看控制台,不承载业务流量 selector: app: nacos ports: - name: http port: 8848 targetPort: 8848 nodePort: 30848

分层的逻辑是:nacos-headless只服务于 StatefulSet 的成员发现,不对外;nacos-client给业务应用用,必须同时开 8848 和 9848,2.x 的客户端先走 HTTP 拿地址,再走 gRPC 建长连接;nacos-console只映射 8848,方便运维浏览器访问,不暴露 gRPC 端口。有人为了省事把 8848 和 9848 都塞进一个 NodePort Service,结果客户端能连上但心跳一直超时,原因就是 gRPC 的连接被 NodePort 的转发规则打散了。

4.4 探针与 JVM:readiness 的 initialDelaySeconds 别照抄

Nacos 启动要先连数据库、加载配置、组建集群,冷启动 30 秒到 90 秒都正常。探针配得太激进,Pod 会在组集群的过程中被反复重启,永远起不来。

readinessProbe: tcpSocket: port: 8848 initialDelaySeconds: 30 # 首次检查前的等待时间 periodSeconds: 10 failureThreshold: 6 # 允许 60 秒内不 ready,别设 1 livenessProbe: tcpSocket: port: 8848 initialDelaySeconds: 90 # 存活探针必须比就绪探针更保守 periodSeconds: 20 failureThreshold: 3 resources: requests: memory: 2Gi cpu: 500m limits: memory: 4Gi cpu: "2"

initialDelaySeconds的取值来自 JVM 堆大小,JVM_XMX=2g时冷启动一般 40 秒左右,设 90 秒是留了数据库慢查询和镜像拉取的余量。livenessProbe用 TCP 而不是 HTTP 接口,是因为 8848 的 HTTP 在鉴权开启后会返回 403,用 HTTP 探针会把正常的 Pod 判死。资源限制里limits.memory给到JVM_XMX的两倍左右,堆外内存、元空间、gRPC 的 DirectBuffer 都要占地方,只给 2Gi 的话 Pod 会在流量上来后被 OOMKilled,日志里连异常都来不及打。

5. 避坑排查:Nacos 集群在 K8s 上起不来的五个现场

下面五条都是我在交付现场真实遇到过的,按「现象 → 原因 → 解决」记,看到类似日志可以直接对号入座。

5.1 启动期:Pod 全 Running,控制台只有一个节点

现象:三个 Pod 状态正常,kubectl logs没明显报错,打开控制台「集群管理」只列出当前节点,另外两个显示不出来,客户端注册的实例时有时无。

原因:MODE环境变量没设成cluster,镜像按单机模式启动。单机模式下 Nacos 用内置 derby 存数据,三个 Pod 各写各的,自然互相看不见。另一种情况是NACOS_SERVERS里的域名和实际 headless Service 名不一致,节点启动时连不上同伴,降级成单机。

解决:先确认环境变量,再确认域名。登录任一 Pod 里env | grep MODE,输出不是 cluster 就改 yaml 重新 apply。域名这块直接在 Pod 里nslookup nacos-1.nacos-headless.middleware.svc.cluster.local,解析不出来说明 headless Service 的 selector 没匹配上 Pod 标签。

5.2 启动期:日志刷 failed to connect to server,节点反复重启

现象:Pod 起来几十秒后重启,kubectl logs --previous里大量failed to connect to server 10.x.x.x:9849。

原因:9849 端口没在 Service 里暴露,或者 NetworkPolicy 只放行了 8848。集群间同步走 9849,这个端口不通,节点之间握手失败,Nacos 会认为集群不可用。

解决:检查 Service 的 ports 段有没有 9849,以及集群里是否有网络策略。临时验证可以在一个 Pod 里nc -zv nacos-1.nacos-headless 9849,通了再去看 Nacos 日志。

5.3 启动期:Pod 卡在 ContainerCreating,事件里报挂载失败

现象:kubectl get pod长时间 ContainerCreating,describe最后几行是FailedMount或waiting for a volume to be created。

原因:volumeClaimTemplates里写的storageClassName在集群里不存在,或者 StorageClass 的 provisioner 没跑起来。NFS 类型的动态供给还常见于 provisioner 的 ServiceAccount 权限不足。

解决:kubectl get sc确认存储类名字逐字符对齐,kubectl -n <provisioner 所在命名空间> logs看供给端日志。实在没有动态供给,就手工建三个 PV 做静态绑定,PVC 里把storageClassName置空。

5.4 运行期:服务注册正常,但配置中心拉取超时

现象:应用启动时读配置报Read timed out,注册中心那边一切正常,控制台能打开、能查实例。

原因:MySQL 的连接被wait_timeout掐断,Druid 拿到的是一条失效连接。也可能是config_info表数据量涨到几十万行后,没建索引的查询拖慢了整个连接池。

解决:连接串里加autoReconnect=true并把socketTimeout调到 60000,MySQL 侧把wait_timeout提到 3600。表数据量大的环境,检查config_info的tenant_id、data_id、group_id联合索引是否存在,缺索引时手工补一条。

5.5 运行期:Pod 周期性 OOMKilled,重启后短暂恢复

现象:kubectl describe pod里Last State显示OOMKilled,重启计数一直涨,业务侧表现为配置推送偶尔延迟。

原因:limits.memory贴着JVM_XMX设置,堆外内存没留余量。Nacos 2.x 的 gRPC 连接多了以后 DirectBuffer 占用明显,三副本各自维护长连接,内存曲线是缓慢上涨的。

解决:limits.memory至少给到JVM_XMX的 1.5 到 2 倍,JVM_XMN设成XMX的一半减少 GC 抖动。改完不要直接 apply,先kubectl rollout restart让三个 Pod 依次重建,观察一天的内存曲线再定稿。

6. 装完怎么验证:注册一个实例,再回头看三处日志

装完不等于跑通。我的验证顺序是「集群成员 → 实例注册 → 配置读写 → 故障自愈」,四步全过才算交付完成。

第一步看集群成员,直接打 OpenAPI:

# 从集群内部请求,返回的 servers 数组里应该有三个节点,state 均为 UP kubectl -n middleware exec -it nacos-0 -- \ curl -s "http://127.0.0.1:8848/nacos/v1/ns/operator/servers?agent=cluster"

返回 JSON 里servers长度是 3 且每个state为UP,说明集群组队成功。只有一个节点,回到 5.1 查MODE。

第二步注册一个临时实例再反查,验证写链路:

# 注册一个测试实例 curl -X POST "http://nacos-client.middleware.svc.cluster.local:8848/nacos/v1/ns/instance" \ -d "serviceName=demo-svc&ip=10.244.1.11&port=8080&ephemeral=true" # 反查服务列表,healthy 数量应为 1 curl -s "http://nacos-client.middleware.svc.cluster.local:8848/nacos/v1/ns/instance/list?serviceName=demo-svc"

如果开启了鉴权,两条命令都要带accessToken,先从/nacos/v1/auth/login拿。反查结果里hosts数组为空,多半是ephemeral=true的临时实例在 gRPC 通道没建起来时写入失败,回去查 9848 端口。

第三步验证配置读写,这是最容易被跳过的一步:

检查项命令或位置期望结果
配置写入控制台新建一条demo.properties列表出现该配置,修改时间正确
配置落库SELECT COUNT(*) FROM nacos.config_info;数量与页面一致
配置监听客户端 SDK 加监听器后改配置3 秒内收到回调

第四步做一次故障自愈演练,这条我每次都强制走:

# 删掉一个 Pod,观察它重建后能否自动回到集群 kubectl -n middleware delete pod nacos-2 kubectl -n middleware get pod -l app=nacos -w

新 Pod 起来后,再执行一次第一步的 OpenAPI,三个节点仍然是 UP,说明 headless 域名和NACOS_SERVERS的配置是对的。这一步失败的话,先看新 Pod 的cluster.conf是不是还残留着旧 IP,PREFER_HOST_MODE=hostname没设就会这样。

注意:验证完记得把demo-svc的测试实例反注册掉,临时实例虽然会随心跳超时自动清理,但留在生产环境的注册表里,后面排查真实服务时会干扰判断。

从那以后我每次交付这套 yaml,都会先删一个 Pod 看它能不能自己爬回集群,再去控制台点一遍配置发布,这两个动作花不到五分钟,却能挡掉后面 90% 的「装的时候好好的,用着用着不对了」。希望帮到你。

本文还有配套的精品资源,点击获取

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/28 3:43:17

特征排名在机器学习中的关键作用与实践方法

1. 项目概述&#xff1a;为什么特征排名是机器学习的关键步骤在机器学习的实际工程中&#xff0c;数据预处理环节往往占据整个项目70%以上的时间成本。而特征排名作为特征工程的核心技术之一&#xff0c;直接决定了模型性能的上限。我曾在金融风控项目中遇到一个典型案例&#…

作者头像 李华
网站建设 2026/10/28 3:42:26

微服务架构与智能调度在生鲜配送系统的实践

1. 系统架构升级&#xff1a;微服务化改造全面落地2026年2月5日的更新标志着万象生鲜配送系统完成了历时18个月的架构重构工程。我们彻底拆解了原有的单体架构&#xff0c;按照业务域划分为12个微服务模块。其中订单处理服务&#xff08;Order-Service&#xff09;和实时路由引…

作者头像 李华
网站建设 2026/10/28 3:42:26

马尾辫扎发全攻略:从高度到定型,解决细节翻车与防塌难题

1. 马尾辫为什么总在细节上翻车&#xff1a;先把审美问题聊透一条马尾辫&#xff0c;听起来是发型里最简单的一件事&#xff1a;把头发拢到一起&#xff0c;拿皮筋一绑&#xff0c;完事。但真到了拍照、出门、开会的时候&#xff0c;你会发现同一颗头&#xff0c;别人扎出来是利…

作者头像 李华
网站建设 2026/10/28 3:42:13

Cloudflare云操作系统:零服务器搭建个人服务架构

先说结论&#xff1a;cloudflare-os并不是 Cloudflare 官方的某个操作系统发行版&#xff0c;而是我折腾了两个月之后&#xff0c;把 Cloudflare 整个边缘网络当成一个“云操作系统”来用的完整方案。域名解析是它的文件系统&#xff0c; Workers 是它的进程调度器&#xff0c;…

作者头像 李华
网站建设 2026/10/28 3:42:09

纯前端SQL转ER图工具:解析、自动布局与可编辑实现

1. 为什么我要自己折腾一个SQL转ER图工具手里攥着一份几百行的建表SQL&#xff0c;产品经理跑过来问“这个模块的表之间到底怎么关联的”&#xff0c;你盯着屏幕上的FOREIGN KEY一行行找&#xff0c;找了十分钟还没理清楚——这种场景做后端的朋友应该都不陌生。市面上的在线建…

作者头像 李华
网站建设 2026/10/28 3:42:09

马尾扎法全攻略:从颅顶蓬松到后脑勺圆润的工程细节

马尾辫这个选题&#xff0c;乍一听实在不像个“项目”——它太日常了&#xff0c;日常到我们甚至都不觉得它是一种发型。但我这几年在造型这条路上折腾下来&#xff0c;反而越来越觉得&#xff0c;越简单的东西越藏学问。一根皮筋、三秒钟、随手一拢&#xff0c;这是马尾。知道…

作者头像 李华