設計雲原生應用程式的15條基本原則

語言: CN / TW / HK

設計可擴充套件的雲原生應用程式需要深思熟慮,即便擁有大量雲來部署我們的應用程式,目前仍有許多挑戰需要克服。以複雜而臭名昭著的分散式計算仍然是真實的。同時網路的不穩定也會導致速度變慢和意外錯誤。因為雲原生應用程式通常是微服務,因此必須專門設計和部署以克服這些挑戰。

在本文中,我將介紹如何設計雲原生應用程式並將其部署在 Kubernetes 上的15條基本原則。

原則1:單個 Pod 幾乎是不可用的

因為 Kubernetes 可以在必要時自行決定終止 Pod,所以你需要一個控制器來建立你的 Pod。除了一次性除錯之外,儘量少使用單個 Pod。

副本集也幾乎不是你想直接使用的東西。

相反,你應該有一個 Deployment 或 StatefulSet 建立 Pod。無論你是否打算執行多個例項,這都適用。你希望實現自動化的原因是 Kubernetes 不保證 Pod 的持續生命週期,所以需要同時執行多個例項,以防萬一其中的容器發生故障。

原則2:明確區分有狀態和無狀態元件

Kubernetes 定義了許多不同的資源和管理它們的控制器。每個都有自己的語義。我看到了關於 Deployment、StatefulSet 和 DaemonSet 是什麼以及它們能做什麼或不能做什麼的困惑。用對了意味著你清楚地表達了你的意圖,Kubernetes 可以幫助你實現目標。

如果使用得當,Kubernetes 會強制你這樣做,但存在許多複雜的解決方案。簡單的經驗法則是讓所有有狀態的東西都在 StatefulSet 中,而在 Deployments 中是無狀態的,因為這樣做是 Kubernetes 的方式。使用時還請仔細閱讀官方文件。

原則3:將祕密與非祕密配置分開,以明確使用以保證安全

ConfigMap 和 Secret 之間幾乎沒有技術差異 。既包括它們在 Kubernetes 內部的表示方式,也包括它們的使用方式。例如,應用程式配置儲存在 ConfigMap 中,然後帶有憑據的資料庫連線字串屬於Secret。

原則4:啟用自動擴容選項

就像所有 Pod 實際上都由 Deployment 管理並以 Service 為前端一樣,你還應該始終考慮為你的 Deployment 使用Horizontal Pod Autoscaler (HPA)。

從來沒有人願意在他們的服務在生產環境中耗盡容量。同樣,沒有人希望終端使用者因為 Pod 的容量分配不佳而受苦。從一開始就為此做好準備意味著你將被迫進入縮放可以並且將會發生的心態。這比容量用完要好得多。

根據一般的可擴充套件性設計原則,你應該已經準備好執行每個應用程式元件的多個例項。這對於可用性和可擴充套件性至關重要。

請注意,你也可以使用 HPA 自動擴充套件 StatefulSet。然而,有狀態的元件通常應該只在絕對需要時才進行擴充套件。

例如,擴充套件資料庫可能會導致大量資料複製和額外的事務管理髮生,如果資料庫已經處於高負載狀態,這會產生不可控制的問題。此外,如果你確實自動縮放有狀態元件,請考慮禁用自動縮減。特別是,如果有狀態元件需要以某種方式與其他例項同步。相反,手動觸發此類操作更安全。

原則5:通過與容器生命週期管理掛鉤來增強和啟用自動化

一個容器可以定義一個 PostStart 和 PreStop 鉤子,這兩個鉤子都可以用來執行重要的工作,以通知應用程式的其他元件一個例項的新啟動或其即將終止。PreStop 函式將在終止之前呼叫,並且有一個(可配置的)時間來完成。使用它來確保即將終止的例項完成其工作,將檔案提交到持久卷,或者為了有序和自動關閉而需要發生的任何其他事情。

原則6:正確使用探針來檢測故障並自動從故障中恢復

與單程序系統相比,分散式系統將以越來越不直觀的方式失敗。網路是一大類新的故障原因。我們越能檢測到故障,我們就越有機會從故障中自動恢復。

為此,Kubernetes 為我們提供了探測能力。特別是就緒探測非常有用,因為失敗會向 Kubernetes 發出訊號,表明你的容器(以及 Pod)還沒有準備好接受請求。

儘管有明確的文件,但活性探針經常被誤解。失敗的活性探測表明元件永久卡在需要強制重啟才能解決的不良情況。

啟動探針被新增到 Kubernetes 以指示何時開始使用其他探針進行探測。因此,這是一種將它們推遲到執行它們開始有意義的方法。

原則7:讓有故障元件快速暴露出來

應用程式元件發生嚴重故障(崩潰)、快速故障(一旦出現問題)和大聲故障(在其日誌中包含資訊豐富的錯誤訊息)。這樣做可以防止資料在你的應用程式中陷入奇怪的狀態,只會將流量路由到健康的例項,並且還會提供根本原因分析所需的所有資訊。本文中的所有自動化和其他原則將幫助你在找到根本原因的同時保持你的應用程式處於良好狀態。

無論是在你的元件中,還是在叢集本身中。失敗是不可避免的,應用程式中的元件必須能夠自動處理失敗或重啟。

原則8:保證可觀測性

監控、日誌記錄和鏈路跟蹤是可觀察性的三大支柱。只需將自定義指標提供給你的監控系統,編寫結構化日誌(例如 JSON 格式),而不是故意刪除 HTTP 標頭(例如帶有相關 ID 的標頭),而是將它們作為記錄內容的一部分,將為你的應用程式提供可觀察的所有內容。

如果你需要更詳細的跟蹤資訊,請將你的應用程式與 Open Telemetry API 整合。但是前面的步驟使你的應用程式易於觀察,無論是人工操作員還是自動化。基於對你的應用程式有意義的指標進行自動縮放幾乎總是比基於 CPU 使用率等原始指標更好。

