Pod 重启 IP 就变——Nacos 上 k8s 的三个致命问题与完整解决方案Deployment 部署 Nacos重启后集群全员失联团队决定把 Nacos 迁移到 k8s。我想着三个 Deployment 不就完了——结果踩了一串连环坑。第一版配置apiVersion:apps/v1kind:Deploymentmetadata:name:nacosspec:replicas:3三个 Pod 跑起来控制台能看到所有节点。一切正常。直到有一天——Pod-0 被 k8s 调度器驱逐重启新 Pod 拿到了新 IP。cluster.conf 里还写着旧 IP。三个节点互相找不到对方集群裂了。后来发现三个问题Pod IP 会变重启后 cluster.conf 里存的是旧地址。不能用 Deployment需要稳定的 Pod 标识来维护集群拓扑。自发现机制和 Readiness Probe 会打架——启动中就被 Service 路由了流量。下面把 k8s 部署 Nacos 的正确姿势完整拆开。第一个问题Pod IP 不稳定cluster.confnacos-pod-2(IP: 10.244.1.25)nacos-pod-1(IP: 10.244.1.24)nacos-pod-0(IP: 10.244.1.23)k8s Schedulercluster.confnacos-pod-2(IP: 10.244.1.25)nacos-pod-1(IP: 10.244.1.24)nacos-pod-0(IP: 10.244.1.23)k8s Scheduler集群正常运行nacos-pod-0 拿到新 IP新 IP: 10.244.1.58不通纳维斯自杀式连接集群裂→只剩两个节点内部通信→一切仍看似正常驱逐 Pod-0重建 Pod-0读 cluster.conf → 10.244.1.23尝试连接 10.244.1.23旧 IP发现 Pod-0 失联发现 Pod-0 失联Pod 重启后 IP 变化cluster.conf 里的旧 IP 失效。如果两个以上节点同时受此影响——集群完全崩溃。解决StatefulSet Headless ServiceStatefulSet 给每个 Pod 分配固定网络标识nacos-0.nacos-headless.nacos.svc.cluster.local nacos-1.nacos-headless.nacos.svc.cluster.local nacos-2.nacos-headless.nacos.svc.cluster.localPod 重启后域名不变即使 IP 变了。# headless-service.yamlapiVersion:v1kind:Servicemetadata:name:nacos-headlessnamespace:nacosspec:clusterIP:None# Headless Service不分配 ClusterIPselector:app:nacosports:-name:httpport:8848targetPort:8848-name:grpc-clientport:9848targetPort:9848-name:grpc-clusterport:9849targetPort:9849坑1不能用普通 Service必须 Headless。普通 Service 有 ClusterIP所有流量经过它代理Pod 不知道自己的域名。Headless ServiceclusterIP: None让每个 Pod 获得独立 DNS 记录。第二个问题Deployment 不适合有状态集群Deployment 管的是无状态副本——Pod 从哪个节点启动无所谓名称随机IP 随机。但集群模式需要启动顺序可控先启动的当 Leader每个节点有固定身份标识滚动更新时知道现在重启的是哪个StatefulSet 完美匹配这三个需求StatefulSet 保障固定 Pod 名称nacos-0 / nacos-1 / nacos-2有序启动nacos-0 → nacos-1 → nacos-2有序终止nacos-2 → nacos-1 → nacos-0独立 PVC每个 Pod 绑定专属存储cluster.conf 用 DNS 名重启后不丢节点避免脑裂第一个 Pod先成为 Leader优雅下线从集群中正常退出StatefulSet 四大保障固定名称、有序启动、逆序终止、独立存储。每一项都命中集群部署的痛点。完整 StatefulSet 配置# statefulset.yamlapiVersion:apps/v1kind:StatefulSetmetadata:name:nacosnamespace:nacosspec:serviceName:nacos-headless# 绑定 Headless Servicereplicas:3podManagementPolicy:Parallel# 并行启动非严格有序但第一个先启selector:matchLabels:app:nacostemplate:metadata:labels:app:nacosspec:# 反亲和三个 Pod 尽量分布在不同节点上affinity:podAntiAffinity:requiredDuringSchedulingIgnoredDuringExecution:-labelSelector:matchLabels:app:nacostopologyKey:kubernetes.io/hostnamecontainers:-name:nacosimage:nacos/nacos-server:v2.3.2env:-name:MODEvalue:cluster-name:PREFER_HOST_MODEvalue:hostname-name:NACOS_SERVERSvalue:nacos-0.nacos-headless.nacos.svc.cluster.local:9849 nacos-1.nacos-headless.nacos.svc.cluster.local:9849 nacos-2.nacos-headless.nacos.svc.cluster.local:9849-name:SPRING_DATASOURCE_PLATFORMvalue:mysql-name:MYSQL_SERVICE_HOSTvalue:mysql.nacos.svc.cluster.local-name:MYSQL_SERVICE_PORTvalue:3306-name:MYSQL_SERVICE_DB_NAMEvalue:nacos_config-name:MYSQL_SERVICE_USERvalueFrom:secretKeyRef:name:nacos-mysql-secretkey:username-name:MYSQL_SERVICE_PASSWORDvalueFrom:secretKeyRef:name:nacos-mysql-secretkey:passwordports:-containerPort:8848name:http-containerPort:9848name:grpc-client-containerPort:9849name:grpc-clusterreadinessProbe:httpGet:path:/nacos/v1/console/health/readinessport:8848initialDelaySeconds:30periodSeconds:10failureThreshold:5livenessProbe:httpGet:path:/nacos/v1/console/health/livenessport:8848initialDelaySeconds:60periodSeconds:20failureThreshold:3第三个问题Readiness Probe 与启动时间打架坑2Readiness Probe 太早探活。Nacos 集群启动需要 30~60 秒初始化数据库 选举。如果initialDelaySeconds设太短Pod 还没准备好就被打入 Service 后端请求直接超时。# 推荐值生产环境readinessProbe:httpGet:path:/nacos/v1/console/health/readinessport:8848initialDelaySeconds:60# 给足启动时间periodSeconds:10failureThreshold:5# 容忍偶尔超时livenessProbe:httpGet:path:/nacos/v1/console/health/livenessport:8848initialDelaySeconds:120# 比 readiness 更晚periodSeconds:20failureThreshold:3Nacos 内部有两个健康端点端点含义探活类型/nacos/v1/console/health/readiness服务是否准备好接收请求Readiness Probe/nacos/v1/console/health/liveness进程是否存活Liveness Probe如果 Liveness Probe 失败k8s 会杀死 Pod 重建。Readiness 失败只是暂时不路由流量。坑3Liveness Probe 设置太激进。选举期间 Nacos 可能短暂不响应不要因为一两次失败就 kill 容器。对外暴露集群内外双通道k8s 集群外k8s 集群内直连通过 NodePort/LoadBalancer业务 PodNacos Headless Service域名nacos-headless.nacosnacos-0nacos-1nacos-2集群外客户端Nacos 对公 Service# service-for-external.yaml# 给集群外客户端和控制台访问apiVersion:v1kind:Servicemetadata:name:nacos-externalnamespace:nacosspec:type:NodePort# 或 LoadBalancerselector:app:nacosports:-name:httpport:8848targetPort:8848nodePort:30848# 对外暴露的端口两套 ServiceHeadless 给集群内 Pod 直连固定 DNSNodePort/LoadBalancer 给集群外客户端和控制台访问。ConfigMap 统一管理配置# configmap.yamlapiVersion:v1kind:ConfigMapmetadata:name:nacos-confignamespace:nacosdata:application.properties:|spring.sql.init.platformmysqldb.num1 db.url.0jdbc:mysql://mysql.nacos.svc.cluster.local:3306/nacos_config?useSSLfalseserverTimezoneAsia/Shanghainacos.core.auth.enabledtrue nacos.core.auth.server.identity.keynacos nacos.core.auth.server.identity.valuenacos通过volumeMounts挂入 PodvolumeMounts:-name:nacos-confmountPath:/home/nacos/conf/application.propertiessubPath:application.propertiesvolumes:-name:nacos-confconfigMap:name:nacos-configHelm 一键部署懒人版# 添加 Nacos Helm 仓库helm repoaddnacos https://nacos-group.github.io/nacos-helm helm repo update# 一键安装helminstallnacos nacos/nacos\--namespacenacos\--create-namespace\--setglobal.modecluster\--setreplicaCount3\--setmysql.enabledtrue\--setmysql.mysqlUsernacos\--setmysql.mysqlPasswordNacos2024# 验证kubectl get pods-nnacos-w# nacos-0 nacos-1 nacos-2 Running常见 k8s 部署问题速查现象原因解决Pod 反复 CrashLoopBackOffLiveness Probe 太激进initialDelaySeconds设 120s集群成员列表只看到自己NACOS_SERVERS写的是 Pod IP 不是 DNS改用 Headless Service DNS 名注册的服务跨 Pod 查不到未共享 MySQL各 Pod 用内置 Derby配置共享 MySQL启动后 Pod 被 Service 路由但仍 503Readiness Probe 还没探活成功耐心等 30~60s不要过早请求podAntiAffinity导致 Pending节点数少于 Pod 数改为preferredDuringScheduling总结Nacos 上 k8s 的五个核心决策StatefulSet 不是 Deployment需要固定 Pod 名 DNS 做集群发现。Headless Service 不是普通 ServiceclusterIP: None给每个 Pod 独立 DNS。cluster.conf 用 DNS 名不是 IPnacos-0.nacos-headless.nacos.svc.cluster.local:9849。Probe 要宽松initialDelaySeconds给 60~120 秒选举期间容忍失败。MySQL 是必须的不能指望 Pod 本地的 Derby 来做集群数据同步。从 Deployment 踩坑到 StatefulSet Headless Service 组合其实就改了三处kind: StatefulSetserviceName绑定 NACOS_SERVERS换 DNS。但每一处都踩过坑才知道。你们 Nacos 跑在什么环境评论区留个数字1传统虚拟机部署 2裸 Docker 容器 3k8s StatefulSet 4Nacos 托管服务MSE/PolarisMesh 等。顺带说一句你觉得 Nacos 上 k8s 最大的坑是什么。
Pod 重启 IP 就变——Nacos 上 k8s 的三个致命问题与完整解决方案
Pod 重启 IP 就变——Nacos 上 k8s 的三个致命问题与完整解决方案Deployment 部署 Nacos重启后集群全员失联团队决定把 Nacos 迁移到 k8s。我想着三个 Deployment 不就完了——结果踩了一串连环坑。第一版配置apiVersion:apps/v1kind:Deploymentmetadata:name:nacosspec:replicas:3三个 Pod 跑起来控制台能看到所有节点。一切正常。直到有一天——Pod-0 被 k8s 调度器驱逐重启新 Pod 拿到了新 IP。cluster.conf 里还写着旧 IP。三个节点互相找不到对方集群裂了。后来发现三个问题Pod IP 会变重启后 cluster.conf 里存的是旧地址。不能用 Deployment需要稳定的 Pod 标识来维护集群拓扑。自发现机制和 Readiness Probe 会打架——启动中就被 Service 路由了流量。下面把 k8s 部署 Nacos 的正确姿势完整拆开。第一个问题Pod IP 不稳定cluster.confnacos-pod-2(IP: 10.244.1.25)nacos-pod-1(IP: 10.244.1.24)nacos-pod-0(IP: 10.244.1.23)k8s Schedulercluster.confnacos-pod-2(IP: 10.244.1.25)nacos-pod-1(IP: 10.244.1.24)nacos-pod-0(IP: 10.244.1.23)k8s Scheduler集群正常运行nacos-pod-0 拿到新 IP新 IP: 10.244.1.58不通纳维斯自杀式连接集群裂→只剩两个节点内部通信→一切仍看似正常驱逐 Pod-0重建 Pod-0读 cluster.conf → 10.244.1.23尝试连接 10.244.1.23旧 IP发现 Pod-0 失联发现 Pod-0 失联Pod 重启后 IP 变化cluster.conf 里的旧 IP 失效。如果两个以上节点同时受此影响——集群完全崩溃。解决StatefulSet Headless ServiceStatefulSet 给每个 Pod 分配固定网络标识nacos-0.nacos-headless.nacos.svc.cluster.local nacos-1.nacos-headless.nacos.svc.cluster.local nacos-2.nacos-headless.nacos.svc.cluster.localPod 重启后域名不变即使 IP 变了。# headless-service.yamlapiVersion:v1kind:Servicemetadata:name:nacos-headlessnamespace:nacosspec:clusterIP:None# Headless Service不分配 ClusterIPselector:app:nacosports:-name:httpport:8848targetPort:8848-name:grpc-clientport:9848targetPort:9848-name:grpc-clusterport:9849targetPort:9849坑1不能用普通 Service必须 Headless。普通 Service 有 ClusterIP所有流量经过它代理Pod 不知道自己的域名。Headless ServiceclusterIP: None让每个 Pod 获得独立 DNS 记录。第二个问题Deployment 不适合有状态集群Deployment 管的是无状态副本——Pod 从哪个节点启动无所谓名称随机IP 随机。但集群模式需要启动顺序可控先启动的当 Leader每个节点有固定身份标识滚动更新时知道现在重启的是哪个StatefulSet 完美匹配这三个需求StatefulSet 保障固定 Pod 名称nacos-0 / nacos-1 / nacos-2有序启动nacos-0 → nacos-1 → nacos-2有序终止nacos-2 → nacos-1 → nacos-0独立 PVC每个 Pod 绑定专属存储cluster.conf 用 DNS 名重启后不丢节点避免脑裂第一个 Pod先成为 Leader优雅下线从集群中正常退出StatefulSet 四大保障固定名称、有序启动、逆序终止、独立存储。每一项都命中集群部署的痛点。完整 StatefulSet 配置# statefulset.yamlapiVersion:apps/v1kind:StatefulSetmetadata:name:nacosnamespace:nacosspec:serviceName:nacos-headless# 绑定 Headless Servicereplicas:3podManagementPolicy:Parallel# 并行启动非严格有序但第一个先启selector:matchLabels:app:nacostemplate:metadata:labels:app:nacosspec:# 反亲和三个 Pod 尽量分布在不同节点上affinity:podAntiAffinity:requiredDuringSchedulingIgnoredDuringExecution:-labelSelector:matchLabels:app:nacostopologyKey:kubernetes.io/hostnamecontainers:-name:nacosimage:nacos/nacos-server:v2.3.2env:-name:MODEvalue:cluster-name:PREFER_HOST_MODEvalue:hostname-name:NACOS_SERVERSvalue:nacos-0.nacos-headless.nacos.svc.cluster.local:9849 nacos-1.nacos-headless.nacos.svc.cluster.local:9849 nacos-2.nacos-headless.nacos.svc.cluster.local:9849-name:SPRING_DATASOURCE_PLATFORMvalue:mysql-name:MYSQL_SERVICE_HOSTvalue:mysql.nacos.svc.cluster.local-name:MYSQL_SERVICE_PORTvalue:3306-name:MYSQL_SERVICE_DB_NAMEvalue:nacos_config-name:MYSQL_SERVICE_USERvalueFrom:secretKeyRef:name:nacos-mysql-secretkey:username-name:MYSQL_SERVICE_PASSWORDvalueFrom:secretKeyRef:name:nacos-mysql-secretkey:passwordports:-containerPort:8848name:http-containerPort:9848name:grpc-client-containerPort:9849name:grpc-clusterreadinessProbe:httpGet:path:/nacos/v1/console/health/readinessport:8848initialDelaySeconds:30periodSeconds:10failureThreshold:5livenessProbe:httpGet:path:/nacos/v1/console/health/livenessport:8848initialDelaySeconds:60periodSeconds:20failureThreshold:3第三个问题Readiness Probe 与启动时间打架坑2Readiness Probe 太早探活。Nacos 集群启动需要 30~60 秒初始化数据库 选举。如果initialDelaySeconds设太短Pod 还没准备好就被打入 Service 后端请求直接超时。# 推荐值生产环境readinessProbe:httpGet:path:/nacos/v1/console/health/readinessport:8848initialDelaySeconds:60# 给足启动时间periodSeconds:10failureThreshold:5# 容忍偶尔超时livenessProbe:httpGet:path:/nacos/v1/console/health/livenessport:8848initialDelaySeconds:120# 比 readiness 更晚periodSeconds:20failureThreshold:3Nacos 内部有两个健康端点端点含义探活类型/nacos/v1/console/health/readiness服务是否准备好接收请求Readiness Probe/nacos/v1/console/health/liveness进程是否存活Liveness Probe如果 Liveness Probe 失败k8s 会杀死 Pod 重建。Readiness 失败只是暂时不路由流量。坑3Liveness Probe 设置太激进。选举期间 Nacos 可能短暂不响应不要因为一两次失败就 kill 容器。对外暴露集群内外双通道k8s 集群外k8s 集群内直连通过 NodePort/LoadBalancer业务 PodNacos Headless Service域名nacos-headless.nacosnacos-0nacos-1nacos-2集群外客户端Nacos 对公 Service# service-for-external.yaml# 给集群外客户端和控制台访问apiVersion:v1kind:Servicemetadata:name:nacos-externalnamespace:nacosspec:type:NodePort# 或 LoadBalancerselector:app:nacosports:-name:httpport:8848targetPort:8848nodePort:30848# 对外暴露的端口两套 ServiceHeadless 给集群内 Pod 直连固定 DNSNodePort/LoadBalancer 给集群外客户端和控制台访问。ConfigMap 统一管理配置# configmap.yamlapiVersion:v1kind:ConfigMapmetadata:name:nacos-confignamespace:nacosdata:application.properties:|spring.sql.init.platformmysqldb.num1 db.url.0jdbc:mysql://mysql.nacos.svc.cluster.local:3306/nacos_config?useSSLfalseserverTimezoneAsia/Shanghainacos.core.auth.enabledtrue nacos.core.auth.server.identity.keynacos nacos.core.auth.server.identity.valuenacos通过volumeMounts挂入 PodvolumeMounts:-name:nacos-confmountPath:/home/nacos/conf/application.propertiessubPath:application.propertiesvolumes:-name:nacos-confconfigMap:name:nacos-configHelm 一键部署懒人版# 添加 Nacos Helm 仓库helm repoaddnacos https://nacos-group.github.io/nacos-helm helm repo update# 一键安装helminstallnacos nacos/nacos\--namespacenacos\--create-namespace\--setglobal.modecluster\--setreplicaCount3\--setmysql.enabledtrue\--setmysql.mysqlUsernacos\--setmysql.mysqlPasswordNacos2024# 验证kubectl get pods-nnacos-w# nacos-0 nacos-1 nacos-2 Running常见 k8s 部署问题速查现象原因解决Pod 反复 CrashLoopBackOffLiveness Probe 太激进initialDelaySeconds设 120s集群成员列表只看到自己NACOS_SERVERS写的是 Pod IP 不是 DNS改用 Headless Service DNS 名注册的服务跨 Pod 查不到未共享 MySQL各 Pod 用内置 Derby配置共享 MySQL启动后 Pod 被 Service 路由但仍 503Readiness Probe 还没探活成功耐心等 30~60s不要过早请求podAntiAffinity导致 Pending节点数少于 Pod 数改为preferredDuringScheduling总结Nacos 上 k8s 的五个核心决策StatefulSet 不是 Deployment需要固定 Pod 名 DNS 做集群发现。Headless Service 不是普通 ServiceclusterIP: None给每个 Pod 独立 DNS。cluster.conf 用 DNS 名不是 IPnacos-0.nacos-headless.nacos.svc.cluster.local:9849。Probe 要宽松initialDelaySeconds给 60~120 秒选举期间容忍失败。MySQL 是必须的不能指望 Pod 本地的 Derby 来做集群数据同步。从 Deployment 踩坑到 StatefulSet Headless Service 组合其实就改了三处kind: StatefulSetserviceName绑定 NACOS_SERVERS换 DNS。但每一处都踩过坑才知道。你们 Nacos 跑在什么环境评论区留个数字1传统虚拟机部署 2裸 Docker 容器 3k8s StatefulSet 4Nacos 托管服务MSE/PolarisMesh 等。顺带说一句你觉得 Nacos 上 k8s 最大的坑是什么。