利用 K8S 的反親和性構建高可用應用

大星說爬蟲發表於2024-02-28

K8S 支援多副本部署,但不代表應用的高可用,因為多個副本可能部署到同一個節點上。

早上發現應用的某一個功能有一半的請求失敗,排查之後發現,原來 容器服務中節點未設定反親和性,導致 Pod 部署到同一個節點中,影響 API 閘道器請求後端服務。

架構圖

先 review 以下架構圖

利用 K8S 的反親和性構建高可用應用
  • Web 應用:Vue 框架,執行在 上
  • 業務 API:Golang 框架,執行在 容器服務上,使用 NodePort 方式對外暴露服務

1. 問題

在頁面中使用頁面功能時,發現有一半的請求失敗,API 返回為空。

於是想到可能和 API 閘道器請求後端介面有關,下圖為 API 閘道器對應後端通道的配置,有 2 個節點。

利用 K8S 的反親和性構建高可用應用

檢視容器服務對應 Pod,發現兩個副本都執行在同一個節點上,問題找到了。

利用 K8S 的反親和性構建高可用應用

副本跑在同一個節點的原因:隨著叢集的變化,一開始部署在兩個節點上的 Pod, 因為其中一個節點的資源被佔滿, 導致 Pod 優先排程到另一個閒置的節點上。

2. 解決問題:設定反親和性

解決問題的思路是讓 Pod 不能排程在同一臺 伺服器上,需要打散排程到所有節點中。

ChatGPT 助手的 QA 詳見附錄,也可以檢視文字的幫助文件(是透過關鍵字 Anti-Affinity 檢索到的 )

利用 K8S 的反親和性構建高可用應用

容器服務雖然有 排程策略 功能,但無法滿足當前的場景, 於是編輯 Deployment 的 YAML 配置,在 Pod 上新增 spec.template.spec.topologySpreadConstraints segment。

      topologySpreadConstraints:
      - labelSelector:
          matchLabels:
            k8s-app: XXX            qcloud-app: XXX        maxSkew: 1
        topologyKey: kubernetes.io/hostname        whenUnsatisfiable: ScheduleAnyway
複製

解讀: maxSkew 設定為 1 表示允許的最大偏差為 1,即任一節點上的 Pod 數量不會比其他節點多 1 個以上。 topologyKey"kubernetes.io/hostname",意味著在不同的節點上分佈 Pods。

部署後,Pod 分佈到多個節點上,問題解決。

利用 K8S 的反親和性構建高可用應用

3. 事後思考

  • 開啟 API 閘道器的健康檢查,當 API 閘道器探測節點失效時從後端通道中剔除
  • 瞭解 K8S 資源排程的基本概念

附錄:ChatGPT 助手

Q: TKE 如何設定讓 Deployment 的 2 個 Pod 分配到兩個節點上,目前 兩個 Pod 分配到同一個 節點中。

A(ChatGPT-4-turbo): TKE(Tencent Kubernetes Engine)是騰訊雲提供的託管 Kubernetes 服務。在 Kubernetes 中,如果希望讓 Deployment 的 Pods 分佈在不同的節點上,可以使用幾種策略,主要包括:

1. 親和性(Affinity)和反親和性(Anti-Affinity)規則

使用 Pod 反親和性規則可以指定 Kubernetes 排程器不要將屬於同一 Deployment 的 Pods 排程到同一節點上。

例如,以下是一個 Deployment 配置的示例,它使用了 Pod 反親和性來確保 Pods 分散到不同的節點上:

apiVersion: apps/v1kind: Deploymentmetadata:
  name: my-deploymentspec:
  replicas: 2
  selector:
    matchLabels:
      app: myapp  template:
    metadata:
      labels:
        app: myapp    spec:
      containers:
      - name: myapp-container        image: myapp:1.0
      affinity:
        podAntiAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: "app"
                operator: In                values:
                - myapp            topologyKey: "kubernetes.io/hostname"
複製

在這個例子中, requiredDuringSchedulingIgnoredDuringExecution 確保排程器在排程時遵循這些規則,而 topologyKey 設定為 "kubernetes.io/hostname" 表示 Pods 不能在擁有相同主機名的節點上執行。

2. 使用 Pod Topology Spread Constraints

Pod Topology Spread Constraints 允許你更細粒度地控制 Pods 的分佈,這可以透過設定 maxSkewtopologyKeywhenUnsatisfiable 等引數來實現。

以下是一個使用 Pod Topology Spread Constraints 的 Deployment 示例:

apiVersion: apps/v1kind: Deploymentmetadata:
  name: my-deploymentspec:
  replicas: 2
  selector:
    matchLabels:
      app: myapp  template:
    metadata:
      labels:
        app: myapp    spec:
      containers:
      - name: myapp-container        image: myapp:1.0
      topologySpreadConstraints:
      - maxSkew: 1
        topologyKey: "kubernetes.io/hostname"
        whenUnsatisfiable: "ScheduleAnyway"
        labelSelector:
          matchLabels:
            app: myapp
複製

在這個配置中, maxSkew 設定為 1 表示允許的最大偏差為 1,即任一節點上的 Pod 數量不會比其他節點多 1 個以上。 topologyKey 同樣設定為 "kubernetes.io/hostname",意味著在不同的節點上分佈 Pods。

確保你的 Kubernetes 叢集有足夠的不同節點來支援這些分佈策略。如果叢集中只有一個可用節點,或者其他節點因為資源限制(如 CPU、記憶體不足)無法排程 Pods,那麼這些策略可能不會有效。


來自 “ ITPUB部落格 ” ,連結:https://blog.itpub.net/70030722/viewspace-3007532/,如需轉載,請註明出處,否則將追究法律責任。

相關文章