1. 为什么选择OpenEBS+StatefulSet部署Nacos集群

在微服务架构中,服务注册与发现是核心基础设施。Nacos作为阿里巴巴开源的动态服务发现、配置管理和服务管理平台,已经成为Spring Cloud Alibaba生态中的标配组件。但在生产环境中,单节点Nacos显然无法满足高可用需求。

我经历过一次线上事故:由于Nacos单节点宕机,导致整个微服务体系瘫痪。这次教训让我深刻认识到,生产环境必须部署Nacos集群。而Kubernetes的StatefulSet配合OpenEBS提供的持久化存储,是实现这一目标的最佳实践方案。

StatefulSet与Deployment的最大区别在于它能为每个Pod提供稳定的网络标识和持久化存储。这对于Nacos这类有状态服务至关重要:

  • 每个Nacos节点有固定的DNS名称(如nacos-0.nacos-headless.nacos.svc.cluster.local)
  • Pod重启后仍能挂载原有的数据卷
  • 支持有序的扩缩容(这对集群选举很关键)

OpenEBS则解决了K8s本地存储管理的痛点:

  • 开箱即用的动态存储供给
  • 数据持久化不依赖特定节点
  • 支持多种存储引擎(本次使用hostpath模式)
  • 完善的监控和运维工具链

2. 环境准备与OpenEBS部署

2.1 基础环境检查

在开始前,请确保你的K8s集群满足以下条件:

  • Kubernetes版本≥1.18(本文使用v1.18.0验证)
  • 每个节点已安装iscsi-initiator-utils(OpenEBS依赖)
  • 至少有3个可用节点(1个Master+2个Worker)
  • 节点间网络互通且时钟同步

验证节点就绪状态:

kubectl get nodes -o wide

正常应看到所有节点STATUS为Ready。

2.2 OpenEBS安装与验证

OpenEBS的安装非常简单:

kubectl apply -f https://openebs.github.io/charts/openebs-operator.yaml

等待约2分钟,检查所有Pod是否运行正常:

kubectl get pods -n openebs

预期看到类似以下输出:

openebs-localpv-provisioner-5c64ffd6df-4z9vf   1/1     Running
openebs-ndm-9rz2n                              1/1     Running  
openebs-ndm-operator-7c4694c5d7-8j5l8          1/1     Running
openebs-ndm-xk5w9                              1/1     Running

特别提醒:如果发现openebs-ndm Pod处于Pending状态,通常是节点没有安装iscsi-initiator-utils导致。在Ubuntu上可通过以下命令修复:

sudo apt-get update && sudo apt-get install -y open-iscsi

3. MySQL数据库部署

3.1 为什么选择独立MySQL

Nacos支持两种存储模式:

  • 嵌入式Derby数据库(适合测试)
  • 外置MySQL(生产推荐)

我们选择MySQL的原因:

  1. 数据可持久化保存
  2. 方便备份恢复
  3. 支持多Nacos节点共享数据
  4. 可利用现有数据库高可用方案

3.2 使用StatefulSet部署MySQL

创建nacos命名空间:

kubectl create ns nacos

mysql.yml配置文件关键点解析:

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: mysql
  namespace: nacos
spec:
  serviceName: "mysql"  # Headless Service名称
  replicas: 1           # 单节点即可,生产建议主从
  template:
    spec:
      containers:
      - name: mysql
        image: mysql:5.7
        env:
        - name: MYSQL_ROOT_PASSWORD
          value: "root"  # 生产环境务必修改
        volumeMounts:
        - name: mysql-data
          mountPath: /var/lib/mysql
  volumeClaimTemplates:  # 动态存储声明
  - metadata:
      name: mysql-data
    spec:
      accessModes: ["ReadWriteOnce"]
      storageClassName: openebs-hostpath  # 使用OpenEBS提供的存储类
      resources:
        requests:
          storage: 5Gi

应用配置并验证:

kubectl apply -f mysql.yml
kubectl get pods -n nacos -w  # 观察Pod启动过程

3.3 初始化Nacos数据库

从Nacos GitHub下载安装包(本文使用2.0.3版本):

wget https://github.com/alibaba/nacos/releases/download/2.0.3/nacos-server-2.0.3.tar.gz
tar -zxvf nacos-server-2.0.3.tar.gz

进入MySQL Pod创建数据库:

kubectl exec -it mysql-0 -n nacos -- mysql -uroot -proot

执行SQL语句:

CREATE DATABASE nacos DEFAULT CHARACTER SET utf8mb4;
USE nacos;
SOURCE /tmp/nacos-mysql.sql;  # 将解压后的config/nacos-mysql.sql拷贝到Pod内
exit

4. Nacos集群部署实战

4.1 集群拓扑设计

我们部署3节点Nacos集群,架构特点:

  • 每个节点有固定标识(nacos-0, nacos-1, nacos-2)
  • 通过headless service实现节点间直接通信
  • 共享同一个MySQL数据库
  • 通过NodePort对外暴露控制台

4.2 关键配置解析

nacos.yml中的核心参数说明:

env:
- name: NACOS_REPLICAS
  value: "3"  # 集群节点数
- name: MYSQL_SERVICE_HOST
  valueFrom:
    configMapKeyRef:
      name: nacos-cm
      key: mysql.host  # 指向之前部署的MySQL
- name: PREFER_HOST_MODE
  value: "hostname"  # 使用主机名模式
- 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"

启动集群:

kubectl apply -f nacos.yml
watch kubectl get pods -n nacos  # 观察3个Pod陆续启动

