Kubernetes环境下Nacos生产级部署与调优实践

发布时间:2026/11/4 17:15:50
Kubernetes环境下Nacos生产级部署与调优实践

1. 为什么需要专门的Nacos生产部署方案

在Kubernetes环境中部署Nacos集群与传统的物理机部署存在显著差异。我经历过从虚拟机迁移到Kubernetes的完整过程,发现至少有三个方面需要特别注意:

首先是网络拓扑的变化。Kubernetes的Pod IP是动态分配的,传统的基于固定IP的集群发现机制需要调整为Service域名发现。这直接影响到nacos-cluster.conf的配置方式,我曾因此导致整个集群无法形成法定人数(quorum)。

其次是存储的持久化问题。在默认配置下,Nacos的嵌入式Derby数据库会随着Pod的重启而丢失数据。生产环境必须配置外部MySQL集群,但官方文档对Kubernetes下的MySQL连接配置描述不够详细。

最后是资源管理的差异。物理机部署时我们可以根据机器配置估算资源需求,但在Kubernetes中需要精确设置requests/limits。特别是JVM内存参数与容器内存限制的关系,配置不当会导致频繁OOMKilled。

2. 生产级部署架构设计

2.1 高可用架构拓扑

经过多次生产验证,我推荐采用下图所示架构:

[Nginx Ingress] | [Service: nacos-headless] | [Pod: nacos-0] --- [Pod: nacos-1] --- [Pod: nacos-2] | | | [PVC: nacos-0] [PVC: nacos-1] [PVC: nacos-2] | | | [MySQL MGR集群] [Redis哨兵集群] [Prometheus+Alertmanager]

关键设计要点:

  1. 使用Headless Service实现Pod间直接通信
  2. 每个Pod绑定独立PVC保证日志持久化
  3. MySQL采用MGR集群确保数据高可用
  4. 监控体系需要覆盖JVM、中间件和K8s指标

2.2 资源配置计算公式

对于生产环境,我总结出以下资源配置公式:

  • CPU:
    • 基础需求 = 核数 × 1.5 (安全系数)
    • 例如3节点集群:3 × 2核 × 1.5 = 9核总量
  • 内存:
    • JVM堆内存 = (容器内存限制 - 1GB) × 0.7
    • 例如设置4GB限制:-Xms2457m -Xmx2457m
  • 存储:
    • 日志存储 = 每日日志量 × 保留天数 × 副本数
    • 通常配置50Gi/节点能满足两周需求

3. 详细部署步骤

3.1 前置条件准备

# 创建专用命名空间 kubectl create ns nacos-prod # 准备MySQL配置文件 cat <<EOF > mysql-config.cnf [mysqld] server-id = \${POD_INDEX} log-bin = mysql-bin binlog_format = ROW transaction_isolation = READ-COMMITTED EOF # 创建Secret存储数据库密码 kubectl create secret generic mysql-secret \ --from-literal=password='Nacos@123' \ -n nacos-prod

3.2 StatefulSet核心配置

apiVersion: apps/v1 kind: StatefulSet metadata: name: nacos namespace: nacos-prod spec: serviceName: nacos-headless replicas: 3 template: spec: containers: - name: nacos image: nacos/nacos-server:2.4.0 env: - name: MODE value: cluster - name: SPRING_DATASOURCE_PLATFORM value: mysql - name: MYSQL_SERVICE_HOST value: "mysql-mgr.nacos-prod.svc.cluster.local" - name: MYSQL_SERVICE_DB_NAME value: "nacos_config" - name: MYSQL_SERVICE_USER value: "nacos" - name: MYSQL_SERVICE_PASSWORD valueFrom: secretKeyRef: name: mysql-secret key: password ports: - containerPort: 8848 name: client - containerPort: 9848 name: raft readinessProbe: httpGet: path: /nacos/health port: 8848 initialDelaySeconds: 30 periodSeconds: 10 resources: limits: cpu: "2" memory: 4Gi requests: cpu: "1" memory: 2Gi volumeMounts: - name: config mountPath: /home/nacos/conf - name: logs mountPath: /home/nacos/logs volumeClaimTemplates: - metadata: name: logs spec: accessModes: [ "ReadWriteOnce" ] storageClassName: "csi-rbd-sc" resources: requests: storage: 50Gi

3.3 网络与服务配置

apiVersion: v1 kind: Service metadata: name: nacos-headless namespace: nacos-prod annotations: service.alpha.kubernetes.io/tolerate-unready-endpoints: "true" spec: clusterIP: None ports: - name: client port: 8848 targetPort: client - name: raft port: 9848 targetPort: raft selector: app: nacos publishNotReadyAddresses: true --- apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: nacos-ingress namespace: nacos-prod annotations: nginx.ingress.kubernetes.io/upstream-hash-by: "$remote_addr" spec: ingressClassName: nginx rules: - host: nacos.company.com http: paths: - path: / pathType: Prefix backend: service: name: nacos-headless port: number: 8848

4. 关键调优参数

4.1 JVM参数优化

在configmap中添加以下JVM参数:

JAVA_OPT="${JAVA_OPT} -server -Xms2g -Xmx2g" JAVA_OPT="${JAVA_OPT} -XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m" JAVA_OPT="${JAVA_OPT} -XX:+UseG1GC -XX:MaxGCPauseMillis=200" JAVA_OPT="${JAVA_OPT} -XX:+HeapDumpOnOutOfMemoryError" JAVA_OPT="${JAVA_OPT} -Djava.security.egd=file:/dev/./urandom"

