Kubernetes 上游 SLOs - Amazon EKS

本文属于机器翻译版本。若本译文内容与英语原文存在差异,则一律以英文原文为准。

Kubernetes 上游 SLOs

Amazon EKS 运行的代码与上游 Kubernetes 版本相同,并确保 EKS 集群在 Kubernetes 社区 SLOs 定义的范围内运行。Kubernetes 可扩展性特别兴趣小组 (SIG) 定义了可扩展性目标,并通过和调查性能瓶颈。 SLIs SLOs

SLIs 是我们衡量系统的方式,例如可用于确定系统运行的 “良好” 的指标或衡量标准,例如请求延迟或计数。 SLOs 定义系统运行 “良好” 时的预期值,例如请求延迟保持在 3 秒以内。Kubernetes SLOs SLIs 侧重于 Kubernetes 组件的性能,完全独立于注重 EKS 集群终端节点可用性的亚马逊 EKS 服务 SLAs 。

Kubernetes 具有许多功能,允许用户使用自定义插件或驱动程序扩展系统,例如 CSI 驱动程序、准入 webhook 和自动缩放器。这些扩展可能会以不同的方式极大地影响 Kubernetes 集群的性能,也就是说,如果 webhook 目标不可用,则带有准入 webhook 的 webhook failurePolicy=Ignore 可能会增加 K8s API 请求的延迟。Kubernetes 可扩展性 SIG 使用 “你承诺,我们承诺” 的框架来定义可扩展性:

Kubernetes SLOs

Kubernetes SLOs 没有考虑到所有可能影响集群的插件和外部限制,例如工作节点扩展或准入 webhook。它们 SLOs 侧重于 Kubernetes 组件,并确保 Kubernetes 的操作和资源在预期范围内运行。它们 SLOs 可以帮助 Kubernetes 开发人员确保对 Kubernetes 代码的更改不会降低整个系统的性能。

Kuberntes 可扩展性 SIG 定义了以下官方 SLO/。SLIsAmazon EKS 团队定期在 EKS 集群上运行可扩展性测试, SLOs/SLIs 以监控随着更改和新版本发布而出现的性能下降。

目标 定义 SLO

API 请求延迟(变更)

处理每对(资源、动词)的单个对象的变异 API 调用的延迟,以过去 5 分钟内的第 99 个百分位数来衡量

在默认的 Kubernetes 安装中,对于每对(资源、动词),不包括虚拟资源和聚合资源以及自定义资源定义,每个集群日的第 99 个百分位数 <= 1s

API 请求延迟(只读)

处理每个(资源、范围)对的非流式只读 API 调用的延迟,以过去 5 分钟内的第 99 个百分位数来衡量

在默认 Kubernetes 安装中,对于每对(资源、范围),不包括虚拟资源和聚合资源以及自定义资源定义,每个集群日的第 99 个百分位数:(a) 如果 (b) <= 1s 否则为 <= 30s 否则为scope=resource(如果或)scope=namespacescope=cluster

Pod 启动延迟

可调度的无状态 pod 的启动延迟,不包括拉取镜像和运行 init 容器的时间,从 pod 创建时间戳到所有容器都报告为已启动并通过 watch 观察的时间来衡量,以过去 5 分钟内的第 99 个百分位数来衡量

在默认的 Kubernetes 安装中,每个集群日的第 99 个百分位数 <= 5s

API 请求延迟

kube-apiserver--request-timeout定义为1m0s默认值,这意味着请求最多可以运行一分钟(60 秒),然后才会被超时和取消。L SLOs atency 的定义按正在发出的请求类型进行细分,可以是变异请求或只读请求:

变异

Kubernetes 中的变异请求会对资源进行更改,例如创建、删除或更新。这些请求非常昂贵,因为在返回更新的对象之前,必须将这些更改写入 etcd 后端Etcd 是一种分布式键值存储,用于所有 Kubernetes 集群数据。

这种延迟是以 Kubernetes 资源对(资源、动词)在 5 分钟内的第 99 个百分位来衡量的,例如,这将衡量 Create Pod 请求和更新节点请求的延迟。请求延迟必须为 <= 1 秒才能满足 SLO。

Read-only

只读请求会检索单个资源(例如 Get Pod X)或集合(例如 “从命名空间 X 获取所有 Pod”)。kube-apiserver维护对象的缓存,因此可以从缓存中返回请求的资源,或者可能需要先从 etcd 中检索它们。这些延迟也是以 5 分钟内的第 99 个百分位数来衡量的,但是只读请求可以有不同的范围。SLO 定义了两个不同的目标:

  • 对于针对单个资源(即kubectl get pod -n mynamespace my-controller-xxx)发出的请求,请求延迟应保持 <= 1 秒。

  • 对于对命名空间或集群(例如kubectl get pods -A)中的多个资源发出的请求,延迟应保持 <= 30 秒

对于不同的请求范围,SLO 具有不同的目标值,因为对 Kubernetes 资源列表发出的请求需要在 SLO 中返回请求中所有对象的详细信息。在大型集群或大型资源集合上,这可能会导致响应大小过大,可能需要一些时间才能返回。例如,在运行成千上万个 Pod 且每个 Pod 以 JSON 编码时大约 1 KiB 的集群中,返回集群中的所有 Pod 将包含 10MB 或更多。Kubernetes 客户端可以使用分 APIList块检索大量资源来帮助缩小响应大小。

Pod 启动延迟