SRE 的 “四個黃金訊號” 是延遲、流量、錯誤和飽和度。從經驗上看,使用特定於應用程式的指標跟蹤這些監控訊號比使用通用基礎資源獲得的原始指標要有用得多。

原則9:適當限制 Pod 資源請求

通過適當地設定Pod資源請求和限制,Horizontal Pod Autoscaler 和 Cluster Autoscaler 都可以做得更好。如果他們知道需要多少容量和可用容量,則確定你的 Pod 和整個叢集需要多少容量的工作會容易的多。

不要將你的請求和限制設定得太低!一開始這可能很誘人,因為它允許叢集執行更多的 Pod。但除非請求和限制設定相同(為 Pod 提供 “有保證的” QoS 類),否則你的 Pod 在正常(常規流量)操作期間可能會獲得更多資源。看起來一切都很好地工作。但在高峰期,它們的QPS將被限制在你指定的數量。而擴大規模實際上意味著每個部署的 Pod 佔用更多的資源,但是整體效能可能會更差。

原則10:預留容量並優先考慮 Pod 優先順序

在容量管理方面,名稱空間資源配額、節點上預留的計算資源以及適當設定 Pod 優先順序 有助於確保叢集容量和穩定性不受影響。

避免叢集負載過高,以至於網路外掛的 Pod 被驅逐。

原則11:根據需要強制合併或分散 Pod

Pod傳播約束以及親和性和反親和性規則可以做到將 Pod 放在一起(以提高網路流量效率)或將它們分散(以實現冗餘)跨多雲區域保證可用性的好方法。

原則12:在可能導致停機的計劃操作期間確保 Pod 可用性

Pod Disruption Budget 指定一次允許多少個 Pod 集合(例如在 Deployment 中)被 自願中斷(即由於你的命令,而不是故障)。儘管管理員標記了部分不可用叢集節點,這有助於確保高可用性。例如,在叢集升級期間會發生這種情況,並且通常每月發生一次,因為 Kubernetes 更新速度很快。

請注意,如果你錯誤地設定 Pod 中斷預算,你可能會限制管理員進行叢集升級的能力。這會干擾自動作業系統修補並危及環境的安全狀況。

PDB 會限制因自願中斷而同時停機的複製應用程式的 Pod 數量。

原則13:選擇藍/綠或金絲雀部署而不是停機部署

在這個時代,為了升級維護而關閉整個應用程式是不可接受的。這現在被稱為“stop-the-world 部署”,其中應用程式暫時無法訪問。通過更復雜的部署策略,可以實現更平滑和更漸進的變化。終端使用者根本不需要知道應用程式已更改。

藍/綠 和 金絲雀 部署曾經是一門黑色藝術,但 Kubernetes 讓所有人都可以更廉價的使用它。更快的推出元件的新版本。不過可能需要您在自己的指令碼中或多或少地手動實現它們,但是更多好的方式是選擇一些 CD 釋出工具,以執行高階部署策略,例如 ArgoCD(藍/綠或金絲雀)。

在技術層面上,大多數部署策略歸結為同時部署同一組件的兩個版本,並以不同的方式將請求拆分給它們。你可以通過 Service 本身執行此操作,例如,用適當的標籤標記新版本的 5% 的 Pod,以使 Service 將流量路由到它們。或者即將推出的 Kubernetes Gateway 將開箱即用。

原則14:避免授予 Pod 不需要的許可權

Kubernetes 本身並不安全,預設情況下也不安全。但是您可以對其進行配置以強制執行安全最佳實踐,例如限制容器在節點上可以執行的操作。

以非 root 使用者身份執行您的容器。在 Docker 中構建容器映象使得容器預設以 root 身份執行這一事實可能已經為黑客帶來了近十年的樂土。僅在容器構建過程中使用 root 來安裝依賴項,然後建立一個非 root 使用者並讓其執行您的應用程式。

如果你的應用程式確實需要提升許可權,那麼仍然使用非 root 使用者,刪除所有 Linux 功能,並僅新增最少的功能集。

原則15:限制Pod在叢集中可以做的事情

禁止將預設服務帳戶暴露給您的應用程式。除非您特別需要與 Kubernetes API 互動,否則不應將預設服務帳戶令牌安裝到其中。然而,預設情況下,Kubernetes 是允許的。

設定並執行最嚴格的 Pod 安全策略 ,以確保預設情況下不會不必要地使不安全的操作模式成為可能。

使用網路策略來限制你的 Pod 可以連線到的其他 Pod。Kubernetes 中暢通無阻的預設網路是一場安全噩夢,因為這樣,攻擊者只需進入一個 Pod 即可直接訪問所有其他 Pod。

Log4Shell 對具有鎖定網路策略的容器完全無效,它會禁止所有出口流量,除了白名單上的流量(以及那個來自漏洞利用的 LDAP 服務不會生效)。

概括

本文介紹瞭如何設計雲原生應用程式並將其部署在 Kubernetes 上的 15 條原則。通過遵循這些原則,你的雲原生應用程式可以與 Kubernetes 工作負載編排器協同工作。這樣做可以讓你獲得 Kubernetes 平臺以及設計和操作軟體的雲原生方式提供的所有好處。

你已經學習瞭如何正確使用 Kubernetes 資源、為自動化做準備、如何處理故障、利用 Kubernetes 探測功能提高穩定性、為應用程式準備可觀察性、使 Kubernetes 排程程式為您工作、使用高階策略執行部署,以及如何限制已部署應用程式的攻擊面。

將這些方面融入到你的軟體架構工作中,可以讓你的日常 DevOps 流程更加順暢和可靠。