如何利用 Kubernetes 實現應用零宕機


我在本地和託管 Kubernetes 集羣方面工作了七年多。我能說的是,容器已經徹底改變了託管格局!它帶來了許多需要複雜設置的設施。擁有多個實例,具有滾動重啓、零停機、健康檢查等功能。以前真是費時費力(實現 VRRP 解決方案、使用 monit 之類的應用程序監控重啓、負載均衡 haproxy 之類的)!

因此,現在使用 Kubernetes 可以更輕鬆地訪問一切,但如果您想爲應用程序的生命週期構建完美的設置,您仍然必須瞭解它的工作原理以及根據您的情況應遵循哪種策略。
在本文中,我將解釋爲什麼以及如何使用 Kubernetes 實現零停機應用程序。

容器鏡像位置

如果您已經使用 Docker 一段時間,那麼這看起來很簡單。拉取和使用容器鏡像非常簡單。但是,在生產環境中,如果您不是映像所有者,您通常不想依賴遠程且不受控制的映像註冊表。爲什麼?

  1. 註冊表可能會消失,並且您無法再拉取鏡像( Kubernetes 上出現 ImagePullBackOff 錯誤)

  2. 您正在使用的圖像標籤已被刪除(相同的 ImagePullBackOff 錯誤)

  3. 圖像標籤沒有改變,但圖像內容不再相同(非不可變圖像,因此圖像哈希值不同)。集羣的不同節點上的圖像之間的行爲不相同(取決於標籤何時更改並在集羣節點上拉取)

  4. 它不符合您要求控制這些圖像的安全要求(SOC2、HIPPA…)。

存在多種解決方案。一種是將容器映像從源註冊表同步到您自己的註冊表

Pod 數量(應用程序實例)

這聽起來很明顯,但如果您正在尋求高可用性,則您的應用程序至少需要 2 個 Kubernetes 副本(2 個 Pod)。例子:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: nginx
spec:
  replicas: 2 # tells deployment to run 2 pods matching the template
  template:
  ..

我多次聽到的關於 Kubernetes 的一個常見錯誤是:“我不需要兩個實例,因爲 Kubernetes 執行滾動更新,因此它將在關閉當前實例之前啓動一個新實例”。確實如此,但它僅適用於部署更新
以下是不適用此規則的其他場景:

這就是爲什麼設置兩個實例是避免停機的最低要求(另請參閱 Pod 反關聯性部分)。

Pod 中斷預算

PodDisruptionBudget (PDB) 是一個 Kubernetes 對象,它指定在部署、維護或任何給定時間不可用的 Pod 數量。這有助於確保您的應用程序保持可用,即使某些 pod 被終止或驅逐也是如此。
讓我們舉一個例子,我的應用程序有三個 pod(實例);我總是希望始終擁有至少兩個 running;我可以應用一個 PDB 對象,這將保證我始終有至少兩個正在運行的 pod!

apiVersion: policy/v1
kind: PodDisruptionBudget
metadata:
  name: my-pdb
spec:
  maxUnavailable: 1
  selector:
    matchLabels:
      app: my-app

部署策略

Kubernetes 部署有兩種策略:
RollingUpdate:默認更新,部署順利。重新創建:在啓動較新版本的應用程序之前強制應用程序完全關閉。




默認情況下,應用 RollingUpdate 策略。但是您可以使用其他選項(例如最大不可用百分比和最大激增)來調整部署的方式。當您面臨繁重的流量負載並且想要控制部署速度以最大程度地減少性能影響時,這些選項非常有用。

自動回滾部署

不幸的是,自動回滾並不是 Kubernetes 默認提供的功能。一般來說,您必須使用 Helm、ArgoCD、Spinnaker 等第三方工具才能實現自動回滾。
大多數人想要的很簡單:如果我的應用程序無法正常啓動,不要向其發送流量並回滾。
例如,對於 Helm,使用 Helm 實現它的一些選項很有趣:

爲了獲得運行良好的解決方案,必須設置並正確配置探針(請參閱下一節)。如果 pod 沒有通過其活性探針正常啓動,則會自動回滾。

Probe 探針

不幸的是,探針經常被低估,但它們對於實現零停機非常重要!
驗證應用程序健康狀況的兩個最重要的探測器是 “Liveness” 和“Readiness”探測器。比長篇大論更好的是,這裏有一個解釋目標的模式:

Kubernetes 探針工作流程
Liveness 探針可確保您的應用程序處於活動狀態,並將決定 pod 是存活還是死亡!
如果活性探測未成功:

  1. Pod 停止接收流量

  2. Pod 重新啓動,嘗試恢復健康狀態。任何進一步的重新啓動都會應用指數退避(指數延遲)