4.2 集群通信参数

# conf/cluster.conf nacos-0.nacos-headless.nacos-prod.svc.cluster.local:8848 nacos-1.nacos-headless.nacos-prod.svc.cluster.local:8848 nacos-2.nacos-headless.nacos-prod.svc.cluster.local:8848 # conf/application.properties nacos.core.protocol.raft.data.dir=/home/nacos/data/raft nacos.naming.distro.taskDispatchThreadCount=8 nacos.naming.distro.taskDispatchPeriod=1000 nacos.naming.distro.batchSyncKeyCount=1000

5. 生产验证与监控

5.1 健康检查方案

# 集群状态检查 curl -X GET "http://nacos.company.com/nacos/v1/ns/operator/health?format=json" # 节点健康检查 for pod in $(kubectl get pods -n nacos-prod -l app=nacos -o name); do kubectl exec -n nacos-prod $pod -- curl -s localhost:8848/nacos/health done # 数据库连接检查 kubectl exec -n nacos-prod nacos-0 -- \ mysql -hmysql-mgr -unacos -p$MYSQL_PWD -e "SHOW DATABASES;"

5.2 Prometheus监控配置

- job_name: 'nacos' metrics_path: '/nacos/actuator/prometheus' kubernetes_sd_configs: - role: pod namespaces: names: ['nacos-prod'] relabel_configs: - source_labels: [__meta_kubernetes_pod_label_app] action: keep regex: nacos - source_labels: [__address__] action: replace regex: ([^:]+)(?::\d+)? replacement: ${1}:8848 target_label: __address__

6. 故障处理实录

6.1 脑裂问题处理

当网络分区发生时,可能出现以下症状:

  • 控制台显示节点健康但配置修改不同步
  • 客户端获取的配置出现不一致
  • 日志中出现"leader timeout"警告

解决方案:

  1. 检查raft日志确认leader状态
    kubectl exec -n nacos-prod nacos-0 -- \ tail -100 /home/nacos/logs/nacos-raft.log
  2. 强制重置集群状态(谨慎操作):
    # 停止所有Pod kubectl scale sts nacos --replicas=0 -n nacos-prod # 清理raft数据 for i in 0 1 2; do kubectl exec -n nacos-prod nacos-$i -- \ rm -rf /home/nacos/data/raft/* done # 重启集群 kubectl scale sts nacos --replicas=3 -n nacos-prod

6.2 客户端连接优化

常见客户端问题及解决方案:

问题现象可能原因解决方案
长轮询超时客户端未使用集群模式配置所有节点地址
配置更新延迟客户端缓存时间过长调整cacheMillis参数
频繁重连网络抖动或DNS解析问题启用客户端本地缓存

Java客户端推荐配置:

Properties properties = new Properties(); properties.put(PropertyKeyConst.SERVER_ADDR, "nacos.company.com:8848"); properties.put(PropertyKeyConst.NAMESPACE, "prod-env"); // 启用故障转移模式 properties.put(PropertyKeyConst.ENABLE_REMOTE_SYNC_CONFIG, "true"); // 设置本地缓存 properties.put(PropertyKeyConst.CONFIG_LONG_POLL_TIMEOUT, "30000"); properties.put(PropertyKeyConst.CONFIG_RETRY_TIME, "5000");

7. 升级与维护策略

7.1 滚动升级方案

采用分批次升级策略确保服务不中断:

  1. 先升级一个从节点并验证
  2. 手动触发leader切换
    curl -X PUT "http://nacos-0:8848/nacos/v1/ns/operator/leader"
  3. 升级原leader节点
  4. 最后升级剩余从节点

7.2 数据迁移流程

从旧版本迁移的关键步骤:

  1. 使用官方工具导出配置
    nacos-export.sh --export --dir /backup \ --host old.nacos.com --port 8848
  2. 验证备份数据完整性
  3. 在新集群执行导入
    nacos-import.sh --import --dir /backup \ --host new.nacos.com --port 8848
  4. 保持双集群并行运行至少24小时

8. 安全加固措施

8.1 认证与鉴权配置

# application.properties nacos.core.auth.enabled=true nacos.core.auth.system.type=nacos nacos.core.auth.plugin.nacos.token.secret.key=VGhpc0lzQXZlcnlTZWNyZXRLZXlEZjM= nacos.core.auth.server.identity.key=serverIdentity nacos.core.auth.server.identity.value=security # 创建管理员账号 kubectl exec -n nacos-prod nacos-0 -- \ curl -X POST "http://localhost:8848/nacos/v1/auth/users?username=admin&password=Strong@Pass123"

8.2 网络策略限制

apiVersion: networking.k8s.io/v1 kind: NetworkPolicy metadata: name: nacos-access-control namespace: nacos-prod spec: podSelector: matchLabels: app: nacos policyTypes: - Ingress ingress: - from: - namespaceSelector: matchLabels: project: microservices ports: - protocol: TCP port: 8848 - protocol: TCP port: 9848

在实际生产环境中运行Nacos集群两年多,最大的经验是一定要提前规划好容量。我们曾经因为低估了配置变更频率导致磁盘频繁告警,后来通过以下措施彻底解决:

  1. 配置日志自动归档脚本
  2. 对历史配置设置保留策略
  3. 定期清理不用的命名空间
  4. 为监控系统设置合理的告警阈值