Nacos 平滑升级不是把 StatefulSet 镜像标签改成新版本,然后等待三个 Pod 自动重启。真正需要保护的是三件事:数据库 schema、服务注册连续性、配置读取连续性。
系列导航:Kubernetes 重建迁移教程系列。升级前应先完成 Nacos 集群基线和客户端版本盘点。
本文假设当前是三节点 StatefulSet、使用外部 MySQL、应用通过普通 Service 连接,节点间通过 Headless Service 通信。
升级前先回答四个问题
在工单或变更记录中写清楚:
- 当前 Server 版本和目标 Server 版本是什么?
- 所有应用的 Nacos Client 主版本是什么?
- 目标版本是否修改数据库表结构、端口、环境变量和探针路径?
- 回滚旧镜像时,新 schema 是否仍与旧版本兼容?
官方升级手册当前说明:从 2.0.x 及以上升级到 3.2.x 需要对比目标版本数据库 schema;3.2.x Server 兼容 2.x 和 3.x Client,而 1.x Client 不再兼容。这个结论会随版本变化,执行前必须重新查阅官方升级手册。
第 1 步:导出版本和客户端清单
保存当前镜像与 Pod:
kubectl -n nacos-system get statefulset nacos \
-o jsonpath='{.spec.template.spec.containers[0].image}{"\n"}' \
| tee reports/nacos-current-image.txt
kubectl -n nacos-system get pods -o wide \
| tee reports/nacos-pods-before.txt
客户端版本不能靠猜。可以从 Maven 依赖树、Gradle dependencies、构建产物清单或镜像 SBOM 中收集:
mvn dependency:tree -Dincludes=com.alibaba.nacos:nacos-client
把结果整理成 CSV:
namespace,workload,client_version,owner,verified
app-test,order-api,<client-version>,team-a,false
只要还有官方不支持的 Client 主版本,升级就应暂停。
第 2 步:备份配置、数据库和 Kubernetes 资源
备份 StatefulSet、Service、ConfigMap 和 Secret 的资源定义:
kubectl -n nacos-system get statefulset,service,configmap -o yaml \
> backup/nacos-kubernetes.yaml
umask 077
kubectl -n nacos-system get secret nacos-secret -o yaml \
> backup/nacos-secret.yaml
数据库应使用一致性备份工具进行备份。以 MySQL 逻辑备份为例:
mysqldump --single-transaction --routines --triggers \
-h <mysql-host> -u <backup-user> -p \
<nacos-database> > backup/nacos-before-upgrade.sql
sha256sum backup/nacos-before-upgrade.sql > backup/nacos-before-upgrade.sha256
配置数据还应通过 Nacos 的导出功能生成独立归档。数据库备份和配置导出必须在隔离环境中至少恢复一次。
第 3 步:比较数据库 schema
从当前版本和目标版本发行包中分别取出 mysql-schema.sql:
diff -u current/mysql-schema.sql target/mysql-schema.sql \
| tee reports/nacos-schema.diff
不要直接执行目标版本的完整建表脚本。提取增量 DDL,先在数据库副本演练:
恢复生产备份到临时库
→ 执行增量 DDL
→ 启动一个目标版本 Nacos
→ 验证配置读取和服务注册
→ 记录耗时与锁表影响
如果变更不可逆,回滚方案不能只写“改回旧镜像”,还必须包含数据库恢复或向后兼容证明。
第 4 步:比较配置、端口和探针
导出当前 StatefulSet:
kubectl -n nacos-system get statefulset nacos -o yaml \
> reports/nacos-statefulset-before.yaml
逐项对照目标镜像文档:
- 环境变量名称是否变化。
- 8848、9848、9849、7848、8080 等端口用途是否变化。
- HTTP API 与控制台路径是否变化。
- 健康检查路径是否仍然有效。
- JDK 和资源要求是否变化。
从 Nacos 3.0 起,控制台与主端口分离,代理层不能沿用针对旧版本的假设。gRPC 端口经过代理时要使用 TCP 转发,不能按普通 HTTP 处理。参考部署手册概览。
第 5 步:在影子环境完成升级演练
从生产备份恢复一个隔离数据库,创建单独命名空间:
kubectl create namespace nacos-upgrade-lab
把 Service 名称、数据库地址和 Secret 全部改为测试值,启动与生产相同的旧版本。先证明旧版本能读取备份数据,再升级到目标版本。
至少验证:
- 登录与权限。
- 命名空间、Data ID、Group 数量。
- 配置发布、回读和历史版本。
- 临时应用的注册、发现和注销。
- 重启任意一个 Nacos Pod 后集群恢复。
影子环境失败时,不要去生产“再试一次”。
第 6 步:设置逐节点滚动策略
StatefulSet 默认从最大序号开始滚动更新。为了先升级一个节点进行观察,可以临时设置 partition:
kubectl -n nacos-system patch statefulset nacos --type merge -p '
{
"spec": {
"updateStrategy": {
"type": "RollingUpdate",
"rollingUpdate": {"partition": 2}
}
}
}'
然后只更新 Pod 模板中的镜像:
kubectl -n nacos-system set image statefulset/nacos \
nacos=<image-registry>/nacos-server:<target-version>@sha256:<target-digest>
此时只应更新 nacos-2:
kubectl -n nacos-system get pods -w
第 7 步:观察第一个新版本节点
不要看到 Ready 就立刻继续。至少观察一个完整业务高峰窗口,检查:
kubectl -n nacos-system logs nacos-2 --since=30m \
| grep -Ei 'error|exception|raft|grpc|database'
kubectl -n nacos-system get endpointslice \
-l kubernetes.io/service-name=nacos-client -o wide
同时运行连续探测:
while true; do
date
curl -fsS 'http://<internal-nacos-address>/nacos/v1/console/health/readiness'
sleep 5
done
应用侧检查配置监听、注册续约、调用错误率和登录链路。若出现实例列表突然为空、gRPC 连接失败或配置监听中断,立即停止。
第 8 步:逐步放开剩余节点
第一个节点稳定后,把 partition 改为 1:
kubectl -n nacos-system patch statefulset nacos --type merge -p '
{"spec":{"updateStrategy":{"rollingUpdate":{"partition":1}}}}'
等待 nacos-1 Ready,重复完整验证。最后把 partition 改为 0:
kubectl -n nacos-system patch statefulset nacos --type merge -p '
{"spec":{"updateStrategy":{"rollingUpdate":{"partition":0}}}}'
kubectl -n nacos-system rollout status statefulset/nacos --timeout=20m
三个节点之间至少留出明确的观察时间,不要在一个命令中同时删除三个 Pod。
第 9 步:做一次真实故障演练
选择一个非 Leader 或已确认可安全重建的 Pod:
kubectl -n nacos-system delete pod nacos-2
kubectl -n nacos-system wait --for=condition=Ready pod/nacos-2 --timeout=10m
删除期间持续发起配置读取和服务调用。目标不是零日志,而是客户端能够重连,业务请求不出现持续失败。
回滚方法
如果新旧版本允许混部、数据库变更向后兼容,可保持 partition,在故障节点先恢复旧镜像:
kubectl -n nacos-system set image statefulset/nacos \
nacos=<image-registry>/nacos-server:<old-version>@sha256:<old-digest>
如果数据库 schema 不向后兼容:
- 停止所有 Nacos 写入和配置发布。
- 将 Nacos StatefulSet 缩容为零。
- 恢复升级前的数据库。
- 恢复旧版 Kubernetes 清单和 Secret。
- 启动旧版本,验证配置与实例。
这个流程会产生中断,因此不可逆 DDL 必须在维护窗口执行。
完成定义
- 三个 Pod 均运行目标镜像 digest。
- 数据库 schema 与目标版本一致,并保存执行记录。
- 配置、服务实例、用户和权限数量与升级前基线一致。
- 所有关键客户端版本在兼容矩阵内。
- 删除一个 Pod 时配置读取和服务调用仍可继续。
- 观察期内没有持续的注册失败、gRPC 断连或数据库异常。
- 备份、旧镜像和回滚清单在观察期结束前不得删除。
DISCUSSION
讨论与反馈