Readiness 探針決定是否將流量發送到您的 Pod。

在什麼情況下配置自定義活躍度和就緒度探測器有用?
答案是 “永遠”!當然,您可以使用簡單的 TCP 檢查,但它永遠不會像您自己在應用程序中構建的自定義探針(例如,REST API 上的專用端點)那樣可靠。

初始啓動時間延遲

初始啓動時間可能需要延遲。它可能發生在不同的情況下:

但這是可能發生片狀啓動的示例。如果您遇到這種情況或想要預見它,您應該像這樣更新 initialDelaySeconds :

livenessProbe:
  initialDelaySeconds: 60
  httpGet:
  ...

注意:存在專用啓動探測器,但在大多數情況下可能沒有用。一般來說,initialDelaySeconds 選項就足夠了。

優雅終止期 GrancePeriodSeconds

這個 Kubernetes 選項並不直接與零停機功能相關,而是更多地涉及忽略應用程序正常關閉的重要性的缺點效應。
僅當應用程序能夠攔截 SIGTERM 時,優雅終止期才能起作用!如果應用程序未編碼爲攔截 SIGTERM,則它只會硬終止應用程序,無論是否存在大於 30 秒的優雅終止期,這都可能導致數據丟失。
不管理 SIGTERM 可能會帶來幾個問題:

還存在其他原因,但您會看到讓應用程序足夠快地關閉是多麼重要。
ℹ️ 硬件故障總是有可能的,因此您的應用程序應該始終能夠在此類故障後恢復。然而,類似的常規故障不應頻繁發生。
多給你一點時間讓你的應用程序正常停止通常是很好的做法(<5 分鐘)。Kubernetes 默認值爲 30 秒,但您可以使用終止 GracePeriodSeconds 選項進行調整。

Pod 反親和力

Pod 反關聯性可讓您避免同一節點上存在同一應用程序 (Pod) 的多個實例。當所有實例都位於同一節點上時發生節點崩潰時,您可以想象會發生停機。
爲了避免這種情況,您可以要求 Kubernetes 避免所有 pod 都位於同一節點上。存在兩個版本:

  1. 軟反親和性 Soft Anti-Affinity

  2. PreferredDuringSchedulingIgnoredDuringExecution:它將盡最大努力避免它,但如果它不能(缺乏資源),它將在同一節點上添加兩個實例。這個版本具有成本效益,並且在 95% 的情況下都能發揮作用。

  3. Hard Anti-Affinity

  4. requiredDuringSchedulingIgnoredDuringExecution:這將是一個硬性要求,不能在同一節點上有兩個 pod。但如果您要求同一應用程序有 50 個 pod,則需要 50 個節點。這很快就會變得非常昂貴。

這是它在 Kubernetes 上的樣子:

affinity:
    podAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
      - labelSelector:
          matchExpressions:
          - key: security
            operator: In
            values:
            - S1
        topologyKey: topology.kubernetes.io/zone
    podAntiAffinity:
      preferredDuringSchedulingIgnoredDuringExecution:
      - weight: 100
        podAffinityTerm:
          labelSelector:
            matchExpressions:
            - key: security
              operator: In
              values:
              - S2
          topologyKey: topology.kubernetes.io/zone

資源

資源是最常見的問題之一。當設置的資源不足時,您的應用程序可以:

自動縮放 Autoscaling

自動縮放是避免流量負載下停機的好方法。默認基於 CPU(可以使用其他自定義指標)。這是自動部署更多實例(Pod)的簡單方法。
⚠️ 自動縮放並不是魔法!您必須在 Kubernetes 上正確配置您的應用程序。
因此,例如,當您的 pod 短時間內運行超過 60% 的 CPU 時,Kubernetes 會觸發一個新的 pod 來處理負載並減少當前正在運行的應用程序的使用率。
以下是 Kubernetes 上的示例:

apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
spec:
...
  minReplicas: 1
  maxReplicas: 10
  metrics:
  - type: Resource
    resource:
      name: cpu
      target:
        type: Utilization
        averageUtilization: 50

結論

Kubernetes 確實有神奇的作用,但只有當應用程序儘可能是雲原生且配置正確時,它才能發揮神奇作用。
總之,當您想將應用程序引入 Kubernetes 時,您至少應該注意:

如果一切設置正確,Kubernetes 體驗將令人難以置信,您將不會再遭受任何停機。

原文鏈接

https://blog.devops.dev/how-to-achieve-zero-downtime-application-with-kubernetes-ba52fdea9a9b

本文由 Readfog 進行 AMP 轉碼,版權歸原作者所有。
來源https://mp.weixin.qq.com/s/mtGtxPK3vfabG9nI6oGY2g