这个 SLO 主要关注从 Pod 创建 Pod 到该 Pod 中的容器实际开始执行所花费的时间。为了衡量这一点,计算了与 Pod 上记录的创建时间戳的差异,以及该 Pod 上的 WAT CH 报告容器已启动的时间(不包括容器镜像拉取和初始化容器执行的时间)。为了满足 SLO,此 Pod 启动延迟中每个集群日的第 99 个百分位数必须保持 <=5 秒。

请注意,此 SLO 假设此集群中已经存在工作节点,处于可以调度 Pod 的就绪状态。此 SLO 不考虑图像拉取或初始化容器执行,还将测试限制在不利用持久存储插件的 “无状态 pod” 上。

Kubernetes SLI 指标

Kubernetes 还通过 SLIs 向随时间跟踪这些指标的 Kubernetes 组件中添加 Prometheus 指标来改善可观察性。 SLIs 使用 Prometheus 查询语言 (PromQL),我们可以构建查询,在 Prom etheus 或 Grafana 仪表板等工具中显示一段时间内的 SLI 性能,以下是上述的一些示例。 SLOs

API 服务器请求延迟

指标 定义

apiserver_request_sli_duration_seconds

每个动词、组、版本、资源、子资源、范围和组件的响应延迟分布(不包括 webhook 持续时间以及优先级和公平性队列等待时间),以秒为单位。

apiserver_request_持续时间_秒

每个动词、试运行值、组、版本、资源、子资源、范围和组件的响应延迟分布(以秒为单位)。

注意:该apiserver_request_sli_duration_seconds指标从 Kubernetes 1.27 开始可用。

您可以使用这些指标来调查 API 服务器的响应时间以及 Kubernetes 组件或其他插件/组件中是否存在瓶颈。以下查询基于社区 SLO 控制面板

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-forwardkubectl exec请求 (subresource!~"proxy|attach|log|exec|portforward"),并且我们只筛选修改对象的 Kubernetes 动词 ()。verb=~"CREATE|DELETE|PATCH|POST|PUT"然后,我们将计算过去 5 分钟内延迟的第 99 个百分位数。

我们可以对只读 API 请求使用类似的查询,我们只需修改要筛选的动词以包含只读操作LISTGET。根据请求的范围,也存在不同的 SLO 阈值,即获取单个资源或列出多个资源。

API 请求延迟 SLI(只读)-此时间包括 webhook 的执行或队列中的等待时间。对于单个资源(范围=资源,阈值=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 执行和等待时间。对于单个资源(范围=资源,阈值=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 优先级和公平性队列中等待所花费的时间、通过准入 webhook 或其他 Kubernetes 扩展程序运行所花费的时间,从而深入了解 Kubernetes 组件的性能。总指标提供了更全面的视图,因为它反映了您的应用程序等待 API 服务器响应的时间。比较这些指标可以深入了解请求处理延迟在哪里引入的。

Pod 启动延迟

指标 定义

kubelet_pod_start_sli_sli_duration_seconds

启动 Pod 的持续时间(以秒为单位),不包括拉取图像和运行 init 容器的时间,从 pod 创建时间戳到其所有容器都报告为已启动并通过 watch 进行观察

kubelet_pod_start_duration_seconds

从 kubelet 第一次看到 pod 到 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 启动延迟总计- 这是 kubelet 首次启动 pod 所花费的时间。这是从 kubelet 通过 WATCH 收到 pod 的时间开始计算的,其中不包括工作节点扩展或调度的时间。这包括拉取映像和初始化容器以供运行的时间。 histogram_quantile(0.99, sum(rate(kubelet_pod_start_duration_seconds_bucket[5m])) by (le))

SLOs 在你的集群上

如果您正在从 EKS 集群中的 Kubernetes 资源中收集 Prometheus 指标,则可以更深入地了解 Kubernetes 控制平面组件的性能。

性能测试存储库包含 Grafana 仪表板,用于显示测试期间集群的延迟和关键性能指标。性能测试配置利用了配置为收集 Kubernetes 指标的开源项目,但你也可以使用亚马逊托管 Prometheus 和亚马逊托管 Grafana。kube-prometheus-stack

如果您使用的是kube-prometheus-stack或类似的 Prometheus 解决方案,则可以安装相同的控制面板来实时观察集群 SLOs 上的情况。

  1. 您首先需要安装控制面板中使用的 Prometheus 规则。kubectl apply -f prometheus-rules.yaml你可以在这里下载规则的副本:p https://github.com/kubernetes/erf--tests/blob/master/clusterloader2/pkg/prometheus/manifests/prometheus rules.yaml

    1. 请务必检查文件中的命名空间是否与您的环境相匹配

    2. 如果您使用的是,请验证标签是否与 prometheus.prometheusSpec.ruleSelector helm 值匹配 kube-prometheus-stack

  2. 然后,您可以在 Grafana 中安装控制面板。这里提供了 json 仪表板和生成它们的 python 脚本:https://github.com/kubernetes/perf-tests/tree/master/clusterloader2/pkg/prometheus/manifests/dashboards

    1. slo.json控制面板显示集群与 Kubernetes 相关的性能 SLOs

考虑一下, SLOs 它们侧重于集群中 Kubernetes 组件的性能,但是您可以查看其他指标,这些指标可以为集群提供不同的视角或见解。像 K 这样的 Kubernetes 社区项目ube-state-metrics可以帮助你快速分析集群中的趋势。Kubernetes 社区中大多数常见的插件和驱动程序也会发出 Prometheus 指标,允许你调查诸如自动扩缩程序或自定义调度器之类的内容。

可观察性最佳实践指南》提供了其他 Kubernetes 指标的示例,您可以使用这些指标来获得进一步的见解。