基于服务的就绪探针场景下StatefulSet集群Pod间DNS解析与配置同步的解决方案咨询
你的问题核心是陷入了一个死循环:Pod需要互相解析DNS来完成同步启动,但就绪探针未通过时Service不会注册端点,导致DNS解析失败,进而无法完成同步。下面是几个针对性的解决方案,结合你的场景来调整:
方案1:分离DNS解析用的Headless Service和流量控制用的普通Service
StatefulSet的serviceName字段对应的**Headless Service(ClusterIP: None)**默认会在Pod创建后立即注册端点,不管Pod的就绪状态——这正是我们需要的Pod间DNS解析能力。而你需要的“阻止外部流量”可以用另一个普通Service来实现,它只在Pod就绪后才关联端点。
步骤1:创建Headless Service用于DNS解析
为你的两个StatefulSet分别创建Headless Service:
# app1-headless.yaml apiVersion: v1 kind: Service metadata: name: app1cluster namespace: app spec: clusterIP: None selector: cluster: appcluster ports: - port: 8080 name: appport
# app2-headless.yaml apiVersion: v1 kind: Service metadata: name: app2cluster namespace: app spec: clusterIP: None selector: cluster: appcluster ports: - port: 8080 name: appport
这两个Headless Service会在Pod创建后立即把它们的IP加入DNS记录,这样app1-0.app1cluster.app.svc.cluster.local和app2-0.app2cluster.app.svc.cluster.local就能被互相解析到。
步骤2:创建普通Service用于外部流量控制
再创建一个普通Service,它会依赖就绪探针的状态,只有当Pod就绪后才允许外部流量访问:
# app-external.yaml apiVersion: v1 kind: Service metadata: name: app-external namespace: app spec: selector: cluster: appcluster ports: - port: 8080 targetPort: appport
这个Service的端点只会在Pod的就绪探针通过后才被添加,完美实现你“阻止外部流量”的需求。
步骤3:修改Pod内的同步配置
在你的Pod环境变量里,把applist的值改成Headless Service的FQDN:比如app1的applist改成app2-0.app2cluster.app.svc.cluster.local,app2的改成app1-0.app1cluster.app.svc.cluster.local,这样Pod启动后就能立即解析到对方IP,完成同步,之后就绪探针通过,外部Service开始转发流量。
方案2:调整就绪探针逻辑,改为同步完成后的自定义检查
如果不想额外创建Service,你可以修改就绪探针,从单纯检查端口改为检查同步是否完成。比如写一个脚本,当Pod成功和对方建立同步连接后,脚本返回0,否则返回1。
修改就绪探针配置:
readinessProbe: exec: command: - /bin/sh - -c - "curl -s http://app2-0.app2cluster.app.svc.cluster.local:8080/health || exit 1" initialDelaySeconds: 10 periodSeconds: 5 failureThreshold: 30
这里的/health假设是你的应用提供的健康检查接口,只有当同步完成后才返回200。这样,Pod启动后可以先通过Headless Service解析到对方IP,完成同步,之后就绪探针通过,Service关联端点。
为什么之前的方案不行?
你之前的StatefulSet指定了serviceName,但如果对应的Service不是Headless类型,那么它的端点只会在Pod就绪后才被添加,导致DNS解析失败。而Headless Service的特性就是忽略就绪状态,只要Pod存在就注册端点,刚好解决Pod间的DNS解析需求,同时用普通Service来控制外部流量,完美分离两个需求。
现在测试的话,创建Headless Service后,再启动StatefulSet,你会发现Pod刚启动就能解析到对方的IP:
kubectl exec -i -t app1-0 -n app -- nslookup app2-0.app2cluster.app.svc.cluster.local
应该能正常返回IP,之后Pod完成同步,就绪探针通过,外部Service开始工作。
内容的提问来源于stack exchange,提问作者drifter

