Kubernetes Services是否有故障转移功能?主备数据库流量切换方案咨询
当然有,但得看具体的Service类型和配置细节。
Kubernetes的Service默认就自带基础的故障转移能力:当后端的Pod出现故障(比如Pod崩溃、就绪探针检测失败)时,kube-proxy会自动把这个Pod从Service的端点列表中移除,后续流量就不会再转发到这个故障Pod上了。
不过要注意几个关键点:
- 这个故障转移是基于Pod的就绪探针状态的——只有当Pod的就绪探针返回失败时,Service才会将其剔除出流量池。如果你的应用内部出了问题但没被就绪探针检测到,Service还是会继续把流量发过去。
- 普通的ClusterIP/NodePort Service默认是轮询负载均衡,故障转移只是把故障Pod从负载池里拿掉,剩下的正常Pod承接流量。但它不会做「优先主节点、主节点挂了才切从节点」这种带优先级的切换——这种场景需要额外的配置或者工具。
你的场景很典型:用StatefulSet部署主从数据库,Headless Service用来做Pod的DNS解析,现在要实现访问database-service.default.svc.cluster.local时优先走主库D-1,D-1挂了自动切到D-2,而且不能在客户端加逻辑,得在K8s层面搞定。
首先得明确:Headless Service本身不会做负载均衡或者流量切换,它只是返回所有后端Pod的DNS记录。所以要实现你要的优先级切换,核心思路是让Service只在主库正常时指向主库,主库故障时自动指向从库,具体可以通过「动态就绪探针+普通ClusterIP Service」的组合来实现,步骤如下:
第一步:给StatefulSet的Pod配置动态就绪探针
我们需要让主库D-1的就绪探针始终返回成功,而从库D-2的就绪探针只有在主库不可用时才返回成功。这样当主库正常时,只有D-1会被加入到Service的端点列表;主库挂了,D-2的就绪探针变成成功,就会被Service纳入流量池,实现自动切换。
以MySQL为例,你可以给每个DB Pod写一个就绪探针脚本,逻辑如下:
- 先判断当前Pod是不是主库(比如执行
SELECT @@read_only,主库返回0,从库返回1); - 如果是主库,直接返回成功;
- 如果是从库,检查主库(通过Headless Service的DNS:
D-1.database-service-headless.default.svc.cluster.local)是否可达、是否还是主库;如果主库不可用,从库返回成功,否则返回失败。
示例的就绪探针配置(放到StatefulSet的Pod模板里):
readinessProbe: exec: command: - sh - -c - | # 用环境变量传递数据库密码,避免硬编码 IS_MASTER=$(mysql -u root -p"${MYSQL_ROOT_PASSWORD}" -e "SELECT @@read_only" -sN) # 当前是主库,直接就绪 if [ "$IS_MASTER" = "0" ]; then exit 0 fi # 检查主库是否可达(用数据库连接测试更准确) mysql -u root -p"${MYSQL_ROOT_PASSWORD}" -h D-1.database-service-headless.default.svc.cluster.local -e "SELECT 1" > /dev/null 2>&1 if [ $? -ne 0 ]; then # 主库连不上,从库就绪 exit 0 else # 主库正常,从库不就绪 exit 1 fi initialDelaySeconds: 30 periodSeconds: 5 failureThreshold: 2
这里的database-service-headless是你原来的Headless Service名称,用来直接解析到D-1 Pod的IP。
第二步:创建普通ClusterIP Service作为流量入口
不要直接用Headless Service做外部访问入口,而是创建一个普通的ClusterIP Service,标签选择器和你的StatefulSet的Pod标签一致:
apiVersion: v1 kind: Service metadata: name: database-service namespace: default spec: type: ClusterIP selector: app: my-db # 替换成你的StatefulSet的Pod标签 ports: - port: 3306 targetPort: 3306
这样,当D-1正常时,它的就绪探针成功,会被加入这个Service的端点列表,所有访问database-service.default.svc.cluster.local的流量都会打到D-1;当D-1故障(Pod崩溃或者就绪探针失败),kube-proxy会把它从端点列表移除,此时D-2的就绪探针检测到主库不可用,返回成功,就会被加入端点列表,流量自动切换到D-2。
可选优化:用Operator实现更可靠的切换
如果是生产环境,我更推荐用数据库Operator(比如MySQL Operator、PostgreSQL Operator)来管理主从集群。这些Operator会自动处理主从切换、更新Service端点,不需要你自己写就绪探针脚本,逻辑更健壮,还能处理比如主库恢复后的回切、从库晋升等复杂场景。
内容的提问来源于stack exchange,提问作者akuscu




