

本文為英文版的機器翻譯版本，如內容有任何歧義或不一致之處，概以英文版為準。

# Kubernetes 上游 SLOs
<a name="kubernetes_upstream_slos"></a>

Amazon EKS 執行與上游 Kubernetes 版本相同的程式碼，並確保 EKS 叢集在 Kubernetes 社群定義的 SLOs 內運作。Kubernetes [Scalability Special Interest Group (SIG)](https://github.com/kubernetes/community/tree/master/sig-scalability) 定義可擴展性目標，並透過 SLIs 和 SLOs 調查效能的瓶頸。

SLIs 是我們測量系統的方式，例如可用來判斷系統執行狀態的指標或指標，例如請求延遲或計數。SLOs會定義系統執行「良好」時預期的值，例如，請求延遲保持不到 3 秒。Kubernetes SLOs 和 SLIs 著重於 Kubernetes 元件的效能，並且與專注於 EKS 叢集端點可用性的 Amazon EKS 服務 SLAs 完全獨立。

Kubernetes 有許多功能，可讓使用者使用自訂附加元件或驅動程式來擴展系統，例如 CSI 驅動程式、許可 Webhook 和自動擴展器。這些擴充功能可能會以不同方式大幅影響 Kubernetes 叢集的效能，例如，如果 Webhook 目標無法使用，則使用 的許可 Webhook `failurePolicy=Ignore`可能會為 K8s API 請求增加延遲。Kubernetes 可擴展性 SIG 使用[「您承諾，我們承諾」架構](https://github.com/kubernetes/community/blob/master/sig-scalability/slos/slos.md#how-we-define-scalability)來定義可擴展性：

如果您承諾： - 正確設定叢集 - 使用擴充功能「合理」 - 將叢集中的負載保持在[建議限制](https://github.com/kubernetes/community/blob/master/sig-scalability/configs-and-limits/thresholds.md)內 

然後我們承諾您的叢集會擴展，即： - 所有 SLOs都已滿足。

## Kubernetes SLOs
<a name="_kubernetes_slos"></a>

Kubernetes SLOs 不會考慮可能影響叢集的所有外掛程式和外部限制，例如工作者節點擴展或許可 Webhook。這些 SLOs著重於 [Kubernetes 元件](https://kubernetes.io/docs/concepts/overview/components/)，並確保 Kubernetes 動作和資源的運作符合預期。SLOs 可協助 Kubernetes 開發人員確保 Kubernetes 程式碼的變更不會降低整個系統的效能。

[Kuberntes 可擴展性 SIG 定義了下列官方 SLO/SLIs](https://github.com/kubernetes/community/blob/master/sig-scalability/slos/slos.md)。Amazon EKS 團隊會定期對這些 SLOs/SLIs 的 EKS 叢集執行可擴展性測試，以在進行變更並發佈新版本時監控效能降低。


| 目標 | 定義 | SLO | 
| --- | --- | --- | 
|  API 請求延遲 （變動）  |  處理每個 （資源、動詞） 對之單一物件變動 API 呼叫的延遲，測量為過去 5 分鐘內的第 99 個百分位數  |  在預設 Kubernetes 安裝中，對於每個 （資源、動詞） 對，不包括虛擬和彙總資源和自訂資源定義，每個叢集天的第 99 個百分位數 <= 1s  | 
|  API 請求延遲 （唯讀）  |  處理每個 （資源、範圍） 對非串流唯讀 API 呼叫的延遲，測量為過去 5 分鐘內的第 99 個百分位數  |  在預設 Kubernetes 安裝中，對於每個 （資源、範圍） 對，不包括虛擬和彙總資源和自訂資源定義，每個叢集天的第 99 個百分位數：(a) <= 1s，如果 `scope=resource`(b) <= 30s （如果 `scope=namespace`或 `scope=cluster`)  | 
|  Pod 啟動延遲  |  可排程無狀態 Pod 的啟動延遲，不包括提取映像和執行 init 容器的時間，從 Pod 建立時間戳記到透過觀察報告其所有容器為啟動和觀察的時間，測量為過去 5 分鐘內的第 99 個百分位數  |  在預設 Kubernetes 安裝中，每個叢集天的第 99 個百分位數 <= 5s  | 

### API 請求延遲
<a name="_api_request_latency"></a>

根據`1m0s`預設， `kube-apiserver` `--request-timeout`定義為 ，這表示在逾時和取消之前，請求最多可以執行一分鐘 (60 秒）。為延遲定義的 SLOs 會依所提出的請求類型細分，可以是變動或唯讀：

#### 變動
<a name="_mutating"></a>

在 Kubernetes 中變更請求會變更資源，例如建立、刪除或更新。這些請求非常昂貴，因為在傳回更新後的物件之前，必須將這些變更寫入[至 等後端](https://kubernetes.io/docs/concepts/overview/components/#etcd)。[Etcd](https://etcd.io/) 是分散式金鑰值存放區，用於所有 Kubernetes 叢集資料。

對於 （資源、動詞） 對 Kubernetes 資源，此延遲測量為 5 分鐘內的第 99 個百分位數，例如，這將測量建立 Pod 請求和更新節點請求的延遲。請求延遲必須 <= 1 秒才能滿足 SLO。

#### 唯讀
<a name="_read_only"></a>

唯讀請求會擷取單一資源 （例如取得 Pod X) 或集合 （例如「從命名空間 X 取得所有 Pod」)。會`kube-apiserver`維護物件的快取，因此可能會從快取傳回請求的資源，或者可能需要先從 等項目擷取它們。這些延遲也會由 5 分鐘內的第 99 個百分位數測量，但唯讀請求可以有不同的範圍。SLO 定義了兩個不同的目標：
+ 對於對*單一*資源提出的請求 （即 `kubectl get pod -n mynamespace my-controller-xxx` )，請求延遲應保持 <= 1 秒。
+ 對於對命名空間或叢集中的多個資源提出的請求 （例如 `kubectl get pods -A`)，延遲應保持 <= 30 秒

SLO 具有不同請求範圍的不同目標值，因為對 Kubernetes 資源清單提出的請求預期請求中所有物件的詳細資訊會在 SLO 中傳回。在大型叢集或大型資源集合上，這可能會導致大型回應大小，這可能需要一些時間才能傳回。例如，在執行數萬個 Pod 的叢集中，當以 JSON 編碼時，每個 Pod 大約為 1 KiB，傳回叢集中的所有 Pod 會包含 10MB 或更多。Kubernetes 用戶端可以使用 [ APIListChunking 來擷取大量資源集合，](https://kubernetes.io/docs/reference/using-api/api-concepts/#retrieving-large-results-sets-in-chunks)協助減少此回應大小。

### Pod 啟動延遲
<a name="_pod_startup_latency"></a>

此 SLO 主要關注從建立 Pod 到該 Pod 中的容器實際開始執行所需的時間。為了測量此值與 Pod 上記錄的建立時間戳記的差異，以及[當該 Pod 上的 WATCH ](https://kubernetes.io/docs/reference/using-api/api-concepts/#efficient-detection-of-changes)報告開始計算容器時 （不包括容器映像提取和初始化容器執行的時間）。為了滿足 SLO，此 Pod 啟動延遲的每個叢集天的第 99 個百分位數必須保持 <=5 秒。

請注意，此 SLO 假設工作者節點已存在於此叢集中，處於就緒狀態，以便排定 Pod。此 SLO 不會考慮映像提取或初始化容器執行，也限制測試為「無狀態 Pod」，其不會利用持久性儲存外掛程式。

## Kubernetes SLI 指標
<a name="_kubernetes_sli_metrics"></a>

Kubernetes 也正在改善 SLIs 的可觀測性，方法是將 [Prometheus 指標](https://prometheus.io/docs/concepts/data_model/)新增至追蹤這些 SLIs 一段時間的 Kubernetes 元件。使用 [Prometheus 查詢語言 (PromQL)](https://prometheus.io/docs/prometheus/latest/querying/basics/)，我們可以建置在 Prometheus 或 Grafana 儀表板等工具中顯示 SLI 效能的查詢，以下是上述 SLOs的一些範例。

### API 伺服器請求延遲
<a name="_api_server_request_latency"></a>


| 指標 | 定義 | 
| --- | --- | 
|  apiserver\$1request\$1sli\$1duration\$1seconds  |  每個動詞、群組、版本、資源、子資源、範圍和元件的回應延遲分佈 （未計算 Webhook 持續時間和優先順序和公平性佇列等待時間），以秒為單位。  | 
|  apiserver\$1request\$1duration\$1seconds  |  每個動詞、試轉值、群組、版本、資源、子資源、範圍和元件的回應延遲分佈，以秒為單位。  | 

**注意**  
從 Kubernetes 1.27 開始，即可使用 `apiserver_request_sli_duration_seconds` 指標。

您可以使用這些指標來調查 API Server 回應時間，以及 Kubernetes 元件或其他外掛程式/元件是否有瓶頸。以下查詢是以[社群 SLO 儀表板](https://github.com/kubernetes/perf-tests/tree/master/clusterloader2/pkg/prometheus/manifests/dashboards)為基礎。

 **API 請求延遲 SLI （變動）** - 這次*不包含* Webhook 執行或佇列中等待的時間。 `histogram_quantile(0.99, sum(rate(apiserver_request_sli_duration_seconds_bucket{verb=~"CREATE|DELETE|PATCH|POST|PUT", subresource!~"proxy|attach|log|exec|portforward"}[5m])) by (resource, subresource, verb, scope, le)) > 0`

 **API 請求延遲總計 （變動）** - 這是請求在 API 伺服器上接受的總時間，這次可能比 SLI 時間長，因為它包括 Webhook 執行和 API 優先順序和公平性等待時間。 `histogram_quantile(0.99, sum(rate(apiserver_request_duration_seconds_bucket{verb=~"CREATE|DELETE|PATCH|POST|PUT", subresource!~"proxy|attach|log|exec|portforward"}[5m])) by (resource, subresource, verb, scope, le)) > 0`

在這些查詢中，我們會排除未立即傳回的串流 API 請求，例如 `kubectl port-forward`或 `kubectl exec`請求 (`subresource!~"proxy|attach|log|exec|portforward"`)，而且只會篩選修改物件 () 的 Kubernetes 動詞`verb=~"CREATE|DELETE|PATCH|POST|PUT"`。然後，我們將計算過去 5 分鐘內該延遲的第 99 個百分位數。

我們可以對唯讀 API 請求使用類似的查詢，只需修改要篩選的動詞，以包含唯讀動作 `LIST`和 `GET`。根據請求的範圍，也有不同的 SLO 閾值，即取得單一資源或列出一些資源。

 **API 請求延遲 SLI （唯讀）** - 這次*不包含* Webhook 執行或佇列中等待的時間。對於單一資源 (scope=resource， threshold=1s) `histogram_quantile(0.99, sum(rate(apiserver_request_sli_duration_seconds_bucket{verb=~"GET", scope=~"resource"}[5m])) by (resource, subresource, verb, scope, le))` 

對於相同命名空間中的資源集合 (scope=namespace， threshold=5s) `histogram_quantile(0.99, sum(rate(apiserver_request_sli_duration_seconds_bucket{verb=~"LIST", scope=~"namespace"}[5m])) by (resource, subresource, verb, scope, le))` 

對於整個叢集的資源集合 (scope=cluster， threshold=30s) `histogram_quantile(0.99, sum(rate(apiserver_request_sli_duration_seconds_bucket{verb=~"LIST", scope=~"cluster"}[5m])) by (resource, subresource, verb, scope, le))` 

 **API 請求延遲總計 （唯讀）** - 這是請求在 API 伺服器上接受的總時間，這次可能比 SLI 時間更長，因為它包含 Webhook 執行和等待時間。對於單一資源 (scope=resource， threshold=1s) `histogram_quantile(0.99, sum(rate(apiserver_request_duration_seconds_bucket{verb=~"GET", scope=~"resource"}[5m])) by (resource, subresource, verb, scope, le))` 

對於相同命名空間中的資源集合 (scope=namespace， threshold=5s) `histogram_quantile(0.99, sum(rate(apiserver_request_duration_seconds_bucket{verb=~"LIST", scope=~"namespace"}[5m])) by (resource, subresource, verb, scope, le))` 

對於整個叢集的資源集合 (scope=cluster， threshold=30s) `histogram_quantile(0.99, sum(rate(apiserver_request_duration_seconds_bucket{verb=~"LIST", scope=~"cluster"}[5m])) by (resource, subresource, verb, scope, le))` 

SLI 指標透過排除請求在 API Priority and Fairness 佇列中等待的時間、透過許可 Webhook 或其他 Kubernetes 延伸模組運作，來深入了解 Kubernetes 元件的執行方式。總指標提供更全面的檢視，因為它反映您的應用程式等待 API 伺服器回應的時間。比較這些指標可以深入了解請求處理發生延遲的位置。

### Pod 啟動延遲
<a name="_pod_startup_latency_2"></a>


| 指標 | 定義 | 
| --- | --- | 
|  kubelet\$1pod\$1start\$1sli\$1duration\$1seconds  |  以秒為單位啟動 Pod 的持續時間，不包括提取影像和執行 init 容器的時間，從 Pod 建立時間戳記到透過 watch 回報其所有容器已啟動和觀察的時間  | 
|  kubelet\$1pod\$1start\$1duration\$1seconds  |  從第一次看到 Pod 的 kubelet 到開始執行 Pod 的持續時間，以秒為單位。這不包括排程 Pod 或向外擴展工作者節點容量的時間。  | 

**注意**  
 `kubelet_pod_start_sli_duration_seconds` 從 Kubernetes 1.27 開始提供。

與上述查詢類似，您可以使用這些指標來深入了解相較於 Kubelet 動作，節點擴展、映像提取和初始化容器延遲 Pod 啟動的時間。

 **Pod 啟動延遲 SLI -** 這是從建立 Pod 到應用程式容器回報為執行中的時間。這包括工作者節點容量可用和 Pod 排程所需的時間，但這不包括提取映像或初始化容器執行所需的時間。 `histogram_quantile(0.99, sum(rate(kubelet_pod_start_sli_duration_seconds_bucket[5m])) by (le))`

 **Pod 啟動延遲總計 -** 這是第一次啟動 Pod 所需的時間。這是從 kubelet 透過 WATCH 接收 Pod 時開始測量，其中不包含工作者節點擴展或排程的時間。這包括提取映像和初始化容器以執行的時間。 `histogram_quantile(0.99, sum(rate(kubelet_pod_start_duration_seconds_bucket[5m])) by (le))`

## 叢集上的 SLOs
<a name="_slos_on_your_cluster"></a>

如果您要從 EKS 叢集中的 Kubernetes 資源收集 Prometheus 指標，您可以深入了解 Kubernetes 控制平面元件的效能。

[效能測試儲存庫](https://github.com/kubernetes/perf-tests/)包含 Grafana 儀表板，可在測試期間顯示叢集的延遲和關鍵效能指標。效能測試組態利用 [kube-prometheus-stack](https://github.com/prometheus-community/helm-charts/tree/main/charts/kube-prometheus-stack)，這是設定為收集 Kubernetes 指標的開放原始碼專案，但您也可以[使用 Amazon Managed Prometheus 和 Amazon Managed Grafana。](https://aws-observability.github.io/terraform-aws-observability-accelerator/eks/)

如果您使用的是 `kube-prometheus-stack`或類似的 Prometheus 解決方案，則可以安裝相同的儀表板，以即時觀察叢集上的 SLOs。

1. 您必須先安裝在具有 的儀表板中使用的 Prometheus 規則`kubectl apply -f prometheus-rules.yaml`。您可以在這裡下載規則的副本：https：//https://github.com/kubernetes/perf-tests/blob/master/clusterloader2/pkg/prometheus/manifests/prometheus-rules.yaml

   1. 請務必檢查 檔案中的命名空間是否符合您的環境

   1. 如果您使用 ，請確認標籤符合 `prometheus.prometheusSpec.ruleSelector` helm 值 `kube-prometheus-stack` 

1. 然後，您可以在 Grafana 中安裝儀表板。此處提供用於產生它們的 json 儀表板和 python 指令碼：https：//https://github.com/kubernetes/perf-tests/tree/master/clusterloader2/pkg/prometheus/manifests/dashboards

   1.  [`slo.json` 儀表板](https://github.com/kubernetes/perf-tests/blob/master/clusterloader2/pkg/prometheus/manifests/dashboards/slo.json)會顯示叢集與 Kubernetes SLOs 相關的效能

假設 SLOs專注於叢集中 Kubernetes 元件的效能，但您可以檢閱其他指標，為您的叢集提供不同的觀點或洞見。Kubernetes 社群專案，例如 [Kube-state-metrics](https://github.com/kubernetes/kube-state-metrics/tree/main)，可協助您快速分析叢集中的趨勢。Kubernetes 社群中最常見的外掛程式和驅動程式也會發出 Prometheus 指標，讓您調查自動擴展器或自訂排程器等項目。

[可觀測性最佳實務指南](https://aws-observability.github.io/observability-best-practices/guides/containers/oss/eks/best-practices-metrics-collection/#control-plane-metrics)提供其他 Kubernetes 指標的範例，您可以用來深入了解。