

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

# 工作负载
<a name="scale-workloads"></a>

工作负载会影响集群的扩展规模。 APIs 大量使用 Kubernetes 的工作负载会限制您在单个集群中可以拥有的工作负载总量，但是您可以更改一些默认值以帮助减少负载。

Kubernetes 集群中的工作负载可以访问与 Kubernetes API 集成的功能（例如 Secrets 和 ServiceAccounts），但是这些功能并不总是必需的，如果不使用这些功能，则应将其禁用。限制工作负载访问和对 Kubernetes 控制平面的依赖将增加你可以在集群中运行的工作负载数量，并通过消除对工作负载的不必要访问和实施最低权限做法来提高集群的安全性。请阅读[安全最佳实践](https://docs.aws.amazon.com/eks/latest/best-practices/security.html)，了解更多信息。

## 用 IPv6 于 pod 联网
<a name="_use_ipv6_for_pod_networking"></a>

您无法将 VPC 从过渡 IPv4 到 IPv6 ，因此 IPv6 在配置集群之前启用非常重要。如果您在 VPC IPv6 中启用，并不意味着您必须使用它，如果您的 pod 和服务使用了， IPv6 您仍然可以路由往返 IPv4 地址的流量。有关更多信息，请参阅 [EKS 网络最佳实践](https://docs.aws.amazon.com/eks/latest/best-practices/networking.html)。

[IPv6 在集群中使用](https://docs.aws.amazon.com/eks/latest/userguide/cni-ipv6.html)可以避免一些最常见的集群和工作负载扩展限制。 IPv6 避免因没有 IP 地址可用而无法创建 Pod 和节点的 IP 地址耗尽。它还提高了每个节点的性能，因为通过减少每个节点的 ENI 连接数量，Pod 可以更快地接收 IP 地址。在 [VPC CNI 中使用IPv4 前缀模式](https://docs.aws.amazon.com/eks/latest/best-practices/prefix-mode-linux.html)可以实现类似的节点性能，但仍需要确保 VPC 中有足够的 IP 地址可用。

## 限制每个命名空间的服务数量
<a name="_limit_number_of_services_per_namespace"></a>

[一个命名空间中的最大服务数为 5,000，集群中的最大服务数为](https://github.com/kubernetes/community/blob/master/sig-scalability/configs-and-limits/thresholds.md) 10,000。为了帮助组织工作负载和服务、提高性能并避免对命名空间范围内的资源造成级联影响，我们建议将每个命名空间的服务数量限制在 500 个。

使用 kube-proxy 为每个节点创建的 IP 表规则数量会随着集群中服务总数的增加而增长。生成成千上万个 IP 表规则并通过这些规则路由数据包会影响节点的性能并增加网络延迟。

只要每个命名空间的服务数量低于 500，即可创建包含单个应用程序环境的 Kubernetes 命名空间。这将使服务发现足够小，以避免服务发现限制，还可以帮助您避免服务命名冲突。应用程序环境（例如开发、测试、生产）应使用单独的 EKS 集群而不是命名空间。

## 了解 Elastic 负载均衡器配额
<a name="_understand_elastic_load_balancer_quotas"></a>

创建服务时，请考虑将使用哪种类型的负载平衡（例如网络负载均衡器 (NLB) 或应用程序负载均衡器 (ALB)）。每种负载均衡器类型提供不同的功能和[不同的配额](https://docs.aws.amazon.com/elasticloadbalancing/latest/application/load-balancer-limits.html)。有些默认配额可以调整，但有些配额上限无法更改。要查看您的账户配额和使用情况，请查看 AWS 控制台中的 S [ervice Quotas 控制面板](https://console.aws.amazon.com/servicequotas)。

例如，ALB 的默认目标是 1000。如果您的服务拥有超过 1000 个终端节点，则需要增加配额或将服务拆分为多个终端节点， ALBs 或者使用 Kubernetes Ingress。NLB 的默认目标是 3000，但每个可用区限制为 500 个目标。如果您的集群为 NLB 服务运行的容量超过 500 个，则需要使用多个容器 AZs 或请求提高配额限制。

使用与服务耦合的负载均衡器的另一种方法是使用[入口控制器](https://kubernetes.io/docs/concepts/services-networking/ingress-controllers/)。AWS Load Balancer 控制器可以 ALBs 为入口资源创建，但您可以考虑在集群中运行专用控制器。集群内入口控制器允许您通过在集群内运行反向代理来从单个负载均衡器公开多个 Kubernetes 服务。控制器具有不同的功能，例如支持 [Gateway API](https://gateway-api.sigs.k8s.io/)，根据您的工作负载的数量和规模，这些功能可能会带来好处。

## 使用 Route 53、Global Accelerator 或 CloudFront
<a name="_use_route_53_global_accelerator_or_cloudfront"></a>

要将使用多个负载均衡[器的服务作为单个终端节点使用，您需要使用[亚马逊 CloudFront](https://aws.amazon.com/cloudfront/)、AWS Global A](https://aws.amazon.com/global-accelerator/) ccelerator 或 A [mazon Route 53](https://aws.amazon.com/route53/) 将所有负载均衡器作为单个面向客户的终端节点公开。每个选项都有不同的好处，可以根据需要单独使用或一起使用。

Route 53 可以用一个通用名称公开多个负载均衡器，并且可以根据分配的权重向每个负载均衡器发送流量。您可以在[文档中阅读有关 DNS 权重的更多信息，也可以在](https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/resource-record-sets-values-weighted.html#rrsets-values-weighted-weight) AWS Load B [alancer Controller 文档中阅读如何使用 [Kubernetes 外部 DNS 控制器](https://github.com/kubernetes-sigs/external-dns)实现这些权重。](https://kubernetes-sigs.github.io/aws-load-balancer-controller/v2.4/guide/integrations/external_dns/#usage)

全球加速器可以根据请求的 IP 地址将工作负载路由到最近的区域。这对于部署到多个区域的工作负载可能很有用，但它并不能改善到单个区域中单个集群的路由。将 Route 53 与全球加速器结合使用还有其他好处，例如运行状况检查和在可用区不可用时自动进行故障转移。您可以[在这篇博客文章](https://aws.amazon.com/blogs/containers/operating-a-multi-regional-stateless-application-using-amazon-eks/)中看到在 Route 53 上使用全球加速器的示例。

CloudFront 可以与 Route 53 和全球加速器一起使用，也可以单独使用将流量路由到多个目的地。 CloudFront 缓存从原始来源提供的资产，这可能会降低带宽需求，具体取决于您提供的服务。

## 使用 EndpointSlices 代替终端节点
<a name="_use_endpointslices_instead_of_endpoints"></a>

在发现与服务标签匹配的 pod 时，应使用[EndpointSlices](https://kubernetes.io/docs/concepts/services-networking/endpoint-slices/)而不是终端节点。端点是小规模公开服务的简单方法，但是自动扩展或有更新的大型服务会导致 Kubernetes 控制平面上的大量流量。 EndpointSlices 有自动分组，可以启用拓扑感知提示之类的东西。

并非所有控制器都 EndpointSlices 默认使用。您应该验证您的控制器设置并在需要时将其启用。对于 [AWS Load Balancer 控制器](https://kubernetes-sigs.github.io/aws-load-balancer-controller/v2.4/deploy/configurations/#controller-command-line-flags)，您应该启用要使用的`--enable-endpoint-slices`可选标志 EndpointSlices。

## 如果可能，请使用不可变的和外部的机密
<a name="_use_immutable_and_external_secrets_if_possible"></a>

kubelet 会保留当前密钥和密钥值的缓存，这些密钥用于该节点上 Pod 的卷中。kubelet 会监视秘密以检测变化。随着集群的扩展，监视数量的增加可能会对 API 服务器性能产生负面影响。

有两种策略可以减少 Secrets 上的观看次数：
+ 对于不需要访问 Kubernetes 资源的应用程序，你可以通过设置 Token: false 来禁用自动挂载的服务账号密钥 automountServiceAccount
+ 如果您的应用程序的密钥是静态的，并且将来不会被修改，请将该[密钥标记为不可变](https://kubernetes.io/docs/concepts/configuration/secret/#secret-immutable)。kubelet 不维护 API 监视不可变的机密。

要禁用自动将服务帐户挂载到 pod，可以在工作负载中使用以下设置。如果特定工作负载需要服务帐号，则可以覆盖这些设置。

```
apiVersion: v1
kind: ServiceAccount
metadata:
  name: app
automountServiceAccountToken: true
```

在集群中的密钥数量超过 10,000 个限制之前对其进行监控。您可以使用以下命令查看集群中的密钥总数。您应该通过集群监控工具监控此限制。

```
kubectl get secrets -A | wc -l
```

您应该设置监控，以便在达到此限制之前提醒集群管理员。考虑使用外部机密管理选项，例如带有 Secrets [St](https://secrets-store-csi-driver.sigs.k8s.io/) ore CSI 驱动程序[的 AWS 密钥管理服务 (AWS KMS)](https://aws.amazon.com/kms/) 或 [Hashicorp Vault](https://www.vaultproject.io/)。

## 限制部署历史记录
<a name="_limit_deployment_history"></a>

创建、更新或删除 Pod 时可能会很慢，因为集群中仍会跟踪旧对象。你可以减少[部署以清理较旧`revisionHistoryLimit`的部署](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/#clean-up-policy) ReplicaSets ，这将降低到 Kubernetes 控制器管理器跟踪的对象总数。10 中部署的默认历史记录限制。

如果您的集群通过 CronJobs 或其他机制创建了大量任务对象，则应使用该[`ttlSecondsAfterFinished`设置](https://kubernetes.io/docs/concepts/workloads/controllers/ttlafterfinished/)自动清理集群中的旧 pod。这将在指定时间后从任务历史记录中删除成功执行的作业。

## enableServiceLinks 默认情况下禁用
<a name="_disable_enableservicelinks_by_default"></a>

当 Pod 在节点上运行时，kubelet 会为每个活动服务添加一组环境变量。Linux 进程的环境大小有上限，如果命名空间中有太多服务，则可以达到该大小。每个命名空间的服务数量不应超过 5,000。此后，服务环境变量的数量超过了 shell 限制，导致 Pod 在启动时崩溃。

Pod 不应使用服务环境变量进行服务发现还有其他原因。环境变量名称冲突、泄漏的服务名和环境总大小不一而足。您应该使用 CoreDNS 来发现服务端点。

## 限制每个资源的动态准入 webhook
<a name="_limit_dynamic_admission_webhooks_per_resource"></a>

 [动态准入 Webhook](https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/) 包括准入 webhook 和变异 Webhook。它们是 API 端点，不是 Kubernetes 控制平面的一部分，当资源发送到 Kubernetes API 时，它们会按顺序调用。每个 webhook 的默认超时时间为 10 秒，如果您有多个 webhook 或其中任何一个 webhook 超时，则可以增加 API 请求所花费的时间。

确保您的 webhook 具有高可用性（尤其是在可用区事件期间），并正确设置 Fa [ilurePolicy 以拒绝资源或忽略故障](https://kubernetes.io/docs/reference/access-authn-authz/extensible-admission-controllers/#failure-policy)。通过允许--dry-run kubectl 命令绕过 webhook，不要在不需要时调用 webhook。

```
apiVersion: admission.k8s.io/v1
kind: AdmissionReview
request:
  dryRun: False
```

改变 webhook 可以频繁地连续修改资源。如果你有 5 个变异 webhook 并部署 50 个资源，etcd 将存储每种资源的所有版本，直到每隔 5 分钟进行一次压缩，以移除修改后的资源的旧版本。在这种情况下，当 etcd 删除被取代的资源时，将从 etcd 中删除 200 个资源版本，根据资源的大小，可能会在 etcd 主机上占用大量空间，直到每 15 分钟进行一次碎片整理。

这种碎片整理可能会导致 etcd 暂停，这可能会对 Kubernetes API 和控制器产生其他影响。应避免频繁修改大型资源或快速连续修改数百个资源。

## 比较多个集群中的工作负载
<a name="_compare_workloads_across_multiple_clusters"></a>

如果您有两个集群的性能应该相似但却没有，请尝试比较指标以找出原因。

例如，比较集群延迟是一个常见问题。这通常是由于 API 请求量的差异造成的。你可以运行以下 CloudWatch LogInsight 查询来了解其中的区别。

```
filter @logStream like "kube-apiserver-audit"
| stats count(*) as cnt by objectRef.apiGroup, objectRef.apiVersion, objectRef.resource, userAgent, verb, responseStatus.code
| sort cnt desc
| limit 1000
```

您可以添加其他过滤器来缩小范围。例如，将重点放在来自的所有列表请求上`foo`。

```
filter @logStream like "kube-apiserver-audit"
| filter verb = "list"
| filter user.username like "foo"
| stats count(*) as cnt by objectRef.apiGroup, objectRef.apiVersion, objectRef.resource, responseStatus.code
| sort cnt desc
| limit 1000
```