You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何让Deployment仅向单个Pod导流并实现故障自动切换?

实现单主Pod+备用Pod的流量切换方案

要实现3个Pod中仅一个接收流量、故障后自动切换的需求,有几种实用的落地方案,以下是最易实现的两种:

方案一:基于标签选择器的动态主Pod切换

核心思路是让ClusterIP Service仅指向带role: primary标签的Pod,通过监控脚本自动检测主Pod状态,故障时将备用Pod(带role: standby标签)升级为主Pod。

1. 部署基础资源

创建Deployment(初始3个备用Pod)

apiVersion: apps/v1
kind: Deployment
metadata:
  name: app-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
        role: standby
    spec:
      containers:
      - name: my-app-container
        image: your-app-image:latest
        ports:
        - containerPort: 8080

创建ClusterIP Service(仅路由主Pod)

apiVersion: v1
kind: Service
metadata:
  name: app-service
spec:
  type: ClusterIP
  selector:
    app: my-app
    role: primary
  ports:
  - port: 80
    targetPort: 8080

2. 初始化主Pod

Deployment创建完成后,手动将第一个就绪的备用Pod标记为主Pod:

kubectl label pod $(kubectl get pods -l app=my-app,role=standby -o jsonpath='{.items[?(@.status.ready==true)][0].metadata.name}') role=primary --overwrite

3. 部署主Pod监控脚本

用CronJob定期检查主Pod状态,故障时自动切换:

先创建RBAC权限(让脚本能修改Pod标签)

apiVersion: v1
kind: ServiceAccount
metadata:
  name: pod-label-manager
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  name: pod-label-manager
rules:
- apiGroups: [""]
  resources: ["pods"]
  verbs: ["get", "list", "patch"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
  name: pod-label-manager-binding
subjects:
- kind: ServiceAccount
  name: pod-label-manager
  namespace: default
roleRef:
  kind: ClusterRole
  name: pod-label-manager
  apiGroup: rbac.authorization.k8s.io

创建CronJob执行监控逻辑

apiVersion: batch/v1
kind: CronJob
metadata:
  name: primary-pod-monitor
spec:
  schedule: "*/1 * * * *"  # 每分钟执行一次
  jobTemplate:
    spec:
      template:
        spec:
          serviceAccountName: pod-label-manager
          containers:
          - name: monitor
            image: bitnami/kubectl:latest
            command: ["bash", "-c"]
            args:
            - |
              # 获取当前就绪的主Pod
              PRIMARY_POD=$(kubectl get pods -l app=my-app,role=primary -o jsonpath='{.items[?(@.status.ready==true)][0].metadata.name}')
              
              if [ -z "$PRIMARY_POD" ]; then
                # 无可用主Pod,选第一个就绪的备用Pod升级
                STANDBY_POD=$(kubectl get pods -l app=my-app,role=standby -o jsonpath='{.items[?(@.status.ready==true)][0].metadata.name}')
                if [ ! -z "$STANDBY_POD" ]; then
                  kubectl label pod $STANDBY_POD role=primary --overwrite
                  echo "Promoted $STANDBY_POD to primary"
                fi
              else
                # 检查主Pod是否仍处于运行状态
                POD_PHASE=$(kubectl get pod $PRIMARY_POD -o jsonpath='{.status.phase}')
                if [ "$POD_PHASE" != "Running" ]; then
                  # 主Pod故障,降级为备用并升级新主Pod
                  kubectl label pod $PRIMARY_POD role=standby --overwrite
                  STANDBY_POD=$(kubectl get pods -l app=my-app,role=standby -o jsonpath='{.items[?(@.status.ready==true)][0].metadata.name}')
                  if [ ! -z "$STANDBY_POD" ]; then
                    kubectl label pod $STANDBY_POD role=primary --overwrite
                    echo "Promoted $STANDBY_POD to primary, demoted $PRIMARY_POD to standby"
                  fi
                fi
              fi
          restartPolicy: OnFailure

方案二:基于StatefulSet的固定标识切换(适合有状态应用)

如果你的应用是有状态的(需要稳定存储/网络标识),可以用StatefulSet实现:

1. 创建StatefulSet

apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: app-statefulset
spec:
  serviceName: app-headless
  replicas: 3
  selector:
    matchLabels:
      app: my-app
  template:
    metadata:
      labels:
        app: my-app
    spec:
      containers:
      - name: my-app-container
        image: your-app-image:latest
        ports:
        - containerPort: 8080
      # 如需持久化存储,添加volumeClaimTemplates字段

2. 创建ClusterIP Service(初始指向第一个Pod)

apiVersion: v1
kind: Service
metadata:
  name: app-service
spec:
  type: ClusterIP
  selector:
    app: my-app
    statefulset.kubernetes.io/pod-name: app-statefulset-0
  ports:
  - port: 80
    targetPort: 8080

3. 监控切换脚本

逻辑和方案一类似,检测app-statefulset-0的状态,故障时修改Service的选择器为app-statefulset-1或app-statefulset-2,恢复后可按需切回。

注意事项

  • 脚本优先选择就绪状态的备用Pod,避免路由到未就绪的实例
  • 若需更高可靠性,可给监控脚本添加分布式锁(比如用ConfigMap实现),防止多实例同时切换导致冲突
  • 有状态应用需提前做好数据同步,确保备用Pod能无缝接管主Pod的业务

内容的提问来源于stack exchange,提问作者Raz Buchnik

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.10 13:55:18