4.3 集群健康检查

查看节点日志确认集群形成:

kubectl logs nacos-0 -n nacos | grep "Cluster"

正常会看到类似日志:

INFO The cluster resource is initialized
INFO Current cluster nodes: [nacos-0, nacos-1, nacos-2]

浏览器访问NodePort(31848端口):

http://<任意节点IP>:31848/nacos

使用默认账号nacos/nacos登录后,在"集群管理→节点列表"应看到3个UP状态的节点。

5. 微服务集成实践

5.1 服务提供者开发

Spring Boot应用接入Nacos的关键步骤:

  1. pom.xml添加依赖:
<dependency>
    <groupId>com.alibaba.cloud</groupId>
    <artifactId>spring-cloud-starter-alibaba-nacos-discovery</artifactId>
</dependency>
  1. 配置application.yml:
spring:
  application:
    name: provider-service  # 服务名
  cloud:
    nacos:
      discovery:
        server-addr: ${NACOS_SERVER:nacos:8848}  # 支持环境变量覆盖
  1. 启动类添加注解:
@EnableDiscoveryClient
@SpringBootApplication
public class ProviderApplication {...}
  1. 暴露测试接口:
@RestController
public class ProviderController {
    @GetMapping("/health")
    public String health() {
        return "OK from " + InetAddress.getLocalHost().getHostName();
    }
}

5.2 服务消费者开发

消费者端额外需要:

  1. OpenFeign声明式调用
  2. Nacos配置管理

关键配置bootstrap.yml:

spring:
  cloud:
    nacos:
      config:
        server-addr: ${NACOS_SERVER:nacos:8848}
        file-extension: yaml  # 配置格式

FeignClient接口示例:

@FeignClient(name = "provider-service")
public interface ProviderClient {
    @GetMapping("/health")
    String health();
}

动态配置测试接口:

@RestController
@RefreshScope  // 支持配置动态刷新
public class ConsumerController {
    @Value("${config.key:default}")
    private String configValue;
    
    @GetMapping("/config")
    public String getConfig() {
        return configValue;
    }
}

5.3 K8s部署微服务

deployment.yml示例片段:

env:
- name: NACOS_SERVER  # 通过环境变量传递Nacos集群地址
  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"

部署后验证:

  1. 在Nacos控制台"服务管理"应看到注册的服务
  2. 多次访问消费者接口,观察负载均衡效果
  3. 修改Nacos配置,验证动态刷新

6. 生产环境优化建议

6.1 存储优化方案

OpenEBS的hostpath模式适合测试环境,生产推荐:

  1. 使用OpenEBS cStor引擎:支持副本、压缩等高级功能
  2. 定期备份PVC数据
  3. 设置合理的存储资源限制

6.2 Nacos调优参数

jvm参数建议:

env:
- name: JVM_XMS
  value: "2g"
- name: JVM_XMX
  value: "2g"
- name: NACOS_SERVER_IP
  valueFrom:
    fieldRef:
      fieldPath: status.podIP

6.3 监控与告警

建议配置:

  1. Prometheus监控Nacos指标
  2. 告警规则:
    • 节点DOWN
    • 健康检查失败
    • 配置变更频繁告警
  3. 日志收集分析

7. 常见问题排查

7.1 集群节点无法发现

现象:Nacos日志中出现"failed to get service"错误 排查步骤:

  1. 检查DNS解析是否正常:
    kubectl exec -it nacos-0 -n nacos -- ping nacos-1.nacos-headless.nacos.svc.cluster.local
    
  2. 验证网络策略是否允许Pod间通信
  3. 检查防火墙规则

7.2 配置更新不生效

可能原因:

  1. 应用未添加@RefreshScope注解
  2. bootstrap.yml配置不正确
  3. 配置Data ID格式不匹配(需为${spring.application.name}.${file-extension})

7.3 磁盘空间不足

处理方法:

  1. 扩容PVC:
    kubectl edit pvc <pvc-name> -n nacos
    
  2. 清理Nacos旧日志:
    kubectl exec -it nacos-0 -n nacos -- rm -f /home/nacos/logs/*.log.*
    

8. 经验分享与踩坑记录

在实际部署过程中,有几个容易忽略的细节值得注意:

  1. 网络时延问题:在跨可用区部署时,曾遇到由于节点间网络延迟过高导致集群脑裂。解决方案是调整选举超时参数:

    - name: NACOS_RAFT_ELECTION_TIMEOUT_MS
      value: "5000"
    
  2. JVM内存设置:默认1GB内存对于生产环境偏小,建议根据节点规格调整:

    - name: JVM_XMS
      value: "2g"
    - name: JVM_XMX 
      value: "2g"
    
  3. 存储性能瓶颈:当配置变更频繁时,MySQL可能出现性能问题。我们最终采取的方案是:

    • 对MySQL进行读写分离
    • 定期归档历史配置
    • 对核心配置启用本地缓存
  4. 版本兼容性:Spring Cloud Alibaba版本需要与Nacos版本严格匹配。我们维护了一个版本对照表:

    Spring Cloud Alibaba 2.2.6.RELEASE → Nacos 2.0.3
    Spring Boot 2.3.7.RELEASE → Spring Cloud Hoxton.SR9
    
  5. 客户端重试机制:在网络不稳定环境下,建议配置客户端重试:

    spring:
      cloud:
        loadbalancer:
          retry:
            enabled: true
            maxRetriesOnSameServiceInstance: 2
            maxRetriesOnNextServiceInstance: 1
    

更多推荐