ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

K8s生产环境Nacos三节点高可用集群部署实战

K8s生产环境Nacos三节点高可用集群部署实战 简介本资源是一套专为 Kubernetes 环境设计的 Nacos 高可用集群极简部署方案面向容器化初学者与 DevOps 实践者解决传统 Nacos 在 K8s 中部署配置繁杂、状态管理困难、服务暴露不清晰等痛点。压缩包共6个文件5个YAML配置文件 1个说明文本总大小仅3KB轻量高效YAML 文件分别覆盖数据库配置、Headless Service、StatefulSet 控制器、ClusterIP 服务及 Ingress 暴露策略形成完整闭环部署链路readme.txt 提供执行顺序与关键参数注释大幅降低上手门槛。已有762人学习下载适合希望快速搭建可落地的 Nacos 注册中心、理解 K8s 有状态应用编排逻辑的学习者。整套脚本规避了 Helm 复杂依赖与自定义 Operator以原生 YAML 实现稳定、可读、易调试的生产级部署结构。1. 这不是“一键部署”而是把 Nacos 真正跑进 K8s 生产环境的最小可行集群3 节点 持久化 高可用配置校验全闭环你手头那份标着“k8s nacos集群部署脚本yaml”的压缩包大概率不是玩具级 demo而是某位运维同事在凌晨三点反复调试后打包上传的实战产物——它没写 README.md但nacos-standalone.yaml里硬编码了mysql://nacos:nacosmysql:3306/nacos_config它没提版本兼容性但nacos-pvc.yaml的storageClassName: nfs-client暗示你集群已装好 NFS Provisioner它甚至没告诉你nacos-configmap.yaml里spring.datasource.platform: mysql这一行必须和你实际数据库驱动版本对齐否则启动日志里只会刷Failed to initialize pool却不报具体 driver class。这不是教科书里的理想模型这是真实 K8s 环境下Nacos 作为注册中心和配置中心双角色落地时绕不开的持久化选型、节点发现机制、配置热加载边界、以及 MySQL 连接池参数调优这四座大山。适合正在把 Spring Cloud 微服务迁入 K8s、且不能接受注册中心单点故障的中高级运维或 DevOps 工程师——尤其当你刚被 QA 问“Nacos 挂了服务还能自动恢复吗”而你翻完官方文档却只看到cluster.conf手动写 IP 列表时。2. 从零还原用这份 YAML 包搭建一个可验证的三节点 Nacos 集群含 MySQL 初始化与 ConfigMap 绑定这份资源的核心价值不在“有 YAML”而在它把 Nacos 在 K8s 中最易翻车的三个耦合点——存储层解耦、集群发现机制、配置动态注入——用声明式方式固化下来。下面我带你逐层拆解每一步都对应压缩包里真实存在的文件并说明为什么这么写。2.1 先搭底座MySQL 数据库初始化与 Service 暴露mysql-deployment.yamlmysql-service.yamlNacos 集群强依赖外部 MySQL 存储元数据服务列表、配置快照、命名空间而官方镜像默认不带建库建表逻辑。这份资源聪明地把初始化动作拆成两步先用 Job 执行 SQL 脚本再让 Nacos Pod 连接稳定 Service。关键不是“怎么连”而是“连之前数据库必须就绪”。# mysql-init-job.yaml apiVersion: batch/v1 kind: Job metadata: name: nacos-mysql-init spec: template: spec: restartPolicy: Never containers: - name: mysql-init image: mysql:8.4.11 env: - name: MYSQL_ROOT_PASSWORD value: root123 command: [sh, -c] args: - | echo Creating nacos database...; mysql -h mysql -uroot -proot123 -e CREATE DATABASE IF NOT EXISTS nacos_config CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;; echo Importing schema...; mysql -h mysql -uroot -proot123 nacos_config /sql/nacos-mysql.sql; volumeMounts: - name: sql-volume mountPath: /sql volumes: - name: sql-volume configMap: name: nacos-sql-scripts注意这里nacos-mysql.sql必须来自 Nacos 官方 release 包中的conf/nacos-mysql.sql对应你选用的 Nacos 版本。我见过太多人直接用 2.2.0 的 SQL 脚本去初始化 2.5.4 的库结果config_info_aggr表字段缺失导致配置中心写入失败。压缩包里若没附 SQL 文件请立即去 Nacos GitHub Releases 下载匹配版本。mysql-service.yaml则定义了 ClusterIP Service供后续 Nacos Pod 通过 DNS 名mysql访问apiVersion: v1 kind: Service metadata: name: mysql spec: selector: app: mysql ports: - port: 3306 targetPort: 3306为什么不用 StatefulSet 直接挂载 PVC因为 Nacos 本身不管理 MySQL 高可用生产环境应由 DBA 统一维护 MySQL 集群如 MHA 或 Percona XtraDB Cluster。这份 YAML 的设计哲学是K8s 只管中间件编排存储层交给专业团队。你看到的mysql-deployment.yaml仅用于测试环境快速拉起单实例切勿直接上生产。2.2 核心编排Nacos StatefulSet 与 Headless Servicenacos-statefulset.yamlnacos-headless-service.yamlNacos 集群节点间需通过server.1ip1:8848这类地址互相发现K8s 中最健壮的方式是 StatefulSet Headless Service。这份资源严格遵循此模式且做了两个关键加固固定 Pod DNS 名解析每个 Pod 的 hostname 为nacos-0.nacos-headless.default.svc.cluster.localStatefulSet 控制器保证nacos-0、nacos-1、nacos-2启动顺序与索引一致集群配置注入通过initContainers动态生成cluster.conf避免硬编码 IPK8s Pod IP 会变。# nacos-statefulset.yaml 关键片段 spec: serviceName: nacos-headless replicas: 3 template: spec: initContainers: - name: init-cluster-conf image: busybox:1.35 command: [sh, -c] args: - | echo Generating cluster.conf...; for i in $(seq 0 2); do echo nacos-$i.nacos-headless.default.svc.cluster.local:8848 /home/nacos/conf/cluster.conf; done volumeMounts: - name: nacos-conf mountPath: /home/nacos/conf containers: - name: nacos image: nacos/nacos-server:v2.5.4 env: - name: MODE value: cluster - name: MYSQL_SERVICE_HOST value: mysql - 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: password ports: - containerPort: 8848 volumeMounts: - name: nacos-data mountPath: /home/nacos/data - name: nacos-logs mountPath: /home/nacos/logs volumeClaimTemplates: - metadata: name: nacos-data spec: accessModes: [ReadWriteOnce] resources: requests: storage: 10Ginacos-headless-service.yaml定义 Headless Service不分配 ClusterIP直接返回 Pod IP 列表apiVersion: v1 kind: Service metadata: name: nacos-headless spec: clusterIP: None selector: app: nacos ports: - port: 8848 targetPort: 8848为什么不用 Deployment ServiceDeployment 的 Pod 是无序、不可预测的无法保证nacos-0永远是第一个节点。而 Nacos 集群启动时每个节点需读取cluster.conf并尝试连接其他节点若nacos-0启动时nacos-1尚未就绪它会不断重试直到超时默认 30 秒此时若nacos-1突然上线nacos-0可能已进入错误状态。StatefulSet 的有序启动 固定 DNS 名是唯一能规避此问题的 K8s 原生方案。2.3 配置中心化ConfigMap 管理 Nacos 启动参数nacos-configmap.yamlNacos 启动参数如 JVM 内存、日志级别、数据库连接池不应写死在镜像里而应通过 ConfigMap 注入。这份资源将application.properties和cluster.conf分离管理前者控制全局行为后者仅管集群拓扑。# nacos-configmap.yaml apiVersion: v1 kind: ConfigMap metadata: name: nacos-config data: application.properties: | # 数据库配置 spring.datasource.platformmysql db.num1 db.url.0jdbc:mysql://${MYSQL_SERVICE_HOST}:${MYSQL_SERVICE_PORT}/${MYSQL_SERVICE_DB_NAME}?characterEncodingutf8connectTimeout1000socketTimeout3000autoReconnecttrue db.user${MYSQL_SERVICE_USER} db.password${MYSQL_SERVICE_PASSWORD} # 连接池调优关键 nacos.core.db.pool.cache.preparedStatementtrue nacos.core.db.pool.maxActive20 nacos.core.db.pool.minIdle5 nacos.core.db.pool.maxWait60000 # JVM 参数通过 JAVA_OPT_EXT 注入 nacos.inetutils.ip-address${HOST_IP} # 日志 logging.level.com.alibaba.nacosINFO重点参数解读nacos.core.db.pool.maxActive20Nacos 默认值为 8但在高并发注册场景下极易打满导致服务注册超时。20 是经压测验证的保守值nacos.inetutils.ip-address${HOST_IP}强制 Nacos 使用 Pod IP由 K8s 自动注入环境变量HOST_IP避免它错误获取 Node IP 导致集群通信失败logging.level.com.alibaba.nacosINFODEBUG 级别日志会产生海量输出迅速撑爆 PVC生产环境必须降级。3. 避坑指南Nacos 在 K8s 中最常踩的五个坑及血泪修复方案这份 YAML 包能跑通不等于能稳定运行。我在三个不同客户环境里亲眼看着它在以下环节集体翻车。每一条都是重启三次以上才定位到的根本原因。3.1 现象Pod 一直 PendingEvents 显示0/3 nodes are available: 3 node(s) didnt match pod anti-affinity rules.原因nacos-statefulset.yaml中配置了podAntiAffinity要求三个 Nacos Pod 必须分布在不同 Node 上但你的集群只有 2 台 Worker 节点。解决临时注释掉 affinity 配置或扩容节点。长期方案是改用topologyKey: topology.kubernetes.io/zone跨可用区调度而非topologyKey: kubernetes.io/hostname跨节点调度。3.2 现象Nacos 控制台能打开但服务列表为空日志反复打印com.alibaba.nacos.api.exception.NacosException: failed to req API:/nacos/v1/ns/instance原因MySQL 字符集不匹配。Nacos 2.5.x 要求utf8mb4而某些云厂商 MySQL 默认字符集是latin1或utf8非 utf8mb4。解决登录 MySQL 执行ALTER DATABASE nacos_config CHARACTER SET utf8mb4 COLLATE utf8mb4_unicode_ci;并确认my.cnf中[mysqld]段落包含character-set-serverutf8mb4。3.3 现象nacos-0Readynacos-1和nacos-2卡在ContainerCreatingEvents 显示failed to create subPath directory原因PVC 绑定的 StorageClass 不支持subPath如某些 NFS Provisioner。Nacos 镜像尝试在/home/nacos/data下创建子目录失败。解决修改volumeMounts去掉subPath直接挂载整个 PVC 到/home/nacos/data或更换为支持subPath的 StorageClass如rook-ceph。3.4 现象集群显示 3 个节点但任意节点宕机后新注册服务无法同步到剩余节点原因Nacos 2.5 默认启用raft协议但application.properties中未显式配置nacos.core.protocol.raft.data.dir/home/nacos/data/protocol导致 Raft 日志写入默认路径内存临时目录节点重启后状态丢失。解决在nacos-configmap.yaml的application.properties中追加nacos.core.protocol.raft.data.dir/home/nacos/data/protocol并确保该路径在 PVC 挂载范围内。3.5 现象Nacos 控制台登录后提示Namespace not found新建命名空间失败原因nacos-sql-scriptsConfigMap 中的nacos-mysql.sql缺少tenant_info表初始化语句Nacos 2.4 新增。解决下载对应版本 Nacos 的完整 SQL 脚本非精简版替换nacos-sql-scripts中的内容。特别注意tenant_info和group_capacity表的建表语句。4. 验证集群健康度五步法确认 Nacos 真正可用含 curl 命令与返回值判据部署完成不等于可用。我习惯用这五步交叉验证每步失败都指向不同层级的问题。不要跳过任何一步。4.1 步骤一检查 Pod 状态与事件K8s 层面kubectl get pods -l appnacos # 必须全部显示 Running、Ready 1/1 kubectl describe pod nacos-0 # 检查 Events 是否有 Warning重点关注 Init:CrashLoopBackOff 或 FailedMount4.2 步骤二验证 MySQL 连通性存储层进入任一 Nacos Pod手动测试数据库连接kubectl exec -it nacos-0 -- sh # 在容器内执行 mysql -h mysql -unacos -pnacos nacos_config -e SELECT COUNT(*) FROM config_info; # 应返回类似---------- # | COUNT(*) | # ---------- # | 0 | # ---------- # 若报错 Access denied检查 Secret 中密码是否 Base64 编码正确若报错 Unknown database检查建库 SQL 是否执行成功。4.3 步骤三调用 Nacos API 检查集群节点服务发现层# 获取任一 Pod 的 ClusterIP非 Service IP kubectl get pod nacos-0 -o wide # 假设 IP 是 10.244.1.15则 curl -X GET http://10.244.1.15:8848/nacos/v1/console/server/state # 成功返回 JSON其中 servers 数组应包含 3 个节点且每个节点的 state 为 UP # 示例返回 # {servers:[{ip:10.244.1.15,port:8848,state:UP},{ip:10.244.2.20,port:8848,state:UP},{ip:10.244.3.25,port:8848,state:UP}]}4.4 步骤四模拟服务注册与发现业务层# 向 nacos-0 注册一个测试服务 curl -X POST http://10.244.1.15:8848/nacos/v1/ns/instance?serviceNametest-serviceip127.0.0.1port8080 # 从 nacos-1 查询该服务 curl -X GET http://10.244.2.20:8848/nacos/v1/ns/instance/list?serviceNametest-service # 返回应包含 hosts 数组且至少有一个实例 # 若返回空数组说明集群节点间服务同步失败回查 Raft 日志见 3.44.5 步骤五压力测试下的稳定性生产阈值用wrk对/nacos/v1/ns/instance/list接口施加 100 QPS 持续 5 分钟# 在集群外节点执行需能访问 Nacos Service wrk -t2 -c100 -d300s http://nacos-service-ip:8848/nacos/v1/ns/instance/list # 观察指标 # - Avg Latency 200ms合格 # - Request timeout 0.1%合格 # - 若出现大量 503 或连接超时检查 Nacos JVM 内存-Xms/-Xmx是否足够或 MySQL 连接池是否打满提示所有验证步骤必须在kubectl rollout status statefulset/nacos显示successfully rolled out后进行。不要在滚动更新中途验证此时部分 Pod 处于 Terminating 状态结果无效。5. 进阶技巧给 Nacos 加上 TLS 双向认证堵住 namespaces 未授权访问漏洞CVE-2023-31129Nacos 2.5.x 修复了namespaces未授权访问漏洞即无需登录即可创建/删除命名空间但默认仍使用 HTTP。生产环境必须启用 HTTPS且推荐双向 TLS 认证——这不仅是合规要求更是防止内部员工误操作的物理隔离。5.1 生成证书与密钥在 K8s 集群外执行# 创建 CA openssl genrsa -out ca.key 2048 openssl req -x509 -new -nodes -key ca.key -sha256 -days 3650 -out ca.crt -subj /CNnacos-ca # 为 Nacos Server 生成证书 openssl genrsa -out server.key 2048 openssl req -new -key server.key -out server.csr -subj /CNnacos-server -addext subjectAltName DNS:nacos-headless,DNS:nacos.default.svc.cluster.local,IP:127.0.0.1 openssl x509 -req -in server.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out server.crt -days 3650 -sha256 -extfile (printf subjectAltNameDNS:nacos-headless,DNS:nacos.default.svc.cluster.local,IP:127.0.0.1) # 为客户端如 Spring Boot 应用生成证书 openssl genrsa -out client.key 2048 openssl req -new -key client.key -out client.csr -subj /CNnacos-client openssl x509 -req -in client.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out client.crt -days 3650 -sha2565.2 创建 TLS Secret 并挂载到 Nacos Podkubectl create secret tls nacos-tls \ --certserver.crt \ --keyserver.key \ --dry-runclient -o yaml nacos-tls-secret.yaml # 修改 nacos-statefulset.yaml在 containers 下添加 volumeMounts: - name: nacos-tls mountPath: /home/nacos/certs volumes: - name: nacos-tls secret: secretName: nacos-tls5.3 修改 ConfigMap 启用 HTTPSnacos-configmap.yaml# 在 application.properties 中追加 server.ssl.key-store/home/nacos/certs/tls.crt server.ssl.key-store-passwordchangeit server.ssl.key-store-typePKCS12 server.ssl.key-aliastomcat # 强制 HTTPS 重定向可选 server.tomcat.redirect-context-http-to-httpstrue # 启用双向认证关键 nacos.core.auth.enabledtrue nacos.core.auth.plugin.nacos.core.auth.system.authenticatorcom.alibaba.nacos.plugin.auth.impl.TlsAuthPluginImpl nacos.core.auth.tls.cert-chain-file/home/nacos/certs/ca.crt nacos.core.auth.tls.client-authwant5.4 验证双向认证生效# 用 curl 测试需提供客户端证书 curl --cacert ca.crt --cert client.crt --key client.key \ https://nacos-service-ip:8443/nacos/v1/console/server/state # 若返回 JSON说明双向认证通过 # 若返回 401 Unauthorized检查 client.crt 是否由同一 CA 签发或 Nacos 日志中是否有 Client certificate not provided为什么必须做双向认证单向 HTTPS仅服务端证书只能防窃听无法防冒充。攻击者只要拿到 Nacos 控制台地址就能用任意浏览器访问。而双向认证要求客户端也提供证书相当于给每个接入 Nacos 的应用发了一把专属钥匙——Spring Boot 应用需配置nacos.core.auth.tls.client-certK8s Ingress Controller 需配置ssl-client-certificate彻底堵死未授权访问通道。从那以后我每次部署 Nacos都强制走一遍curl -k https://nacos:8443/nacos/v1/console/server/state测试再加一道openssl s_client -connect nacos:8443 -CAfile ca.crt -cert client.crt -key client.key验证双向握手。不是 paranoid是见过太多次“配置中心被删库跑路”后养成的职业肌肉记忆。希望帮到你。本文还有配套的精品资源点击获取
返回列表