

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

# 成本优化的最佳实践
<a name="cost-opt"></a>

成本优化就是以最低的价格实现您的业务成果。按照本指南中的文档进行操作，您将优化您的 Amazon EKS 工作负载。

## 一般指导原则
<a name="general-guidelines"></a>

在云中，有许多通用准则可以帮助您实现微服务的成本优化：
+ 确保在 Amazon EKS 上运行的工作负载独立于用于运行容器的特定基础设施类型，这将为在最便宜的基础设施类型上运行它们提供更大的灵活性。在将 Amazon EKS 与配合使用时 EC2，由于工作负载的性质，当我们的工作负载[需要特定类型的 EC2 实例类型（例如需要 GPU](https://docs.aws.amazon.com/eks/latest/userguide/gpu-ami.html) 或其他实例类型）时，可能会出现例外情况。
+ 选择经过优化配置的容器实例 — 使用[适用于 Amazon EKS 的 Ama CloudWatch ](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/deploy-container-insights-EKS.html) zon Container Insights 或 Kubernetes 生态系统中提供的第三方工具，分析您的生产或预生产环境，并监控 CPU 和内存等关键指标。这将确保我们可以分配适当数量的资源，避免浪费资源。
+ 利用 AWS 中提供的不同购买选项来运行 EKS EC2，例如按需、Spot 和 Savings Plan。

## EKS 成本优化最佳实践
<a name="eks-cost-optimization-best-practices"></a>

云端成本优化有三个一般最佳实践领域：
+ 经济实惠的资源（Auto Scaling、向下扩展、政策和购买选项）
+ 支出意识（使用 AWS 和第三方工具）
+ 随着时间的推移进行优化（正确尺寸）

与任何指导一样，需要权衡取舍。确保与您的组织合作，了解此工作负载的优先级以及哪些最佳实践最重要。

### 如何使用本指南
<a name="how-to-use-this-guide"></a>

本指南适用于负责实施和管理 EKS 集群及其支持的工作负载的开发运营团队。该指南分为不同的最佳实践领域，便于使用。每个主题都列出了 EKS 集群成本优化的建议、要使用的工具和最佳实践。主题无需按特定顺序阅读。

### AWS 服务和 Kubernetes 的主要功能
<a name="key-aws-services-and-kubernetes-features"></a>

以下 AWS 服务和功能支持成本优化：
+ EC2 实例类型，Savings Plan（和预留实例）和竞价型实例，价格不同。
+ Auto Scaling 以及 Kubernetes 原生 Auto Scaling 策略。对于可预测的工作负载，可以考虑使用 Savings Plan（以前的预留实例）。使用托管数据存储（如 EBS 和 EFS），以获得应用程序数据的弹性和持久性。
+ 账单和成本管理控制台控制面板以及 AWS Cost Explorer 可概述您的 AWS 使用情况。使用 AWS Organizations 获取详细的账单详情。还分享了几种第三方工具的详细信息。
+ Amazon CloudWatch 容器指标提供了有关 EKS 集群资源使用情况的指标。除了 Kubernetes 仪表板之外，Kubernetes 生态系统中还有一些工具可以用来减少浪费。

本指南包括一组建议，您可以使用这些建议来改进 Amazon EKS 集群的成本优化。

## 反馈
<a name="feedback"></a>

本指南发布的目的是收集来自更广泛 GitHub 的 EKS/Kubernetes 社区的直接反馈和建议。如果您认为我们应该在指南中包含最佳实践，请在 GitHub 存储库中提交问题或提交 PR。我们的意图是在服务中添加新功能或出现新的最佳实践时，定期更新指南。

# 成本优化框架
<a name="cost-opt-framework"></a>

AWS 云经济学是一门通过采用 Amazon EKS 等现代计算技术来帮助客户提高效率和降低成本的学科。该学科建议遵循一种名为 “云财务管理（CFM）框架” 的方法，该框架由四个支柱组成：

![\[CFM 框架\]](http://docs.aws.amazon.com/zh_cn/eks/latest/best-practices/images/cfm_framework.png)


## See 支柱：衡量和问责制
<a name="_the_see_pillar_measurement_and_accountability"></a>

See 支柱是一组基础活动和技术，用于定义如何衡量、监控和创建云支出的问责制。它通常被称为 “可观测性”、“仪器” 或 “遥测”。“可观测性” 基础架构的功能和局限性决定了哪些可以优化。清晰地了解成本是成本优化的关键第一步，因为您需要知道自己的起点。这种可见性还将指导您为进一步优化环境而需要进行的活动类型。

以下是我们在 See 支柱方面的最佳实践的简要概述：
+ 为您的工作负载定义和维护标签策略。
  + 使用[实例标记](https://docs.aws.amazon.com/eks/latest/userguide/eks-using-tags.html#tag-resources-for-billing)，通过标记 EKS 集群，您可以查看单个集群的成本，并在成本和使用情况报告中进行分配。
+ 使用 K [ubecost 等技术建立对 EK](https://www.ibm.com/docs/en/kubecost/self-hosted/2.x?topic=installations-amazon-eks-integration) S 使用情况的报告和监控。
  +  [启用 Cloud Intelligence 仪表板](https://wellarchitectedlabs.com/cost/200_labs/200_enterprise_dashboards/)，通过正确标记资源并使用可视化效果，您可以衡量和估算成本。
+ 将云成本分配给应用程序、业务线 (LoBs) 和收入流。
+ 定义、衡量并 efficiency/value KPIs 与业务利益相关者进行沟通。例如，创建一个 “单位指标” KPI 来衡量每笔交易的成本，例如，拼车服务可能有 “每次行程成本” 的 KPI。

有关与该支柱相关的推荐技术和活动的更多详细信息，请参阅本指南的 “[成本优化-可观察性](cost-opt-observability.md)” 部分。

## 节省支柱：成本优化
<a name="_the_save_pillar_cost_optimization"></a>

该支柱基于 “See” 支柱中开发的技术和能力。以下活动通常属于这一支柱：
+ 识别并消除环境中的浪费。
+ 建筑师和设计旨在提高成本效益。
+ 选择最佳购买选项，例如按需实例与竞价型实例。
+ 随着服务的发展而适应：随着 AWS 服务的发展，高效使用这些服务的方式可能会发生变化。愿意适应这些变化。

由于这些活动是可操作的，因此它们在很大程度上取决于您的环境特征。问问自己，成本的主要驱动因素是什么？ 您的不同环境提供了哪些商业价值？ 哪些购买选项和基础架构选择（例如实例系列类型）最适合每种环境？

以下是按优先顺序排列的 EKS 集群最常见的成本驱动因素列表：

1.  **计算成本：**需要仔细考虑组合多种类型的实例系列、购买选项以及在可扩展性与可用性之间取得平衡。有关更多信息，请参阅本指南[成本优化-计算](cost-opt-compute.md)部分中的建议。

1.  **网络成本：对** EKS 集群使用 3 AZs 可能会增加可用区间的流量成本。有关如何平衡高可用性要求和降低网络流量成本的建议，请参阅本指南的 “[成本优化-联网](cost-opt-networking.md)” 部分。

1.  **存储成本：**根据 EKS 集群中工作负载的 stateful/stateless 性质以及不同存储类型的使用方式，可以将存储视为工作负载的一部分。有关 EKS 存储成本的注意事项，请参阅本指南的 “[成本优化-存储](cost-opt-storage.md)” 部分。

## 计划支柱：规划和预测
<a name="_the_plan_pillar_planning_and_forecasting"></a>

一旦 See 支柱中的建议得到实施，集群就会持续优化。随着在高效运营集群方面积累的经验，规划和预测活动可以侧重于：
+ 动态预算和预测云成本。
+ 量化 EKS 容器服务提供的商业价值。
+ 将 EKS 集群成本管理与 IT 财务管理规划相结合。

## 跑步支柱
<a name="_the_run_pillar"></a>

成本优化是一个持续的过程，涉及逐步改进的飞轮：

![\[成本优化飞轮\]](http://docs.aws.amazon.com/zh_cn/eks/latest/best-practices/images/flywheel.png)


确保高管对这类活动的赞助对于将EKS集群优化整合到组织的 “FinOps” 工作中至关重要。它允许利益相关者通过对EKS集群成本的共同理解、实施EKS集群成本护栏以及确保工具、自动化和活动随着组织的需求而发展，来协调利益相关者。

## 参考
<a name="_references"></a>
+  [AWS 云经济、云财务管理](https://aws.amazon.com/aws-cost-management/) 

# 支出意识
<a name="cost-opt-awareness"></a>

支出意识是了解谁在哪里以及是什么原因导致了您的 EKS 集群中的支出。准确了解这些数据将有助于提高人们对支出的认识，并突出需要补救的领域。

## 建议
<a name="_recommendations"></a>

### 使用 Cost Explorer
<a name="_use_cost_explorer"></a>

 [AWS Cost Explorer](https://aws.amazon.com/aws-cost-management/aws-cost-explorer/) 有一个 easy-to-use界面，可让您直观地了解、了解和管理您的 AWS 成本和使用情况。您可以使用 Cost Explorer 中提供的筛选器分析不同级别的成本和使用数据。

#### EKS 控制飞机和 EKS Fargate 成本
<a name="_eks_control_plane_and_eks_fargate_costs"></a>

使用筛选器，我们可以查询控制平面和 Fargate Pod 的 EKS 成本所产生的成本，如下图所示：

![\[Cost Explorer-EKS 控制平面\]](http://docs.aws.amazon.com/zh_cn/eks/latest/best-practices/images/eks-controlplane-costexplorer.png)


使用筛选器，我们可以查询 EKS 中各个区域的 Fargate Pod 产生的总成本，其中包括每个 CPU 的 vCPU 小时数和 GB 小时数，如下图所示：

![\[Cost Explorer-EKS Fargate\]](http://docs.aws.amazon.com/zh_cn/eks/latest/best-practices/images/eks-fargate-costexplorer.png)


#### 为资源加标签
<a name="_tagging_of_resources"></a>

Amazon EK [S 支持向您的亚马逊 EKS 集群添加 AWS 标签](https://docs.aws.amazon.com/eks/latest/userguide/eks-using-tags.html)。这样可以轻松控制对用于管理集群的 EKS API 的访问权限。添加到 EKS 集群的标签特定于 AWS EKS 集群资源，它们不会传播到集群使用的其他 AWS 资源，例如 EC2 实例或负载均衡器。如今，所有新的和现有的 EKS 集群都支持通过 AWS API、控制台和 SDKs进行集群标记。

AWS Fargate 是一项为容器提供按需、大小合适的计算容量的技术。您必须先定义至少一个 Fargate 配置文件，以指定 Pod 在启动时哪些 Pod 应该使用 Fargate，然后才能安排在集群中的 Fargate 上运行的 Pod。

向 EKS 集群添加和列出标签：

```
$ aws eks tag-resource --resource-arn arn:aws:eks:us-west-2:xxx:cluster/ekscluster1 --tags team=devops,env=staging,bu=cio,costcenter=1234
$ aws eks list-tags-for-resource --resource-arn arn:aws:eks:us-west-2:xxx:cluster/ekscluster1
{
    "tags": {
        "bu": "cio",
        "env": "staging",
        "costcenter": "1234",
        "team": "devops"
    }
}
```

在 [AWS Cost Explorer](https://docs.aws.amazon.com/awsaccountbilling/latest/aboutv2/cost-alloc-tags.html) 中激活成本分配标签后，AWS 会使用成本分配标签在成本分配报告中整理资源成本，以便您更轻松地对自己的 AWS 成本进行分类和跟踪。

标签对 Amazon EKS 没有任何语义意义，应严格按字符串进行解析。例如，您可以为 Amazon EKS 集群定义一组标签，以帮助您跟踪每个集群的拥有者和堆栈级别。

### 使用 AWS Trusted Advisor
<a name="_use_aws_trusted_advisor"></a>

AWS Trusted Advisor 提供了五个类别的一系列丰富的最佳实践检查和建议：成本优化、安全、容错、性能和服务限制。

为了实现成本优化，Trusted Advisor 可帮助消除未使用和闲置的资源，并建议对预留容量做出承诺。有助于 Amazon EKS 的关键行动项目将围绕低利用率 EC2 实例、未关联的弹性 IP 地址、空闲负载均衡器、未充分利用的 EBS 卷等。完整的检查清单可在-practice https://aws.amazon.com/premiumsupport/ technology/trusted-advisor/best-checklist/ 中找到。

Trusted Advisor 还为 EC2 实例和 Fargate 提供储蓄计划和预留实例建议，允许您承诺稳定的使用量以换取折扣费率。

**注意**  
来自 Trusted Advisor 的建议是一般性建议，并不特定于 EKS。

### 使用 Kubernetes 控制面板
<a name="_use_the_kubernetes_dashboard"></a>

 ***Kubernetes 控制面板*** 

Kubernetes 控制面板是一个适用于 Kubernetes 集群的通用基于 Web 的用户界面，它提供有关 Kubernetes 集群的信息，包括集群、节点和容器级别的资源使用情况。[亚马逊 EKS 文档中描述了在亚马逊 EKS 集群上部署 Kubernetes 控制面板的情况。](https://docs.aws.amazon.com/eks/latest/userguide/dashboard-tutorial.html)

控制面板提供每个节点和 Pod 的资源使用情况明细，以及有关 Pod、服务、部署和其他 Kubernetes 对象的详细元数据。这些整合的信息提供了对您的 Kubernetes 环境的可见性。

![\[Kubernetes 控制面板\]](http://docs.aws.amazon.com/zh_cn/eks/latest/best-practices/images/kubernetes-dashboard.png)


 ***kubectl top 然后描述命令*** 

使用 kubectl top 和 kubectl describe 命令查看资源使用指标。kubectl top 将显示集群中容器或节点或特定容器或节点的当前 CPU 和内存使用情况。kubectl describe 命令将提供有关特定节点或 Pod 的更多详细信息。

```
$ kubectl top pods
$ kubectl top nodes
$ kubectl top pod pod-name --namespace mynamespace --containers
```

使用 top 命令，输出将显示节点正在使用的 CPU（以内核为单位）和内存（以 MiB 为单位）的总量，以及这些数字所代表的节点可分配容量的百分比。然后，通过添加 *--c* ontainers标志，你可以深入到容器中的下一个级别，即容器级别。

```
$ kubectl describe node <node>
$ kubectl describe pod <pod>
```

 *kubectl des* cribe 返回每个资源请求或限制所代表的总可用容量的百分比。

kubectl 在 kubernetes pod、节点和容器中描述、跟踪关键资源（例如 CPU、内存和存储）的利用率和可用性。这种意识将有助于了解资源使用情况并有助于控制成本。

### 使用 CloudWatch 容器见解
<a name="_use_cloudwatch_container_insights"></a>

使用 CloudWatch Container [Insights](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/deploy-container-insights-EKS.html) 收集、汇总和汇总来自容器化应用程序和微服务的指标和日志。容器见解适用于亚马逊 Elastic Kubernetes Service、亚马逊上的 Kubernetes 平台和亚马逊 EC2上的 Kubernetes 平台。 EC2指标包括资源的使用率，如 CPU、内存、磁盘和网络。

[文档](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/deploy-container-insights-EKS.html)中给出了见解的安装。

CloudWatch 创建集群、节点、Pod、任务和服务级别的聚合指标作为 CloudWatch 指标。

 **以下查询显示了按节点 CPU 平均利用率排序的节点列表** 

```
STATS avg(node_cpu_utilization) as avg_node_cpu_utilization by NodeName
| SORT avg_node_cpu_utilization DESC
```

 **按容器名称划分的 CPU 使用率** 

```
stats pct(container_cpu_usage_total, 50) as CPUPercMedian by kubernetes.container_name
| filter Type="Container"
```

 **按容器名称划分的磁盘使用情况** 

```
stats floor(avg(container_filesystem_usage/1024)) as container_filesystem_usage_avg_kb by InstanceId, kubernetes.container_name, device
| filter Type="ContainerFS"
| sort container_filesystem_usage_avg_kb desc
```

更多示例查询在《[容器见解》文档](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Container-Insights-view-metrics.html)中给出 

这种意识将有助于了解资源使用情况并有助于控制成本。

### 使用 Kubecost 进行支出意识和指导
<a name="_using_kubecost_for_expenditure_awareness_and_guidance"></a>

诸如 [kubecost](https://kubecost.com/) 之类的第三方工具也可以部署在 Amazon EKS 上，以了解运行 Kubernetes 集群的成本。有关使用 Kubecost 跟踪成本的信息，请参阅此 [AWS 博客](https://aws.amazon.com/blogs/containers/how-to-track-costs-in-multi-tenant-amazon-eks-clusters-using-kubecost/)

使用 Helm 3 部署 kubecost：

```
$ curl -sSL https://raw.githubusercontent.com/helm/helm/master/scripts/get-helm-3 | bash
$ helm version --short
v3.2.1+gfe51cd1
$ helm repo add stable https://kubernetes-charts.storage.googleapis.com/
$ helm repo add stable https://kubernetes-charts.storage.googleapis.com/c^C
$ kubectl create namespace kubecost
namespace/kubecost created
$ helm repo add kubecost https://kubecost.github.io/cost-analyzer/
"kubecost" has been added to your repositories

$ helm install kubecost kubecost/cost-analyzer --namespace kubecost --set kubecostToken="aGRoZEBqc2pzLmNvbQ==xm343yadf98"
NAME: kubecost
LAST DEPLOYED: Mon May 18 08:49:05 2020
NAMESPACE: kubecost
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
--------------------------------------------------Kubecost has been successfully installed. When pods are Ready, you can enable port-forwarding with the following command:

    kubectl port-forward --namespace kubecost deployment/kubecost-cost-analyzer 9090

Next, navigate to http://localhost:9090 in a web browser.
$ kubectl port-forward --namespace kubecost deployment/kubecost-cost-analyzer 9090

NOTE: If you are using Cloud 9 or have a need to forward it to a different port like 8080, issue the following command
$ kubectl port-forward --namespace kubecost deployment/kubecost-cost-analyzer 8080:9090
```

Kubecost 控制面板-![\[Kubernetes Cluster Auto Scaler logs\]](http://docs.aws.amazon.com/zh_cn/eks/latest/best-practices/images/kube-cost.png) 

### 使用 Kubernetes 成本分配和容量规划分析工具
<a name="_use_kubernetes_cost_allocation_and_capacity_planning_analytics_tool"></a>

 [Kubernetes Opex Analytics](https://github.com/rchakode/kube-opex-analytics) 是一种工具，可帮助组织跟踪其 Kubernetes 集群消耗的资源，以防止多付钱。为此，它会生成短期（7 天）、中期（14 天）和长期（12 个月）使用报告，显示有关每个项目在一段时间内花费的资源量的相关见解。

![\[Kubernetes 运营支出分析\]](http://docs.aws.amazon.com/zh_cn/eks/latest/best-practices/images/kube-opex-analytics.png)


### Yotascale
<a name="_yotascale"></a>

Yotascale 有助于准确分配 Kubernetes 成本。Yotascale Kubernetes 成本分配功能利用实际成本数据（包括预留实例折扣和竞价实例定价，而不是通用的市场价格估计）来告知 Kubernetes 的总成本占用空间

更多细节可以在[他们的网站上](https://www.yotascale.com/)找到。

### Alcide 顾问
<a name="_alcide_advisor"></a>

Alcide 是 AWS 合作伙伴网络 (APN) 的高级技术合作伙伴。Alcide Advisor 可帮助确保您的 Amazon EKS 集群、节点和容器配置经过调整，使其根据安全最佳实践和内部指南运行。Alcide Advisor 是一项针对 Kubernetes 审计和合规性的无代理服务，旨在通过在进入生产之前强化开发阶段来确保 DevSecOps 流畅和安全的流程。

更多细节可以在此[博客文章](https://aws.amazon.com/blogs/apn/driving-continuous-security-and-configuration-checks-for-amazon-eks-with-alcide-advisor/)中找到。

## 其他工具
<a name="_other_tools"></a>

### Kubernetes 垃圾收集
<a name="_kubernetes_garbage_collection"></a>

[Kubernetes 垃圾收集](https://kubernetes.io/docs/concepts/workloads/controllers/garbage-collection/)器的作用是删除某些曾经拥有所有者但不再拥有所有者的对象。

### Fargate 计数
<a name="_fargate_count"></a>

 [Fargatecount](https://github.com/mreferre/fargatecount) 是一个有用的工具，它允许 AWS 客户使用自定义 CloudWatch 指标跟踪特定账户特定区域中已在 Fargate 上部署的 EKS 容器总数。这有助于跟踪在 EKS 集群中运行的所有 Fargate 吊舱。

### Popeye-Kubernetes 集群消毒器
<a name="_popeye_a_kubernetes_cluster_sanitizer"></a>

 [Popeye-Kubernetes 集群清理器](https://github.com/derailed/popeye)是一个实用程序，用于扫描实时的 Kubernetes 集群并报告已部署资源和配置的潜在问题。它会根据已部署的内容而不是磁盘上的内容对集群进行清理。通过扫描您的集群，它可以检测错误配置并帮助您确保最佳实践到位

### 资源
<a name="_resources"></a>

要详细了解成本优化的最佳实践，请参阅以下资源。

#### 文档和博客
<a name="_documentation_and_blogs"></a>
+  [亚马逊 EKS 支持标记](https://docs.aws.amazon.com/eks/latest/userguide/eks-using-tags.html) 

#### 工具
<a name="_tools"></a>
+  [什么是 AWS 账单和成本管理？](https://docs.aws.amazon.com/awsaccountbilling/latest/aboutv2/cost-alloc-tags.html) 
+  [Amazon CloudWatch 容器洞察](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/ContainerInsights.html) 
+  [如何使用 Kubecost 跟踪多租户 Amazon EKS 集群的成本](https://aws.amazon.com/blogs/containers/how-to-track-costs-in-multi-tenant-amazon-eks-clusters-using-kubecost/) 
+  [Kubecost](https://kubecost.com/) 
+  [Kube Opsview](https://github.com/hjacobs/kube-ops-view) 
+  [Kubernetes 运营支出分析](https://github.com/rchakode/kube-opex-analytics) 

# 计算和自动缩放
<a name="cost-opt-compute"></a>

作为开发人员，您需要估算应用程序的资源需求，例如CPU和内存，但是如果您不不断调整它们，它们可能会过时，这可能会增加您的成本并降低性能和可靠性。持续调整应用程序的资源需求比第一次就正确调整它们更为重要。

下面提到的最佳实践将帮助您构建和运营成本感知型工作负载，从而实现业务成果，同时最大限度地降低成本，并使您的组织能够最大限度地提高投资回报。优化集群计算成本的高级重要性顺序是：

1. 适当调整工作负载规模

1. 减少未使用的容量

1. 优化计算容量类型（例如 Spot）和加速器（例如 GPUs）

## 正确调整工作负载规模
<a name="_right_size_your_workloads"></a>

在大多数 EKS 集群中，大部分成本来自用于运行容器化工作负载的 EC2 实例。如果不了解自己的工作负载需求，您将无法调整计算资源的大小。因此，您必须使用适当的请求和限制，并根据需要对这些设置进行调整。此外，实例大小和存储选择等依赖关系可能会影响工作负载性能，从而对成本和可靠性产生各种意想不到的后果。

 *请求*应与实际利用率保持一致。如果容器的请求过高，就会出现未使用的容量，这是集群总成本的一个重要因素。Pod 中的每个容器（例如应用程序和 sidecar）都应设置自己的请求和限制，以确保集合 pod 限制尽可能准确。

使用 [Goldilocks](https://www.youtube.com/watch?v=DfmQWYiwFDk)、[KRR 和 K](https://www.youtube.com/watch?v=uITOzpf82RY) [ubecost](https://aws.amazon.com/blogs/containers/aws-and-kubecost-collaborate-to-deliver-cost-monitoring-for-eks-customers/) 等工具来估算容器的资源请求和限制。根据应用程序的性质、 performance/cost 要求和复杂性，您需要评估哪些指标最适合扩展，应用程序性能在什么时候下降（饱和点），以及如何相应地调整请求和限制。有关此主题的进一步指导，请参阅[应用程序的正确尺寸](https://docs.aws.amazon.com/eks/latest/best-practices/node_and_workload_efficiency.html)。

我们建议使用水平容器自动扩缩器 (HPA) 来控制应运行应用程序的副本数量，使用垂直容器自动扩缩器 (VPA) 来调整应用程序每个副本所需的请求数量和限制，使用像 [Karpent](http://karpenter.sh/) er 或 Cluster Autoscaler 这样的节点自动扩缩器来持续调整[集群中的](https://github.com/kubernetes/autoscaler)节点总数。本文档的后面部分将记录使用 Karpenter 和 Cluster Autoscaler 的成本优化技术。

Vertical Pod Autoscaler 可以调整分配给容器的请求和限制，从而使工作负载以最佳方式运行。你应该在审计模式下运行 VPA，这样它就不会自动进行更改和重启你的 pod。它将根据观察到的指标提出更改建议。对于影响生产工作负载的任何更改，您都应先在非生产环境中查看和测试这些更改，因为这些更改可能会影响应用程序的可靠性和性能。

## 减少消费
<a name="_reduce_consumption"></a>

节省资金的最佳方法是配置更少的资源。实现这一目标的一种方法是根据工作负载的当前需求调整工作负载。在开始任何成本优化工作时，您都应确保您的工作负载定义其要求并动态扩展。这将需要从您的应用程序中获取指标并设置配置（例如[https://kubernetes.io/docs/tasks/run-application/configure-pdb/](https://kubernetes.io/docs/tasks/run-application/configure-pdb/)和 [Pod Readiness Gates](https://kubernetes-sigs.github.io/aws-load-balancer-controller/v2.5/deploy/pod_readiness_gate/)），以确保您的应用程序可以安全地动态地向上和向下扩展。重要的是要考虑到，限制 PodDisruptionBudgets 会阻止 Cluster Autoscaler 和 Karpenter 缩小节点规模，因为集群自动扩缩器和 Karpenter 都尊重。 PodDisruptionBudgets中的 “minAvailable” 值 PodDisruptionBudget 应始终低于部署中的容器数量，并且应在两者之间保持良好的缓冲区。例如，在 6 个 pod 的部署中，您希望始终至少运行 4 个 pod，请将您 PodDisruptionBidget 的 “minAvailable” 设置为 4。这将允许 Cluster Autoscaler 和 Karpenter 在节点缩减事件期间安全地从未充分利用的节点中排出 Pod 并将其驱逐出去。请参阅[集群自动扩缩器常见问题解答文档](https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/FAQ.md#what-types-of-pods-can-prevent-ca-from-removing-a-node)。

Horistant Pod Autoscaler 是一款灵活的工作负载自动扩缩器，可以调整需要多少副本来满足应用程序的性能和可靠性要求。它有一个灵活的模型，可以根据各种指标（例如 CPU、内存或自定义指标（例如队列深度、与 Pod 的连接数等）来定义何时向上和向下扩展。

[Kubernetes Metrics Server 支持根据内置指标（例如 CPU 和内存使用情况）进行扩展，但是如果您想根据其他指标（例如 Amazon CloudWatch 或 SQS 队列深度）进行扩展，则应考虑事件驱动的自动扩展项目，例如 KEDA。](https://keda.sh/)请参阅[此博客文章](https://aws.amazon.com/blogs/mt/proactive-autoscaling-of-kubernetes-workloads-with-keda-using-metrics-ingested-into-amazon-cloudwatch/)，了解如何将 KEDA 与 CloudWatch 指标配合使用。如果您不确定要根据哪些指标进行监控和扩展，请查看有关[重要监控指标的最佳实践](https://aws-observability.github.io/observability-best-practices/guides/#monitor-what-matters)。

减少工作负载消耗会在集群中造成容量过剩，通过适当的自动扩展配置，您可以自动缩减节点并减少总支出。我们建议您不要尝试手动优化计算容量。Kubernetes 调度器和节点自动扩缩器旨在为您处理此过程。

## 减少未使用的容量
<a name="_reduce_unused_capacity"></a>

在确定了应用程序的正确大小并减少了多余的请求之后，就可以开始减少预配置的计算容量了。如果您已经花时间根据上面的部分正确调整工作负载的大小，则应该能够动态地执行此操作。AWS 中有两个主节点自动扩缩器与 Kubernetes 配合使用。

### Karpenter 和 Cluster 自动扩缩器
<a name="_karpenter_and_cluster_autoscaler"></a>

随着 Pod 的创建或移除以及计算要求的变化，Karpenter 和 Kubernetes 集群自动扩缩器都会扩展集群中的节点数量。两者的主要目标是一样的，但是 Karpenter 在节点管理配置和取消配置方面采用了不同的方法，这有助于降低成本并优化集群范围的使用率。

随着集群规模的扩大和工作负载种类的增加，预配置节点组和实例变得越来越困难。就像处理工作负载请求一样，设定初始基准并根据需要不断调整非常重要。

如果您使用的是集群自动扩缩器，它将尊重每个 Auto Scaling 组 (ASG) 的 “最小” 和 “最大” 值，并且只调整 “所需值”。在为底层 ASG 设置这些值时务必注意，因为 Cluster Autoscaler 无法将超出 “最小” 数量的 ASG 缩小规模。将 “期望” 计数设置为正常工作时间所需的节点数，将 “最小” 设置为非工作时间所需的节点数。请参阅[集群自动扩缩器常见问题解答文档](https://github.com/kubernetes/autoscaler/blob/master/cluster-autoscaler/cloudprovider/aws/README.md#auto-discovery-setup)。

### 集群自动扩缩器优先级扩展器
<a name="_cluster_autoscaler_priority_expander"></a>

Kubernetes Cluster Autoscaler 的工作原理是在应用程序向上和向下扩展时向上和向下扩展节点组（称为节点组）。如果您没有动态扩展工作负载，那么集群自动扩缩器将无法帮助您节省资金。Cluster Autoscaler 要求集群管理员提前创建节点组以供工作负载使用。节点组需要配置为使用具有相同 “配置文件” 的实例，即大致相同的 CPU 和内存量。

您可以有多个节点组，并且可以将 Cluster Autoscaler 配置为设置优先级扩展级别，并且每个节点组可以包含不同大小的节点。节点组可以有不同的容量类型，优先级扩展器可以先扩展成本较低的组。

以下是集群配置片段的示例，该片段在使用按需实例之前使用`ConfigMap``来确定预留容量的优先级。您可以使用相同的方法将 Graviton 或 Spot 实例优先于其他类型。

```
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig
metadata:
  name: my-cluster
managedNodeGroups:
  - name: managed-ondemand
    minSize: 1
    maxSize: 7
    instanceType: m5.xlarge
  - name: managed-reserved
    minSize: 2
    maxSize: 10
    instanceType: c5.2xlarge
```

```
apiVersion: v1
kind: ConfigMap
metadata:
  name: cluster-autoscaler-priority-expander
  namespace: kube-system
data:
  priorities: |-
    10:
      - .*ondemand.*
    50:
      - .*reserved.*
```

默认情况下，使用节点组可以帮助底层计算资源完成预期的事情，例如将节点分布在各处 AZs，但并非所有工作负载都有相同的要求或期望，最好让应用程序明确声明其需求。有关集群自动扩缩器的更多信息，请参阅[最佳实践部分](https://docs.aws.amazon.com/eks/latest/best-practices/cas.html)。

### Descheduler
<a name="_descheduler"></a>

Cluster Autoscaler 可以根据需要调度的新 Pod 或未充分利用的节点来增加和移除集群中的节点容量。在将 pod 调度到节点后，它不会全面了解 pod 的放置情况。如果您使用的是集群自动扩缩程序，则还应查看 [Kubernetes 解调器，以避免浪费集群中的容](https://github.com/kubernetes-sigs/descheduler)量。

如果您的集群中有 10 个节点，并且每个节点的利用率为 60%，则您使用的容量不会占集群中预置容量的 40%。使用 Cluster Autoscaler，您可以将每个节点的利用率阈值设置为 60%，但只有在利用率降至 60% 以下之后，才会尝试缩小单个节点。

使用解调器，它可以在调度 pod 或将节点添加到集群后查看集群容量和利用率。它会尝试将集群的总容量保持在指定的阈值以上。它还可以根据节点污点或加入集群的新节点移除 Pod，以确保 Pod 在其最佳计算环境中运行。请注意，descheduler 不会安排更换已驱逐的 pod，而是依赖默认的调度器来完成此操作。

### Karpenter 整合
<a name="_karpenter_consolidation"></a>

Karpenter 采用 “无组” 方法进行节点管理。这种方法对于不同的工作负载类型更加灵活，并且需要更少的集群管理员预先配置。Karpenter 没有预先定义组并根据工作负载的需要扩展每个组，而是使用配置器和节点模板来广泛定义可以创建的 EC2 实例类型以及创建实例时的设置。

Bin packing 是一种通过将更多工作负载打包到更少、大小最优的实例上来利用更多实例资源的做法。虽然这仅通过配置工作负载使用的资源来帮助降低计算成本，但它需要权衡取舍。启动新工作负载可能需要更长时间，因为必须向集群添加容量，尤其是在大规模扩展活动期间。设置垃圾箱包装时，请考虑成本优化、性能和可用性之间的平衡。

Karpenter 可以持续监控和装箱，以提高实例资源利用率并降低计算成本。Karpenter 还可以为您的工作负载选择更具成本效益的工作节点。这可以通过在配置器中将 “合并” 标志设置为 true 来实现（下面的示例代码片段）。以下示例显示了一个支持整合的置备程序示例。在撰写本指南时，Karpenter 不会将正在运行的竞价型实例替换为更便宜的竞价型实例。有关 Karpenter 整合的更多详细信息，请参阅[此](https://aws.amazon.com/blogs/containers/optimizing-your-kubernetes-compute-costs-with-karpenter-consolidation/)博客。

```
apiVersion: karpenter.sh/v1
kind: Provisioner
metadata:
  name: enable-binpacking
spec:
  consolidation:
    enabled: true
```

对于可能无法中断的工作负载，例如没有检查点的长时间运行的批处理作业，可以考虑使用注释为 pod 添加注释。`do-not-evict`通过选择 pod 退出驱逐，你是在告诉 Karpenter 它不应该自愿移除包含这个 pod 的节点。但是，如果在节点耗尽时将 `do-not-evict` Pod 添加到该节点，则其余的 pod 仍会被驱逐，但是该 Pod 在被移除之前会阻止终止。无论哪种情况，都将封锁该节点，以防止在该节点上安排其他工作。以下是显示如何设置注释的示例：

```
apiVersion: v1
kind: Pod
metadata:
  name: label-demo
  labels:
    environment: production
  annotations: +
    "karpenter.sh/do-not-evict": "true"
spec:
  containers:

* name: nginx
image: nginx
ports:
 ** containerPort: 80
```

### 通过调整集群自动扩缩程序参数来移除未充分利用的节点
<a name="_remove_under_utilized_nodes_by_adjusting_cluster_autoscaler_parameters"></a>

节点利用率定义为请求的资源总和除以容量。默认情况下`scale-down-utilization-threshold`，设置为 50%。此参数可以与和一起使用`scale-down-unneeded-time`，后者决定了节点在有资格缩减之前应该不需要多长时间，默认值为 10 分钟。Kube-scheduler 会将仍在缩减的节点上运行的 Pod 调度到其他节点上。调整这些设置可以帮助移除未充分利用的节点，但请务必先测试这些值，这样就不会强迫集群过早缩小规模。

您可以确保驱逐成本高昂的 Pod 受到集群自动扩缩器识别的标签的保护，从而防止缩小规模的发生。为此，请确保驱逐成本高昂的 pod 具有注释`cluster-autoscaler.kubernetes.io/safe-to-evict=false`。以下是设置注释的 yaml 示例：

```
apiVersion: v1
kind: Pod
metadata:
  name: label-demo
  labels:
    environment: production
  annotations: +
    "cluster-autoscaler.kubernetes.io/safe-to-evict": "false"
spec:
  containers:

* name: nginx
image: nginx
ports:
 ** containerPort: 80
```

### 使用集群自动扩缩器和 Karpenter 标记节点
<a name="_tag_nodes_with_cluster_autoscaler_and_karpenter"></a>

AWS 资源[标签](https://docs.aws.amazon.com/tag-editor/latest/userguide/tagging.html)用于组织您的资源，并详细跟踪您的 AWS 成本。它们不与 Kubernetes 标签直接关联以进行成本跟踪。建议从 Kubernetes 资源标签开始，然后使用 Kubecos [t 之类的工具根据容器、命名空间等上的 K](https://aws.amazon.com/blogs/containers/aws-and-kubecost-collaborate-to-deliver-cost-monitoring-for-eks-customers/) ubernetes 标签来获取基础设施成本报告。

工作节点需要有标签才能在 AWS Cost Explorer 中显示账单信息。使用 Cluster Autoscaler，使用[启动](https://docs.aws.amazon.com/eks/latest/userguide/launch-templates.html)模板在托管节点组中标记您的工作节点。对于自我管理的节点组，请使用 a [EC2 uto Scaling 组](https://docs.aws.amazon.com/autoscaling/ec2/userguide/ec2-auto-scaling-tagging.html)标记您的实例。对于 Karpenter 配置的实例，请在节点模板中使用 [spec.tags对其进行标记。](https://karpenter.sh/docs/concepts/nodeclasses/#spectags)

### 多租户集群
<a name="_multi_tenant_clusters"></a>

在处理由不同团队共享的集群时，您可能无法看到在同一节点上运行的其他工作负载。虽然资源请求可以帮助隔离一些 “邻居噪音大” 的问题，例如 CPU 共享，但它们可能无法隔离所有资源边界，例如磁盘 I/O 耗尽。并非每个工作负载消耗的资源都可以被隔离或限制。应通过节点[污点和容忍](https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/)度来隔离以比其他工作负载更高的速率消耗共享资源的工作负载。处理此类工作负载的另一种高级技术是 [CPU 固定](https://kubernetes.io/docs/tasks/administer-cluster/cpu-management-policies/#static-policy)，它可确保容器专用 CPU 而不是共享 CPU。

[在节点级别隔离工作负载可能会更昂贵，但可以通过使用[预留实例](https://aws.amazon.com/ec2/pricing/reserved-instances/)、[Graviton 处理器](https://aws.amazon.com/ec2/graviton/)或 Spot 来安排[BestEffort](https://kubernetes.io/docs/concepts/workloads/pods/pod-qos/#besteffort)任务或利用额外节省的费用。](https://aws.amazon.com/ec2/spot/)

共享集群还可能存在集群级别的资源限制，例如 IP 耗尽、Kubernetes 服务限制或 API 扩展请求。您应查看[可扩展性最佳实践指南](https://docs.aws.amazon.com/eks/latest/best-practices/scale-control-plane.html)，确保您的集群规避这些限制。

您可以在命名空间或 Karpenter 配置器级别隔离资源。[资源配额](https://kubernetes.io/docs/concepts/policy/resource-quotas/)提供了一种设置命名空间中工作负载可以消耗的资源数量限制的方法。这可能是一个不错的初始防护栏，但应不断对其进行评估，以确保它不会人为地限制工作负载的扩展。

Karpenter Provisioners 可以[对集群中的某些消耗资源（例如 CPU、GPU）设置限制](https://karpenter.sh/docs/concepts/nodepools/#speclimitsresources)，但您需要配置租户应用程序才能使用相应的配置器。这可以防止单个配置器在集群中创建太多节点，但应持续对其进行评估，以确保限制设置得不太低，从而防止工作负载扩展。

### 定时自动缩放
<a name="_scheduled_autoscaling"></a>

您可能需要在周末和非工作时间缩小集群。这对于测试和非生产集群尤其重要，在这些集群中，您希望在不使用时将其缩小到零。诸如[集群关闭之类](https://github.com/kubecost/cluster-turndown)的解决方案可以根据cron计划将副本缩小到零。[您也可以使用 Karpenter 实现这一目标，下面的 AWS 博客对此进行了概述。](https://aws.amazon.com/blogs/containers/manage-scale-to-zero-scenarios-with-karpenter-and-serverless/)

## 优化计算容量类型
<a name="_optimize_compute_capacity_types"></a>

在优化了集群中的总计算容量并利用垃圾箱打包后，您应该查看在集群中预配置了哪种类型的计算以及如何为这些资源付费。AWS 的[计算节省计划](https://aws.amazon.com/savingsplans/compute-pricing/)可以降低您的计算成本，我们会将其归类为以下容量类型：
+ Spot
+ 节省计划
+ 按需型
+ Fargate

每种容量类型在管理开销、可用性和长期承诺方面都有不同的权衡，您需要决定哪种容量类型适合您的环境。任何环境都不应依赖单一容量类型，您可以在单个集群中混合使用多种运行类型，以优化特定的工作负载要求和成本。

### Spot
<a name="_spot"></a>

[Spot](https://aws.amazon.com/ec2/spot/) 容量类型利用可用区的备用容量配置 EC2 实例。Spot 提供的折扣最大，最高可达 90%，但是当其他地方需要这些实例时，这些实例可能会被中断。此外，可能并不总是有容量来配置新的竞价型实例，并且只要[发出中断通知 2 分钟](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/spot-interruptions.html)，就可以回收现有的竞价型实例。如果您的应用程序启动或关闭过程很长，则竞价型实例可能不是最佳选择。

竞价计算应使用各种各样的实例类型，以降低竞价容量不可用的可能性。需要处理实例中断才能安全关闭节点。使用 Karpenter 或托管节点组的一部分配置的节点会自动支持[实例](https://docs.aws.amazon.com/eks/latest/best-practices/karpenter.html)中断通知。如果您使用的是自管理节点，则需要单独运行[节点终止处理程序](https://github.com/aws/aws-node-termination-handler)以优雅地关闭竞价型实例。

可以在单个集群中平衡竞价实例和按需实例。借助 Karpenter，您可以创建[加权配置器](https://karpenter.sh/docs/concepts/scheduling/#on-demandspot-ratio-split)以实现不同容量类型的平衡。借助 Cluster Autoscaler，您可以创建[包含竞价型实例和按需实例或预留实例的混合节点组](https://aws.amazon.com/blogs/containers/amazon-eks-now-supports-provisioning-and-managing-ec2-spot-instances-in-managed-node-groups/)。

以下是使用 Karpenter 将竞价型实例优先于按需实例的优先级的示例。创建置备程序时，您可以指定竞价型、按需型或两者兼而有之（如下所示）。[当您同时指定两者时，如果 pod 没有明确指定需要使用 Spot 还是按需，则在使用分配策略配置节点时，Karpenter 会优先考虑 Spot。price-capacity-optimization ](https://aws.amazon.com/blogs/compute/introducing-price-capacity-optimized-allocation-strategy-for-ec2-spot-instances/)

```
apiVersion: karpenter.sh/v1
kind: Provisioner
metadata:
  name: spot-prioritized
spec:
  requirements:
    - key: "karpenter.sh/capacity-type"
      operator: In
        values: ["spot", "on-demand"]
```

### Savings Plans、预留实例和 AWS EDP
<a name="_savings_plans_reserved_instances_and_aws_edp"></a>

您可以使用计算[节省计划来减少计算](https://aws.amazon.com/savingsplans/compute-pricing/)支出。节省计划为 1 年或 3 年的计算使用承诺提供更低的价格。该用法可以适用于 EKS 集群中的 EC2 实例，但也适用于任何计算用量，例如 Lambda 和 Fargate。通过节省计划，您可以降低成本，并且仍然可以在承诺期内选择任何 EC2 实例类型。

计算节省计划可以将 EC2 成本降低多达 66%，而无需承诺要使用的实例类型、系列或区域。在您使用实例时，节省的费用会自动应用于实例。

EC2 Instance Savings Plans 承诺使用特定地区和 EC2 系列（例如 C 系列的实例），可节省高达 72% 的计算费用。您可以将使用量转移到该区域内的任何可用区，使用任何一代的实例系列，例如 c5 或 c6，并使用该系列中任意大小的实例。折扣将自动应用于您账户中符合储蓄计划标准的任何实例。

 [预留实例](https://aws.amazon.com/ec2/pricing/reserved-instances/)与 Instance EC2 Savings Plan 类似，但与按需实例相比，它们还可以保证可用区或区域的容量，并可降低高达 72% 的成本。计算出需要多少预留容量后，您可以选择要保留多长时间（1 年或 3 年）。当您在账户中运行这些 EC2 实例时，折扣将自动生效。

客户还可以选择与 AWS 签订企业协议。企业协议让客户可以选择定制最适合其需求的协议。客户可以享受基于 AWS EDP（企业折扣计划）的定价折扣。有关企业协议的更多信息，请联系您的 AWS 销售代表。

### 按需型
<a name="_on_demand"></a>

与现货相比，按需 EC2 实例具有无中断可用性的优势，而且与储蓄计划相比，无需长期承诺。如果您想降低集群成本，则应减少按需 EC2 实例的使用量。

优化工作负载要求后，您应该能够计算出集群的最小和最大容量。这个数字可能会随着时间的推移而变化，但很少会下降。考虑对低于最低限额的所有内容使用 Savings Plan，并选择不会影响应用程序可用性的容量。任何其他可能无法持续使用或可用性所必需的东西都可以按需使用。

如本节所述，减少使用量的最佳方法是消耗更少的资源，并最大限度地利用您配置的资源。使用集群自动扩缩器，您可以使用该设置删除未充分利用的节点。`scale-down-utilization-threshold`使用 Karpenter 时，建议启用整合。

要手动识别可用于您的工作负载的 EC2 实例类型，您应该使用 [ec2-instance-selec](https://github.com/aws/amazon-ec2-instance-selector) tor，它可以显示每个区域中可用的实例以及与 EKS 兼容的实例。具有 x86 进程架构、4 Gb 内存、2 v CPUs 且在 us-east-1 区域可用的实例的用法示例。

```
ec2-instance-selector --memory 4 --vcpus 2 --cpu-architecture x86_64 \
  -r us-east-1 --service eks
c5.large
c5a.large
c5ad.large
c5d.large
c6a.large
c6i.large
t2.medium
t3.medium
t3a.medium
```

对于非生产环境，您可以在夜间和周末等未使用的时间自动缩小集群。kubecost 项目[集群关闭就是](https://github.com/kubecost/cluster-turndown)控制器的一个示例，它可以根据设定的时间表自动缩小集群。

### Fargate 计算
<a name="_fargate_compute"></a>

Fargate 计算是 EKS 集群的完全托管计算选项。它通过在 Kubernetes 集群中为每个节点调度一个容器来提供容器隔离。它允许您根据工作负载的 CPU 和 RAM 要求调整计算节点的大小，从而严格控制集群中的工作负载使用情况。

Fargate 可以将工作负载扩展到 0.25 vCPU，内存为 0.5 GB，内存为 120 GB，内存可扩展至 16 个 vCPU。[容器大小可用的变体](https://docs.aws.amazon.com/eks/latest/userguide/fargate-pod-configuration.html)数量有限制，您需要了解您的工作负载如何最适合 Fargate 配置。例如，如果您的工作负载需要 1 个 vCPU 和 0.5 GB 内存，那么最小的 Fargate 容器将是 1 个 vCPU 和 2 GB 内存。

尽管 Fargate 有许多好处，例如无需 EC2 实例或操作系统管理，但由于每个部署的 Pod 都作为集群中的单独节点隔离，因此它可能需要比传统 EC2 实例更多的计算容量。这需要对诸如 Kubelet、日志代理以及通常 DaemonSets 要部署到节点的任何东西进行更多的复制。 DaemonSets 在 Fargate 中不支持它们，需要将其转换为 pod “`sidecars” 并与应用程序一起运行。

Fargate 无法从 bin 打包或 CPU 过度配置中受益，因为工作负载的边界是一个不可突发的节点，也不能在工作负载之间共享。Fargate 将为您节省 EC2 实例管理时间，而这本身就是有成本的，但是 CPU 和内存成本可能比其他 EC2 容量类型更昂贵。Fargate pod 可以利用计算节省计划来降低按需成本。

## 优化计算使用率
<a name="_optimize_compute_usage"></a>

在计算基础设施上节省资金的另一种方法是为工作负载使用更高效的计算。这可能来自性能更高的通用计算，例如 [Graviton处理器](https://aws.amazon.com/ec2/graviton/)，它比x86便宜20％，能效高60％，或者工作负载特定的加速器，例如和。 GPUs [FPGAs](https://aws.amazon.com/ec2/instance-types/f1/)你需要构建可以[在 arm 架构上运行](https://aws.amazon.com/blogs/containers/how-to-build-your-containers-for-arm-and-save-with-graviton-and-spot-instances-on-amazon-ecs/)的容器，并为你的工作负载[设置带有正确加速器的节点](https://aws.amazon.com/blogs/compute/running-gpu-accelerated-kubernetes-workloads-on-p3-and-p2-ec2-instances-with-amazon-eks/)。

EKS 能够运行混合架构的集群（例如 amd64 和 arm64），如果您的容器是针对多个架构编译的，则可以通过在配置器中允许这两种架构来利用带有 Karpenter 的 Graviton 处理器。但是，为了保持稳定的性能，建议您将每个工作负载保持在单个计算架构上，并且仅在没有额外容量可用时才使用不同的架构。

Provisioner 可以配置多个架构，工作负载也可以在其工作负载规格中请求特定的架构。

```
apiVersion: karpenter.sh/v1
kind: Provisioner
metadata:
  name: default
spec:
  requirements:
  - key: "kubernetes.io/arch"
    operator: In
    values: ["arm64", "amd64"]
```

使用 Cluster Autoscaler，你需要为 Graviton 实例创建一个节点组，并[对工作负载设置节点容忍度才能利用新的容量](https://kubernetes.io/docs/concepts/scheduling-eviction/taint-and-toleration/)。

GPUs 并 FPGAs 可以大大提高工作负载的性能，但是需要优化工作负载才能使用加速器。机器学习和人工智能的许多工作负载类型 GPUs 可用于计算，并且可以使用资源请求将实例添加到集群并安装到工作负载中。

```
spec:
  template:
    spec:
    - containers:
      ...
      resources:
          limits:
            nvidia.com/gpu: "1"
```

某些 GPU 硬件可以在多个工作负载之间共享，因此可以配置和使用单个 GPU。要了解如何配置工作负载 GPU 共享，请参阅[虚拟 GPU 设备插件](https://aws.amazon.com/blogs/opensource/virtual-gpu-device-plugin-for-inference-workload-in-kubernetes/)了解更多信息。您也可以参考以下博客：
+  [使用 NVIDIA 时间切片和加速实例在 Amazon EKS 上共享 GPU EC2 ](https://aws.amazon.com/blogs/containers/gpu-sharing-on-amazon-eks-with-nvidia-time-slicing-and-accelerated-ec2-instances/) 
+  [在 Amazon EKS 上使用 NVIDIA 的多实例 GPU（MIG），最大限度地提高 GPU 利用率：让每个 GPU 运行更多容器组（pod）以增强性能](https://aws.amazon.com/blogs/containers/maximizing-gpu-utilization-with-nvidias-multi-instance-gpu-mig-on-amazon-eks-running-more-pods-per-gpu-for-enhanced-performance/) 

# 成本优化-联网
<a name="cost-opt-networking"></a>

架构系统以实现高可用性 (HA) 是实现弹性和容错能力的最佳实践。实际上，这意味着将您的工作负载和底层基础设施分散到给定 AWS 区域的多个可用区 (AZs)。确保您的 Amazon EKS 环境具备这些特性将增强系统的整体可靠性。除此之外，您的 EKS 环境也可能由各种结构（即 VPCs）、组件（即）和集成（即 ECR 和其他容器注册表 ELBs）组成。

高可用性系统和其他特定用例组件的组合可以在数据的传输和处理方式中发挥重要作用。这反过来又会影响数据传输和处理所产生的成本。

下面详细介绍的实践将帮助您设计和优化 EKS 环境，从而实现不同领域和用例的成本效益。

## Pod 到 Pod 通信
<a name="_pod_to_pod_communication"></a>

根据您的设置，Pod 之间的网络通信和数据传输可能会对运行 Amazon EKS 工作负载的总体成本产生重大影响。本节将介绍降低与 pod 间通信相关的成本的不同概念和方法，同时考虑高可用性 (HA) 架构、应用程序性能和弹性。

### 限制流向可用区的流量
<a name="_restricting_traffic_to_an_availability_zone"></a>

Kubernetes 项目很早就开始开发拓扑感知结构，包括 kubernetes 等标签。 io/hostname, topology.kubernetes.io/region, and topology.kubernetes.io/zone分配给节点以启用诸如跨故障域分配工作负载和拓扑感知卷配置器之类的功能。在 Kubernetes 1.17 中毕业后，这些标签还被用来为 Pod 到 Pod 的通信启用拓扑感知路由功能。

以下是一些策略，说明如何控制 EKS 集群中 Pod 之间的跨可用区流量以降低成本并最大限度地减少延迟。

 *如果您想详细了解集群中 Pod 之间的跨可用区流量（例如[以字节为单位传输的数据量），请参阅这](https://aws.amazon.com/blogs/containers/getting-visibility-into-your-amazon-eks-cross-az-pod-to-pod-network-bytes/)篇文章。*

![\[拓扑感知路由\]](http://docs.aws.amazon.com/zh_cn/eks/latest/best-practices/images/topo_aware_routing.png)


如上图所示，服务是稳定的网络抽象层，用于接收发往您的 Pod 的流量。创建服务时， EndpointSlices 会创建多个服务。每个端点 EndpointSlice 都有一份端点列表，其中包含 Pod 地址的子集，以及它们正在运行的节点和任何其他拓扑信息。在使用 Amazon VPC CNI 时，kube-proxy（在每个节点上运行的守护进程集）会维护网络规则以启用 Pod 通信和服务发现（基于 EBPF 的替代方案可能不使用 kube-p CNIs roxy 但提供等效行为）。它起到了内部路由的作用，但它是根据它从创建的路由中消耗的资源来实现的。 EndpointSlices

在 EKS 上，kube-proxy 主要使用 iptables NAT 规则（或 [IPVS [NFTables](https://kubernetes.io/blog/2025/02/28/nftables-kube-proxy/)](https://docs.aws.amazon.com/eks/latest/best-practices/ipvs.html)作为替代方案）在集群中的所有 Pod 之间分配流量，无论它们的节点或可用区位置如何。这种默认分布可能导致跨可用区流量路由，从而可能导致敏感应用程序的延迟增加和大型部署中的可用区间数据传输费用。

 **使用拓扑感知路由（以前称为拓扑感知提示）** 

在 Kubernetes 服务上启用和实现[https://kubernetes.io/docs/concepts/services-networking/topology-aware-routing/](https://kubernetes.io/docs/concepts/services-networking/topology-aware-routing/)后， EndpointSlice 控制器将按比例将端点分配给集群分布的不同区域。对于每个端点， EndpointSlice 控制器还将为该区域设置一个*提示*。*提示*描述了终端节点应为哪个区域提供流量。 `kube-proxy`然后会根据应用的*提示*将流量从区域路由到终端节点。

下图显示了如何 EndpointSlices 以这样的方式组织提示，即`kube-proxy`可以根据其区域原点知道它们应该去哪个目的地。如果没有提示，就没有这样的分配或组织，无论流量来自哪里，都会被代理到不同的区域目的地。

![\[端点切片\]](http://docs.aws.amazon.com/zh_cn/eks/latest/best-practices/images/endpoint_slice.png)


在某些情况下， EndpointSlice 控制器可能会为不同的区域应用*提示*，这意味着该端点最终可能会为来自不同区域的流量提供服务。这样做的原因是要尝试在不同区域的端点之间保持流量均匀分布。

以下是有关如何为服务启用*拓扑感知路由*的代码片段。

```
apiVersion: v1
kind: Service
metadata:
  name: orders-service
  namespace: ecommerce
  annotations:
    service.kubernetes.io/topology-mode: Auto
spec:
  selector:
    app: orders
  type: ClusterIP
  ports:

* protocol: TCP
port: 3003
targetPort: 3003
```

下面的屏幕截图显示了 EndpointSlice 控制器成功向在 AZ 中运行的 Pod 副本的终端节点应用提示的结果`eu-west-1a`。

![\[切片外壳\]](http://docs.aws.amazon.com/zh_cn/eks/latest/best-practices/images/slice_shell.png)


**注意**  
值得注意的是，拓扑感知路由仍处于测试阶段。在整个集群拓扑结构中均匀分布的工作负载时，此功能的性能更具可预测性，因为控制器在各个区域之间按比例分配端点，但是当区域中的节点资源过于不平衡而无法避免过度过载时，可能会跳过提示分配。因此，强烈建议将其与提高应用程序可用性的调度约束（例如 [Pod 拓扑分布限制](https://kubernetes.io/docs/concepts/scheduling-eviction/topology-spread-constraints/)）结合使用。请注意，当容量跨区域波动时（例如使用 [Amazon EC2 竞价型实例](https://aws.amazon.com/ec2/spot/)时），也可能无法分配提示，因为在计算比例分布时不会实时检测到中断或替换。

 **使用流量分配** 

[流量分布在 Kubernetes 1.30 中引入，在 1.33 中正式推出，它为同区域流量偏](https://kubernetes.io/docs/reference/networking/virtual-ips/#traffic-distribution)好提供了一种更简单的拓扑感知路由替代方案。虽然拓扑感知路由尝试使用智能的流量路由方法来避免端点过载，但它导致了不可预测的行为。相反，流量分配优先考虑可预测性。该 PreferClose 选项指示 kube-proxy 创建规则，根据控制器设置的区域*提示*，首先将流量路由到同区域端点。 EndpointSlice 当没有同区域终端节点可用时，它会回退为在服务的所有集群终端节点之间分配流量。此功能专为那些接受权衡取舍的工作负载而设计，即优化邻近性，而不是像拓扑感知路由那样尝试均匀分配负载。

以下是有关如何为服务启用*流量分配*的代码片段。

```
apiVersion: v1
kind: Service
metadata:
  name: orders-service
  namespace: ecommerce
spec:
  trafficDistribution: PreferClose
  selector:
    app: orders
  type: ClusterIP
  ports:

* protocol: TCP
port: 3003
targetPort: 3003
```

启用流量分布时，会出现一个常见的难题：如果大多数流量来自同一个区域，则单个可用区内的端点可能会过载。这种重载可能会造成重大问题：
+ 管理多可用区部署的单个水平 Pod Autoscaler (HPA) 可以通过跨不同区域扩展 pod 来做出响应。 AZs但是，此操作无法有效解决受影响区域中增加的负载。
+ 这种情况反过来会导致资源效率低下。当像 Karpenter 这样的集群自动扩缩器检测到不同的 pod 横向扩展时 AZs，它们可能会在未受影响的 AZs节点中配置其他节点，从而导致不必要的资源分配。

要克服这一挑战：
+ 为每个区域创建单独的部署，这些部署 HPAs 可以相互独立扩展。
+ 利用拓扑分布约束来确保工作负载分布在整个集群中，这有助于防止高流量区域中的端点过载。

 **使用自动扩缩器：将节点配置到特定的可用区** 

 *我们强烈建议您在*多个高度可用的环境中运行您的工作负载 AZs。这可以提高应用程序的可靠性，尤其是在可用区出现问题时。如果您愿意为了降低网络相关成本而牺牲可靠性，则可以将节点限制为单个可用区。

要在同一个可用区中运行所有 Pod，要么在同一个可用区中配置工作节点，要么将 Pod 调度到在同一个可用区上运行的工作节点上。要在单个可用区内配置节点，请使用[集群自动扩缩器 (](https://github.com/kubernetes/autoscaler/tree/master/cluster-autoscaler)CA) 定义一个子网属于同一可用区的节点组。对于 [Karpenter，](https://karpenter.sh/)请使用`topology.kubernetes.io/zone`并指定要在其中创建工作节点的可用区。例如，下面的 Karpenter 配置程序片段配置了 us-west-2a AZ 中的节点。

 **Karpenter** 

```
apiVersion: karpenter.sh/v1
kind: Provisioner
metadata:
name: single-az
spec:
  requirements:

* key: "topology.kubernetes.io/zone"`
operator: In
values: ["us-west-2a"]
```

 **集群自动扩缩器 (CA)** 

```
apiVersion: eksctl.io/v1alpha5
kind: ClusterConfig
metadata:
  name: my-ca-cluster
  region: us-east-1
  version: "1.21"
availabilityZones:

* us-east-1a
managedNodeGroups:
* name: managed-nodes
labels:
  role: managed-nodes
instanceType: t3.medium
minSize: 1
maxSize: 10
desiredCapacity: 1
...
```

 **使用 Pod 分配和节点亲和性** 

或者，如果您有多个 AZs工作节点运行，则每个节点的标签都将标有 *[topology.kubernetes.io/zone 以及其可用区的值（例如 us-](http://topology.kubernetes.io/zone%E2%80%9D)* west-2a 或 us-west-2b）。您可以利用`nodeSelector`或将 Pod 调度`nodeAffinity`到单个可用区中的节点。例如，以下清单文件会将 Pod 调度到在 AZ us-west-2a 中运行的节点内。

```
apiVersion: v1
kind: Pod
metadata:
  name: nginx
  labels:
    env: test
spec:
  nodeSelector:
    topology.kubernetes.io/zone: us-west-2a
  containers:

* name: nginx
image: nginx
imagePullPolicy: IfNotPresent
```

### 限制流向节点的流量
<a name="_restricting_traffic_to_a_node"></a>

在某些情况下，仅在区域级别限制流量是不够的。除了降低成本外，您可能还需要降低某些经常相互通信的应用程序之间的网络延迟。为了实现最佳网络性能并降低成本，您需要一种方法来限制特定节点的流量。例如，即使在高可用性 (HA) 设置中，微服务 A 也应始终在节点 1 上与微服务 B 通信。让节点 1 上的微服务 A 与节点 2 上的微服务 B 通信可能会对这种性质的应用程序的预期性能产生负面影响，尤其是在节点 2 完全位于单独的可用区时。

 **使用服务内部流量策略** 

为了限制流向节点的 Pod 网络流量，你可以使用*[服务内部流量策略](https://kubernetes.io/docs/concepts/services-networking/service-traffic-policy/)*。默认情况下，发送到工作负载服务的流量将随机分布在生成的不同端点上。因此，在 HA 架构中，这意味着来自微服务 A 的流量可以流向不同节点上任何给定节点上的微服务 B 的任何副本。 AZs但是，当服务的内部流量策略设置为`Local`时，流量将仅限于流量来源节点上的端点。此政策规定只能使用节点本地端点。这意味着，该工作负载的网络流量相关成本将低于分布在集群范围内的成本。此外，延迟会降低，从而提高应用程序的性能。

**注意**  
需要注意的是，此功能不能与 Kubernetes 中的拓扑感知路由结合使用。

![\[本地内部流量\]](http://docs.aws.amazon.com/zh_cn/eks/latest/best-practices/images/local_traffic.png)


以下是有关如何为服务设置*内部流量策略*的代码片段。

```
apiVersion: v1
kind: Service
metadata:
  name: orders-service
  namespace: ecommerce
spec:
  selector:
    app: orders
  type: ClusterIP
  ports:

* protocol: TCP
port: 3003
targetPort: 3003
  internalTrafficPolicy: Local
```

为避免应用程序因流量下降而出现意外行为，应考虑以下方法：
+ 为每个通信的 Pod 运行足够的副本
+ 使用[拓扑分布约束让 Pod 分布](https://kubernetes.io/docs/concepts/scheduling-eviction/topology-spread-constraints/)相对均匀 
+ 利用 [pod 关联性规则对通信 Pod](https://kubernetes.io/docs/concepts/scheduling-eviction/assign-pod-node/#inter-pod-affinity-and-anti-affinity) 进行同地定位

在此示例中，您有 2 个微服务 A 副本和 3 个微服务 B 副本。如果微服务 A 的副本分布在节点 1 和节点 2 之间，而微服务 B 的 3 个副本全部位于节点 3 上，则由于内部流量策略，它们将无法通信。`Local`当没有可用的节点本地端点时，流量将被丢弃。

![\[node-local_no_peer\]](http://docs.aws.amazon.com/zh_cn/eks/latest/best-practices/images/no_node_local_1.png)


如果微服务 B 的 3 个副本中的 2 个位于节点 1 和 2 上，则对等应用程序之间将进行通信。但是你仍然会有一个微服务 B 的隔离副本，没有任何对等副本可以与之通信。

![\[node-local_with_peer\]](http://docs.aws.amazon.com/zh_cn/eks/latest/best-practices/images/no_node_local_2.png)


**注意**  
在某些情况下，像上图所示的隔离副本如果仍有用途（例如处理来自外部传入流量的请求），则可能不会引起担忧。

 **使用具有拓扑分布约束的服务内部流量策略** 

将*内部流量策略*与*拓扑分布限制*结合使用可能有助于确保您拥有正确数量的副本，以便在不同节点上通信微服务。

```
apiVersion: apps/v1
kind: Deployment
metadata:
  name: express-test
spec:
  replicas: 6
  selector:
    matchLabels:
      app: express-test
  template:
    metadata:
      labels:
        app: express-test
        tier: backend
    spec:
      topologySpreadConstraints:
      - maxSkew: 1
        topologyKey: "topology.kubernetes.io/zone"
        whenUnsatisfiable: ScheduleAnyway
        labelSelector:
          matchLabels:
            app: express-test
```

 **将服务内部流量策略与 Pod 关联性规则配合使用** 

另一种方法是在使用服务内部流量策略时使用 Pod 关联性规则。借助 Pod 亲和性，你可以影响调度器将某些 Pod 放在同一个位置，因为它们经常通信。通过对某些 Pod 应用严格的调度约束 (`requiredDuringSchedulingIgnoredDuringExecution`)，当调度器将 Pod 放在节点上时，这将为你提供 Pod 托管的更好结果。

```
apiVersion: apps/v1
kind: Deployment
metadata:
  name: graphql
  namespace: ecommerce
  labels:
    app.kubernetes.io/version: "0.1.6"
    ...
    spec:
      serviceAccountName: graphql-service-account
      affinity:
        podAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: app
                operator: In
                values:
                - orders
            topologyKey: "kubernetes.io/hostname"
```

## Load Balancer 到 Pod 通信
<a name="_load_balancer_to_pod_communication"></a>

EKS 工作负载通常由负载均衡器前置，该负载均衡器将流量分配到 EKS 集群中的相关 Pod。您的架构可能包括面向 and/or 外部的内部负载均衡器。根据您的架构和网络流量配置，负载均衡器与 Pod 之间的通信可能会导致大量的数据传输费用。

您可以使用 [AWS Load Balancer 控制器](https://kubernetes-sigs.github.io/aws-load-balancer-controller)自动管理 ELB 资源（ALB 和 NLB）的创建。在此类设置中产生的数据传输费用将取决于网络流量所采用的路径。AWS Load Balancer 控制器支持两种网络流量*模式，即实例*模式和 *IP 模式*。

使用*实例模式*时， NodePort 将在您的 EKS 集群中的每个节点上打开。然后，负载均衡器将均匀地代理节点间的流量。如果节点上运行了目标 Pod，则不会产生数据传输费用。但是，如果目标 Pod 与 NodePort 接收流量的 Pod 位于不同的节点和不同的可用区中，则从 kube-proxy 到目标 Pod 将有额外的网络跳跃。在这种情况下，将收取跨可用区数据传输费用。由于流量分布均匀，从 kube-proxy 到相关目标 Pod 的跨区域网络流量跳跃很可能会产生额外的数据传输费用。

下图描绘了流量从负载均衡器流向另一可用区中单独节点上的目标 Pod NodePort，然后从负载均衡器流`kube-proxy`向目标 Pod 的网络路径。这是*实例模式*设置的示例。

![\[LB 到 Pod\]](http://docs.aws.amazon.com/zh_cn/eks/latest/best-practices/images/lb_2_pod.png)


使用 *IP 模式*时，网络流量会直接从负载均衡器代理到目标 Pod。因此，这种方法*不涉及数据传输费用*。

**注意**  
建议您将负载均衡器设置为 *IP 流量模式*，以降低数据传输费用。在此设置中，确保您的负载均衡器部署在您的 VPC 中的所有子网中也很重要。

下图描绘了在网络 *IP 模式*下从负载均衡器流向 Pod 的流量的网络路径。

![\[IP 模式\]](http://docs.aws.amazon.com/zh_cn/eks/latest/best-practices/images/ip_mode.png)


## 从容器注册表传输数据
<a name="_data_transfer_from_container_registry"></a>

### Amazon ECR
<a name="_amazon_ecr"></a>

向 Amazon ECR 私有注册表传输数据是免费的。*区域内数据传输不产生任何费用*，但传输到互联网和跨区域的数据传输将按传输双方的互联网数据传输费率收费。

您应该利用 ECRs 内置的[映像复制功能](https://docs.aws.amazon.com/AmazonECR/latest/userguide/replication.html)将相关的容器镜像复制到与您的工作负载相同的区域。这样，复制只需支付一次费用，并且所有相同的区域（区域内）图像拉取都将是免费的。

通过*使用接[口 VPC 终端节点](https://docs.aws.amazon.com/whitepapers/latest/aws-privatelink/what-are-vpc-endpoints.html)连接到区域内* ECR 存储库，可以进一步降低与从 ECR 提取映像（数据传出）相关的数据传输成本。连接到 ECR 的公有 AWS 终端节点（通过 NAT 网关和 Internet Gateway）的替代方法将产生更高的数据处理和传输成本。下一节将更详细地介绍如何降低您的工作负载和 AWS 服务之间的数据传输成本。

如果您运行的工作负载包含特别大的映像，则可以使用预先缓存的容器映像构建自己的自定义 Amazon 系统映像 (AMIs)。这可以减少初始映像提取时间和从容器注册表到 EKS 工作节点的潜在数据传输成本。

## 将数据传输到互联网和 AWS 服务
<a name="_data_transfer_to_internet_aws_services"></a>

通过互联网将 Kubernetes 工作负载与其他 AWS 服务或第三方工具和平台集成，这是一种常见的做法。用于将流量路由到相关目的地的底层网络基础设施可能会影响数据传输过程中产生的成本。

### 使用 NAT 网关
<a name="_using_nat_gateways"></a>

NAT 网关是执行网络地址转换 (NAT) 的网络组件。下图描绘了 EKS 集群中的 Pod 与其他 AWS 服务（亚马逊 ECR、DynamoDB 和 S3）和第三方平台通信。在此示例中，Pod 分别 AZs在私有子网中运行。为了发送和接收来自互联网的流量，需要将 NAT 网关部署到一个可用区的公有子网中，从而允许任何具有私有 IP 地址的资源共享一个公有 IP 地址来访问互联网。反过来，此 NAT 网关与 Internet Gateway 组件通信，允许将数据包发送到其最终目的地。

![\[NAT 网关\]](http://docs.aws.amazon.com/zh_cn/eks/latest/best-practices/images/nat_gw.png)


在此类用例中使用 NAT 网关时，*您可以通过在每个可用区部署一个 NAT 网关来最大限度地降低数据传输成本*。这样，路由到互联网的流量将通过同一可用区中的 NAT 网关，从而避免可用区间的数据传输。但是，尽管您可以节省可用区间数据传输的成本，但这种设置的含义是，您的架构中会产生额外的 NAT 网关的成本。

这种推荐的方法如下图所示。

![\[推荐方法\]](http://docs.aws.amazon.com/zh_cn/eks/latest/best-practices/images/recommended_approach.png)


### 使用 VPC 终端节点
<a name="_using_vpc_endpoints"></a>

为了进一步降低此类架构的成本，*您应该使用 [VPC 终端节点](https://docs.aws.amazon.com/whitepapers/latest/aws-privatelink/what-are-vpc-endpoints.html)在工作负载和 AWS 服务之间建立连接*。VPC 终端节点允许您从 VPC 内部访问 AWS 服务，无需 data/network 数据包通过互联网。所有流量均为内部流量并保持在 AWS 网络内。VPC 终端节点有两种类型：接口 VPC 终端节点（[受许多 AWS 服务支持](https://docs.aws.amazon.com/vpc/latest/privatelink/aws-services-privatelink-support.html)）和网关 VPC 终端节点（仅受 S3 和 DynamoDB 支持）。

 **网关 VPC 终端节点** 

 *网关 VPC 终端节点不收取每小时费用或数据传输费用*。使用网关 VPC 终端节点时，请务必注意，它们不能跨越 VPC 边界扩展。它们不能用于 VPC 对等互连、VPN 网络或通过 Direct Connect。

 **接口 VPC 终端节点** 

VPC 终端节点[按小时收费](https://aws.amazon.com/privatelink/pricing/)，通过底层 ENI 进行数据处理需要支付额外费用。请注意，可用区间数据传输[不收费](https://aws.amazon.com/about-aws/whats-new/2022/04/aws-data-transfer-price-reduction-privatelink-transit-gateway-client-vpn-services/)。

下图显示了通过 VPC 终端节点与 AWS 服务通信的 Pod。

![\[VPC 端点\]](http://docs.aws.amazon.com/zh_cn/eks/latest/best-practices/images/vpc_endpoints.png)


## 之间的数据传输 VPCs
<a name="_data_transfer_between_vpcs"></a>

在某些情况下，不同的 VPC（在同一 AWS 区域内）中可能有工作负载需要相互通信。这可以通过允许流量通过连接到相应VPC的互联网网关穿越公共互联网来实现。可以通过在公有子网中部署 EC2 实例、NAT 网关或 NAT 实例等基础设施组件来启用此类通信。但是，包含这些组件的设置将产生 processing/transferring 数据进出 VPCs费用。如果进出分开的流量 VPCs 正在流过 AZs，则数据传输将额外收费。下图描绘了一种使用 NAT 网关和 Internet 网关在不同 VPCs工作负载之间建立通信的设置。

![\[之间 VPCs\]](http://docs.aws.amazon.com/zh_cn/eks/latest/best-practices/images/between_vpcs.png)


### VPC 对等连接
<a name="_vpc_peering_connections"></a>

要降低此类用例的成本，您可以使用 [VPC 对等连接](https://docs.aws.amazon.com/vpc/latest/peering/what-is-vpc-peering.html)。使用 VPC 对等连接时，停留在同一可用区内的网络流量无需支付数据传输费用。如果交通过境 AZs，则会产生费用。不过，建议使用 VPC 对等互连方法，以便在同一 AWS 区域 VPCs 内的不同工作负载之间进行经济高效的通信。但是，需要注意的是，VPC 对等互连主要对 1:1 VPC 连接有效，因为它不允许传输网络。

下图是通过 VPC 对等连接进行工作负载通信的高级表示。

![\[对等连接\]](http://docs.aws.amazon.com/zh_cn/eks/latest/best-practices/images/peering.png)


### 可传递网络连接
<a name="_transitive_networking_connections"></a>

如上一节所述，VPC 对等连接不允许传输网络连接。如果您想根据过渡网络要求连接 3 个或更多个 VPCs ，则应使用 T [ransit Gateway](https://docs.aws.amazon.com/vpc/latest/tgw/what-is-transit-gateway.html) (TGW)。这将使您能够克服 VPC 对等互连的限制或与在多个 VPC 对等连接之间建立多个 VPC 对等连接相关的任何运营开销。 VPCs您按[小时计费，并按](https://aws.amazon.com/transit-gateway/pricing/)发送到 TGW 的数据收费。*流经TGW的可用区间流量不产生任何目标成本。*

下图显示了不同 VPCs 但位于相同 AWS 区域内的不同工作负载之间通过 TGW 的可用区间流量。

![\[可传递的\]](http://docs.aws.amazon.com/zh_cn/eks/latest/best-practices/images/transititive.png)


## 使用服务网格
<a name="_using_a_service_mesh"></a>

服务网格提供强大的联网功能，可用于降低 EKS 集群环境中的网络相关成本。但是，如果您采用服务网格，则应仔细考虑服务网格会给您的环境带来的操作任务和复杂性。

### 限制流向可用区的流量
<a name="_restricting_traffic_to_availability_zones"></a>

 **使用 Istio 的局部加权分布** 

Istio 使您能够在路由发生*后*将网络策略应用于流量。这是使用[目的地规则](https://istio.io/latest/docs/reference/config/networking/destination-rule/)（例如[地点加权分布](https://istio.io/latest/docs/tasks/traffic-management/locality-load-balancing/distribute/)）完成的。使用此功能，您可以根据流量来源控制可以前往某个目的地的流量的权重（以百分比表示）。这种流量的来源可以来自外部（或面向公众）的负载均衡器，也可以来自集群本身的 Pod。当所有 Pod 端点都可用时，将根据加权轮询负载平衡算法选择地点。如果某些端点运行状况不佳或不可用，则[会自动调整区域权重](https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/upstream/load_balancing/locality_weight.html)，以反映可用端点的这种变化。

**注意**  
在实施区域加权分布之前，您应该首先了解您的网络流量模式以及目标规则策略可能对应用程序行为产生的影响。因此，使用诸如 [AWS X-Ray](https://aws.amazon.com/xray/) 或 [Jaeg](https://www.jaegertracing.io/) er 之类的工具建立分布式跟踪机制非常重要。

上面详述的 Istio 目标规则也可以应用于管理从负载均衡器到 EKS 集群中 Pod 的流量。本地加权分配规则可以应用于从高可用性负载均衡器（特别是 Ingress Gateway）接收流量的服务。这些规则允许您根据其区域来源（在本例中为负载均衡器）来控制流量流向何处。如果配置正确，与将流量均匀或随机分配到不同的 Pod 副本的负载均衡器相比，跨区域的出口流量将更少。 AZs

以下是 Istio 中目标规则资源的代码块示例。如下所示，该资源为来自该区域 3 个不同 AZs `eu-west-1`地区的传入流量指定了加权配置。这些配置声明，来自给定可用区的大部分传入流量（在本例中为 70%）应代理到其来源的同一个可用区中的目的地。

```
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
  name: express-test-dr
spec:
  host: express-test.default.svc.cluster.local
  trafficPolicy:
    loadBalancer:                      +
      localityLbSetting:
        distribute:
        - from: eu-west-1/eu-west-1a/  +
          to:
            "eu-west-1/eu-west-1a/_": 70
            "eu-west-1/eu-west-1b/_": 20
            "eu-west-1/eu-west-1c/_": 10
        - from: eu-west-1/eu-west-1b/_  +
          to:
            "eu-west-1/eu-west-1a/_": 20
            "eu-west-1/eu-west-1b/_": 70
            "eu-west-1/eu-west-1c/_": 10
        - from: eu-west-1/eu-west-1c/_  +
          to:
            "eu-west-1/eu-west-1a/_": 20
            "eu-west-1/eu-west-1b/_": 10
            "eu-west-1/eu-west-1c/*": 70**
    connectionPool:
      http:
        http2MaxRequests: 10
        maxRequestsPerConnection: 10
    outlierDetection:
      consecutiveGatewayErrors: 1
      interval: 1m
      baseEjectionTime: 30s
```

**注意**  
可以分配到目的地的最小权重为 1%。这样做的原因是为了维护故障转移区域和区域，以防主目标中的终端节点运行状况不佳或不可用。

下图描绘了一个场景，其中 eu *-west-1* 区域中有一个高可用性负载均衡器，并应用了地区加权分布。此图表的目标规则策略配置为将来自 eu-west-1a 的流量的 60% 发送到同一个可用区中的 Pod，而来自 e *u-west-1a* 的流量中有 40% 应发送到 e *u-west-* 1b 中的 Pod。

![\[istop 交通管制\]](http://docs.aws.amazon.com/zh_cn/eks/latest/best-practices/images/istio-traffic-control.png)


### 限制流向可用区和节点的流量
<a name="_restricting_traffic_to_availability_zones_and_nodes"></a>

 **在 Istio 中使用服务内部流量策略** 

*为了降低与*外部*传入流量和 Pod 之间的*内部*流量相关的网络成本，您可以将 Istio 的目标规则和 Kubernetes 服务内部流量策略结合起来。*将 Istio 目标规则与服务内部流量策略相结合的方法在很大程度上取决于三件事：
+ 微服务的作用
+ 跨微服务的网络流量模式
+ 如何在 Kubernetes 集群拓扑中部署微服务

下图显示了嵌套请求情况下的网络流会是什么样子，以及上述策略将如何控制流量。

![\[外部和内部流量政策\]](http://docs.aws.amazon.com/zh_cn/eks/latest/best-practices/images/external-and-internal-traffic-policy.png)


1. 最终用户向**应用程序 A 发出请求，而应用程序 A** 又向 **AP C** 发出嵌套请求。 此请求首先发送到高可用性负载均衡器，该负载均衡器在可用区 1 和可用区 2 中都有实例，如上图所示。

1. 然后，Istio 虚拟服务会将外部传入的请求路由到正确的目的地。

1. 请求被路由后，Istio 目标规则 AZs 根据请求的来源（AZ 1 或 AZ 2）控制流向相应请求的流量。

1. 然后，流量会进入**应用程序 A** 的服务，然后被代理到相应的 Pod 端点。如图所示，80% 的传入流量发送到可用区 1 中的 Pod 终端节点，20% 的传入流量发送到可用区 2。

1.  然后**，应用程序 A** 向**应用程序 C** 发出内部请求。 **APP C** 的服务启用了内部流量策略 (`internalTrafficPolicy``: Local`)。

1. 由于 **APP C 有可用的节点本地端点，因此从 APP A****（在节点 1** **上）向 AP **P** C** 发出的内部请求是成功的。

1. 从**应用程序 A**（在**节点 3 上）向**应用程序 C** 发出的内部请求失败，因为**应用程序** C 没有可用的节点***本地端点*。 如图所示，应用程序 C 在 NODE 3 上没有副本。 **\$1**

以下屏幕截图是从这种方法的真实示例中截取的。第一组屏幕截图演示了向节点`ip-10-0-0-151.af-south-1.compute.internal`上托管`orders`副本的成功外部请求`graphql`以及来自的成功嵌套请求。`graphql`

![\[Before\]](http://docs.aws.amazon.com/zh_cn/eks/latest/best-practices/images/before.png)


![\[在结果之前\]](http://docs.aws.amazon.com/zh_cn/eks/latest/best-practices/images/before-results.png)


使用 Istio，您可以验证和导出代理知道的任何[上游集群](https://www.envoyproxy.io/docs/envoy/latest/intro/arch_overview/intro/terminology)和终端节点的统计信息。这可以帮助了解网络流以及工作负载各服务之间的分布份额。继续使用相同的示例，可以使用以下命令获取`graphql`代理知道的`orders`端点：

```
kubectl exec -it deploy/graphql -n ecommerce -c istio-proxy -- curl localhost:15000/clusters | grep orders
```

```
...
orders-service.ecommerce.svc.cluster.local::10.0.1.33:3003::**rq_error::0**
orders-service.ecommerce.svc.cluster.local::10.0.1.33:3003::**rq_success::119**
orders-service.ecommerce.svc.cluster.local::10.0.1.33:3003::**rq_timeout::0**
orders-service.ecommerce.svc.cluster.local::10.0.1.33:3003::**rq_total::119**
orders-service.ecommerce.svc.cluster.local::10.0.1.33:3003::**health_flags::healthy**
orders-service.ecommerce.svc.cluster.local::10.0.1.33:3003::**region::af-south-1**
orders-service.ecommerce.svc.cluster.local::10.0.1.33:3003::**zone::af-south-1b**
...
```

在这种情况下，`graphql`代理只知道与其共享节点的副本的`orders`终端节点。如果您从 orders Service 中删除该`internalTrafficPolicy: Local`设置，然后重新运行类似于上面的命令，则结果将返回分布在不同节点上的副本的所有端点。此外，通过检查相应的`rq_total`端点，您会注意到网络分布的份额相对均匀。因此，如果端点与在不同区域中运行的上游服务相关联 AZs，则这种跨区域的网络分布将导致更高的成本。

如上文前一节所述，你可以利用 pod 的亲和力将频繁通信的 Pod 放在同一个地方。

```
...
spec:
...
  template:
    metadata:
      labels:
        app: graphql
        role: api
        workload: ecommerce
    spec:
      affinity:
        podAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
          - labelSelector:
              matchExpressions:
              - key: app
                operator: In
                values:
                - orders
            topologyKey: "kubernetes.io/hostname"
      nodeSelector:
        managedBy: karpenter
        billing-team: ecommerce
...
```

当`graphql`和`orders`副本不在同一个节点 (`ip-10-0-0-151.af-south-1.compute.internal`) 上共存时，第一个请求成功，如下面`graphql`的 Postman 屏幕截图所`200 response code`示，而第二个从`graphql`到的嵌套请求`orders`失败，结果为 a。`503 response code`

 ![\[After\]](http://docs.aws.amazon.com/zh_cn/eks/latest/best-practices/images/after.png) ![\[After results\]](http://docs.aws.amazon.com/zh_cn/eks/latest/best-practices/images/after-results.png) 

## 其他资源
<a name="_additional_resources"></a>
+  [使用 Istio 解决 EKS 上的延迟和数据传输成本](https://aws.amazon.com/blogs/containers/addressing-latency-and-data-transfer-costs-on-eks-using-istio/) 
+  [探索拓扑感知提示对亚马逊 Elastic Kubernetes Service 中网络流量的影响 Amazon Kubernetes Service](https://aws.amazon.com/blogs/containers/exploring-the-effect-of-topology-aware-hints-on-network-traffic-in-amazon-elastic-kubernetes-service/) 
+  [查看你的 Amazon EKS 跨可用区容器到容器网络字节](https://aws.amazon.com/blogs/containers/getting-visibility-into-your-amazon-eks-cross-az-pod-to-pod-network-bytes/) 
+  [使用 Istio 优化可用区流量](https://youtu.be/EkpdKVm9kQY) 
+  [使用拓扑感知路由优化 AZ 流量](https://youtu.be/KFgE_lNVfz4) 
+  [利用服务内部流量策略优化 Kubernetes 的成本和性能](https://youtu.be/-uiF_zixEro) 
+  [利用 Istio 和服务内部流量策略优化 Kubernetes 的成本和性能](https://youtu.be/edSgEe7Rihc) 
+  [Overview of Data Transfer Costs for Common Architectures](https://aws.amazon.com/blogs/architecture/overview-of-data-transfer-costs-for-common-architectures/) 
+  [了解 AWS 容器服务的数据传输成本](https://aws.amazon.com/blogs/containers/understanding-data-transfer-costs-for-aws-container-services/) 

# 存储
<a name="cost-opt-storage"></a>

## 概览
<a name="_overview"></a>

在某些情况下，您可能需要运行需要在短期或长期基础上保留数据的应用程序。对于此类用例，可以由 Pod 定义和挂载卷，这样它们的容器就可以利用不同的存储机制。Kubernetes 支持不同类型的[卷](https://kubernetes.io/docs/concepts/storage/volumes/)用于临时存储和永久存储。存储的选择在很大程度上取决于应用程序要求。每种方法都有成本影响，下面详细介绍的做法将帮助您在 EKS 环境中为需要某种形式存储的工作负载实现成本效益。

## 短暂卷
<a name="_ephemeral_volumes"></a>

临时卷适用于需要临时本地卷但不需要在重启后保留数据的应用程序。这方面的例子包括对暂存空间、缓存和只读输入数据（如配置数据和机密）的要求。[你可以在这里找到 Kubernetes 临时卷的更多细节。](https://kubernetes.io/docs/concepts/storage/ephemeral-volumes/)大多数临时卷（例如 emptyDir、ConfigMap、downwardAPI、secret、hostpath）都由本地连接的可写入设备（通常是根磁盘）或 RAM 提供支持，因此选择最具成本效益和性能的主机卷非常重要。

### 使用 EBS 卷
<a name="_using_ebs_volumes"></a>

 *我们建议从 [gp3](https://aws.amazon.com/ebs/general-purpose/) 作为主机根卷开始。*它是Amazon EBS提供的最新通用固态硬盘容量，与gp2卷相比，每GB的价格也更低（最高可达20％）。

### 使用亚马逊 EC2 实例存储
<a name="_using_amazon_ec2_instance_stores"></a>

 [Amazon EC2 实例存储](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/InstanceStorage.html)为您的 EC2 实例提供临时块级存储。 EC2 实例存储提供的存储可通过物理连接到主机的磁盘进行访问。与 Amazon EBS 不同，您只能在实例启动时附加实例存储卷，而且这些卷仅在实例的生命周期内存在。它们不能分离并重新连接到其他实例。您可以在此处了解有关 Amazon EC2 实例存储的[更多信息](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/InstanceStorage.html)。*实例存储容量不收取任何额外费用。*这使得它们（实例存储卷）比具有大 EBS 卷的普通 EC2 实例*更具成本效益*。

要在 Kubernetes 中使用本地存储卷，您应该使用 [Amazon EC2 用户数据](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instancedata-add-user-data.html)对磁盘进行分区、配置和格式化，以便可以按照 pod 规范安装卷。[HostPath](https://kubernetes.io/docs/concepts/storage/volumes/#hostpath)或者，您可以利用[本地永久卷静态配置器](https://github.com/kubernetes-sigs/sig-storage-local-static-provisioner)来简化本地存储管理。本地永久卷静态配置器允许您通过标准 Kubernetes PersistentVolumeClaim (PVC) 接口访问本地实例存储卷。此外，它还会配置 PersistentVolumes (PVs)，其中包含节点亲和性信息，将 Pod 调度到正确的节点。尽管它使用 Kubernetes PersistentVolumes，但 EC2 实例存储卷本质上是短暂的。写入临时磁盘的数据仅在实例的生命周期内可用。当实例终止时，数据也会终止。有关更多详细信息，请参阅此[博客](https://aws.amazon.com/blogs/containers/eks-persistent-volumes-for-instance-store/)。

请记住，在使用 Amazon EC2 实例存储卷时，总的 IOPS 限制与主机共享，并将 Pod 绑定到特定的主机。在采用 Amazon EC2 实例存储卷之前，您应该仔细检查您的工作负载要求。

## 永久卷
<a name="_persistent_volumes"></a>

Kubernetes 通常与运行无状态应用程序相关联。但是，在某些情况下，您可能需要运行微服务，这些微服务需要将一个请求中的永久数据或信息保留到下一个请求。数据库是此类用例的常见示例。但是，Pod 及其中的容器或进程本质上是短暂的。要在 Pod 的生命周期之后保留数据，您可以使用定义 PVs 对独立于 Pod 的特定位置的存储的访问权限。*与 PVs 之相关的成本在很大程度上取决于所使用的存储类型以及应用程序的使用方式。*

[此处列出了支持 PVs Amazon EKS 上的 Kubernetes 的不同类型的存储选项。](https://docs.aws.amazon.com/eks/latest/userguide/storage.html)下面介绍的存储选项是亚马逊 EBS、Amazon EFS、Amazon for Lustre、Ama FSx zon for ONTA FSx P NetApp 。

### 亚马逊 Elastic Block Store (EBS) Volumes
<a name="_amazon_elastic_block_store_ebs_volumes"></a>

Amazon EBS 卷可以作为 Kubernetes 使用， PVs 以提供块级存储卷。它们非常适合依赖随机读取和写入的数据库，以及执行长时间、连续读取和写入的吞吐量密集型应用程序。[Amazon Elastic Block Store 容器存储接口 (CSI) 驱动程序](https://docs.aws.amazon.com/eks/latest/userguide/ebs-csi.html)允许 Amazon EKS 集群管理永久卷的 Amazon EBS 卷的生命周期。容器存储接口支持并促进了 Kubernetes 与存储系统之间的交互。将 CSI 驱动程序部署到您的 EKS 集群后，您可以通过原生 Kubernetes 存储资源访问其功能，例如永久卷 (PVs)、永久卷声明 (PVCs) 和存储类别 ()。SCs此[链接](https://github.com/kubernetes-sigs/aws-ebs-csi-driver/tree/master/examples/kubernetes)提供了如何使用亚马逊 EBS CSI 驱动程序与亚马逊 EBS 卷进行交互的实际示例。

#### 选择合适的音量
<a name="_choosing_the_right_volume"></a>

 *我们建议使用最新一代的块存储 (gp3)，因为它在价格和性能之间提供了适当的平衡*。它还允许您独立于卷大小扩展卷 IOPS 和吞吐量，而无需配置额外的块存储容量。如果您目前正在使用 gp2 卷，我们强烈建议您迁移到 gp3 卷。博客文章[将 Amazon EKS 集群从 gp2 迁移到 gp3 EBS 卷解释了如何使用 CSI 卷](https://aws.amazon.com/blogs/containers/migrating-amazon-eks-clusters-from-gp2-to-gp3-ebs-volumes/)快照功能从亚马逊 EKS 集群上的 *gp3 上的 gp* *2* 迁移，并使用需要应用程序停机的 [CSI](https://kubernetes.io/docs/concepts/storage/volume-snapshots/) 卷快照功能进行备份和恢复。

Amazon EBS 允许在线更改卷特征，例如卷大小、IOPS 和吞吐量。[https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/](https://kubernetes.io/docs/concepts/storage/volume-attributes-classes/)

当您的应用程序需要更高的性能并且需要的卷大于单个 [gp3 卷所能支持的容量](https://aws.amazon.com/ebs/general-purpose/)时，您应该考虑使用 [io2](https://aws.amazon.com/ebs/provisioned-iops/) block express。这种类型的存储非常适合规模最大、最 I/O 密集和任务关键型部署，例如 SAP HANA 或其他具有低延迟要求的大型数据库。请记住，实例的 EBS 性能受实例性能限制的限制，因此并非所有实例都支持 io2 block express 卷。您可以在本[文档](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/provisioned-iops.html)中查看支持的实例类型和其他注意事项。

 *一个 gp3 卷最多可以支持最大 16,000 个 IOPS、 MiB/s 最大吞吐量 1,000、最大 16TiB。最新一代的预配置 IOPS 固态硬盘卷，可提供高达 256,000 IOPS、4,000 MiB/s、吞吐量和 64TiB。*

在这些选项中，您应该根据应用程序的需求量身定制存储性能和成本。

#### 随着时间的推移进行监控和优化
<a name="_monitor_and_optimize_over_time"></a>

重要的是要了解应用程序的基准性能并监控所选卷的基准性能，以检查其是否满足您的要求 requirements/expectations 或是否过度配置（例如，未充分利用预配置 IOPS 的情况）。

与其从一开始就分配大卷，不如在积累数据时逐渐增加卷的大小。您可以使用 Amazon Elastic Block Store CSI 驱动程序 () aws-ebs-csi-driver 中的卷[大小调整](https://github.com/kubernetes-sigs/aws-ebs-csi-driver/tree/master/examples/kubernetes/resizing)功能动态调整卷大小。*请记住，您只能增加 EBS 卷的大小。*

要识别和移除任何悬挂的 EBS 卷，您可以使用 AW [S trusted Advisor 的成本优化类别](https://docs.aws.amazon.com/awssupport/latest/user/cost-optimization-checks.html)。此功能可帮助您识别未连接的卷或一段时间内写入活动非常低的卷。有一个名为 [Popeye](https://github.com/derailed/popeye) 的云原生开源只读工具，它可以扫描实时 Kubernetes 集群，并报告已部署资源和配置的潜在问题。例如，它可以扫描未使用的 PVs 和 PVCs 并检查它们是否已绑定或是否存在任何卷装入错误。

要深入了解监控，请参阅 [EKS 成本优化可观察性指南](https://docs.aws.amazon.com/eks/latest/best-practices/cost-opt-observability.html)。

你可以考虑的另一个选择是 [AWS Compute Optimizer Amazon EBS](https://docs.aws.amazon.com/compute-optimizer/latest/ug/view-ebs-recommendations.html) 交易量建议。该工具可自动识别所需的最佳卷配置和正确的性能级别。例如，根据过去 14 天的最大利用率，它可以用于与预配置 IOPS、卷大小和 EBS 卷类型有关的最佳设置。它还量化了根据其建议可能节省的每月成本。您可以查看此[博客](https://aws.amazon.com/blogs/storage/cost-optimizing-amazon-ebs-volumes-using-aws-compute-optimizer/)以获取更多详细信息。

#### 备份保留政策
<a name="_backup_retention_policy"></a>

您可以通过拍摄 point-in-time快照来备份 Amazon EBS 卷上的数据。Amazon EBS CSI 驱动程序支持卷快照。您可以使用此[处](https://github.com/kubernetes-sigs/aws-ebs-csi-driver/blob/master/examples/kubernetes/snapshot/README.md)概述的步骤学习如何创建快照和恢复 EBS PV。

后续快照是增量备份，这意味着仅保存设备上在最近一次快照后发生更改的块。由于无需复制数据，这将最大限度缩短创建快照所需的时间和增加存储成本节省。但是，在没有适当的保留策略的情况下增加旧 EBS 快照的数量可能会在大规模运营时造成意想不到的成本。如果您通过 AWS API 直接备份亚马逊 EBS 卷，则可以利用亚马逊[数据生命周期管理器 (DLM)，它为亚马逊](https://aws.amazon.com/ebs/data-lifecycle-manager/)弹性区块存储 (EBS) Elastic Block Store 快照和 EBS 支持的亚马逊系统映像 () 提供基于策略的自动生命周期管理解决方案 ()。AMIs通过控制台，可以更轻松地自动创建、保留和删除 EBS 快照和 AMIs。

**注意**  
目前无法通过亚马逊 EBS CSI 驱动程序使用亚马逊 DLM。

在 Kubernetes 环境中，你可以利用名为 [Velero](https://velero.io/) 的开源工具来备份 EBS 永久卷。在安排任务以使备份过期时，您可以设置 TTL 标志。以下是Velero的[指南](https://velero.io/docs/v1.12/how-velero-works/#set-a-backup-to-expire)作为示例。

### Amazon Elastic File System (EFS)
<a name="_amazon_elastic_file_system_efs"></a>

 [Amazon Elastic File System (EFS)](https://aws.amazon.com/efs/) 是一个无服务器、完全弹性的文件系统，允许您使用标准文件系统接口和文件系统语义为各种工作负载和应用程序共享文件数据。工作负载和应用程序的示例包括 Wordpress 和 Drupal、JIRA 和 Git 等开发者工具，以及 Jupyter 等共享笔记本系统以及主目录。

Amazon EFS 的主要优势之一是，它可以由分布在多个节点和多个可用区的多个容器进行安装。另一个好处是，您只需为使用的存储空间付费。EFS 文件系统将在您添加和删除文件时自动增长和缩小，从而无需进行容量规划。

要在 Kubernetes 中使用 Amazon EFS，你需要使用亚马逊弹性文件系统 Elastic File System 容器存储接口 (CSI) 驱动程序。[aws-efs-csi-driver](https://github.com/kubernetes-sigs/aws-efs-csi-driver)目前，驱动程序可以动态创建[接入点](https://docs.aws.amazon.com/efs/latest/ug/efs-access-points.html)。但是，必须先配置 Amazon EFS 文件系统，并将其作为输入提供给 Kubernetes 存储类参数。

#### 选择正确的 EFS 存储类别
<a name="_choosing_the_right_efs_storage_class"></a>

Amazon EFS 提供[四种存储类别](https://docs.aws.amazon.com/efs/latest/ug/storage-classes.html)。

两个标准存储类别：
+ 亚马逊 EFS 标准
+  [亚马逊 EFS 标准——不频繁访问（EFS 标准-IA）](https://aws.amazon.com/blogs/aws/optimize-storage-cost-with-reduced-pricing-for-amazon-efs-infrequent-access/)

两个单区域存储类别：
+  [亚马逊 EFS One Zone](https://aws.amazon.com/blogs/aws/new-lower-cost-one-zone-storage-classes-for-amazon-elastic-file-system/) 
+ 亚马逊 EFS 单区-不频繁访问 (EFS 单区-IA)

不频繁访问 (IA) 存储类针对并非每天都访问的文件进行了成本优化。借助 Amazon EFS 生命周期管理，您可以将生命周期策略期间（7、14、30、60 或 90 天）未被访问的文件移动到 IA 存储类别，与 *EFS 标准和 EFS One Zone 存储类别相比，存储成本可分别降低多达 92%*。

借助 EFS Intelligent-Tiering，生命周期管理可以监控文件系统的访问模式，并自动将文件移动到最佳存储类别。

**注意**  
aws-efs-csi-driver 目前无法控制更改存储类别、生命周期管理或智能分层。应在 AWS 控制台中手动设置或通过 EFS 进行设置 APIs。

**注意**  
aws-efs-csi-driver 与基于 Windows 的容器镜像不兼容。

**注意**  
启用 *vol-metrics-opt-in*（发出音量指标）时存在已知的内存问题，这是因为该[DiskUsage](https://github.com/kubernetes/kubernetes/blob/ee265c92fec40cd69d1de010b477717e4c142492/pkg/volume/util/fs/fs.go#L66)功能消耗的内存量与文件系统的大小成正比。*目前，我们建议在大型文件系统上禁用 vol-metrics-opt-in* *`--`选项，以免消耗太多内存。以下是 github 问题[链接](https://github.com/kubernetes-sigs/aws-efs-csi-driver/issues/1104)，了解更多详情。*

### 亚马逊 f FSx or Lustre
<a name="_amazon_fsx_for_lustre"></a>

Lustre 是一种高性能并行文件系统，通常用于需要高达数百的吞吐量 GB/s 和亚毫秒的每次操作延迟的工作负载。它用于机器学习训练、财务建模、HPC 和视频处理等场景。[Amazon FSx for Lustre](https://aws.amazon.com/fsx/lustre/) 提供完全托管的共享存储，具有可扩展性和性能，并与 Amazon S3 无缝集成。

你可以使用 Amazon EKS 的 for Lustre [CSI 驱动程序或 AWS 上 FSx 自行管理的 Kubernetes 集群，使用由 for Lustre FSx 提供](https://github.com/kubernetes-sigs/aws-fsx-csi-driver)的 Kubernetes 永久存储卷。有关更多详细信息和示例，请参阅 [Amazon EKS 文档](https://docs.aws.amazon.com/eks/latest/userguide/fsx-csi.html)。

#### 链接到亚马逊 S3
<a name="_link_to_amazon_s3"></a>

建议将驻留在 Amazon S3 上的高度持久的长期数据存储库与 for Lustre 文件系统关联起来。 FSx 链接后，大型数据集将根据需要从 Amazon S3 延迟加载到 FSx Lustre 文件系统。您也可以将分析和结果运行回 S3，然后删除 Lustre 文件系统。

#### 选择正确的部署和存储选项
<a name="_choosing_the_right_deployment_and_storage_options"></a>

FSx for Lustre 提供了不同的部署选项。第一个选项叫做 s *cratch*，它不复制数据，而第二个选项叫做 persi *st* ent，顾名思义，它可以保留数据。

第一个选项（*从头开始*）可用于*降低临时短期数据处理的成本*。永久部署选项*专为长期存储而设计*，可自动复制 AWS 可用区域内的数据。它还支持固态硬盘和硬盘存储。

你可以在 lustre 文件系统的 Kubernetes FSx 的参数下配置所需的部署类型。 StorageClass以下是提供示例模板的[链接](https://github.com/kubernetes-sigs/aws-fsx-csi-driver/tree/master/examples/kubernetes/dynamic_provisioning#edit-storageclass)。

**注意**  
对于延迟敏感型工作负载或需要最高 IOPS/吞吐量级别的工作负载，您应该选择 SSD 存储。对于以吞吐量为重点且对延迟不敏感的工作负载，您应该选择 HDD 存储。

#### 启用数据压缩
<a name="_enable_data_compression"></a>

也可以通过将 “LZ4” 指定为数据压缩类型，在文件系统上启用数据压缩。启用后，所有新写入的文件将在写入磁盘之前自动压缩 Lustre，并在读取时解压缩。 FSx LZ4 数据压缩算法是无损的，因此可以从压缩的数据中完全重建原始数据。

你可以在 for lustre 文件系统的 Kubernet FSx es 的参数 LZ4 下配置数据压缩类型。 StorageClass当该值设置为 NONE（默认值）时，压缩功能处于禁用状态。此[链接](https://github.com/kubernetes-sigs/aws-fsx-csi-driver/tree/master/examples/kubernetes/dynamic_provisioning#edit-storageclass)提供示例模板。

**注意**  
Amazon FSx for Lustre 与基于 Windows 的容器镜像不兼容。

### FSx 适用于 NetApp ONTAP 的亚马逊
<a name="_amazon_fsx_for_netapp_ontap"></a>

 [Amazon FSx f NetApp or ONTAP](https://aws.amazon.com/fsx/netapp-ontap/) 是一个完全托管的共享存储，建立在 ONTAP 文件系统 NetApp之上。 FSx for ONTAP 提供功能丰富、快速、灵活的共享文件存储，可通过在 AWS 或本地运行的 Linux、Windows 和 macOS 计算实例进行广泛访问。

Amazon FSx NetApp for ONTAP 支持两个存储层：*1/主层*和 *2/容量池*层。

*主层*是基于固态硬盘的高性能预配置层，用于存放对延迟敏感的活跃数据。完全弹性的*容量池层*针对不经常访问的数据进行了成本优化，可随着数据分层到该层而自动扩展，并提供几乎无限的 PB 容量。您可以在容量池存储上启用数据压缩和重复数据删除，从而进一步减少数据消耗的存储容量。 NetApp基于策略的本机 FabricPool 功能可持续监控数据访问模式，自动在存储层之间双向传输数据以优化性能和成本。

NetApp的 Astra Trident 使用 CSI 驱动程序提供动态存储编排，该驱动程序允许 Amazon EKS 集群管理亚马逊支持的 FSx 适用于 NetApp ONTAP 文件 PVs 系统的永久卷的生命周期。要开始使用，请参阅 [Astra Trident 文档中的在亚马逊 FSx 上使用 Astra Trident for NetApp ONTAP](https://docs.netapp.com/us-en/trident/trident-use/trident-fsx.html)。

## 其他考虑因素
<a name="_other_considerations"></a>

### 最小化容器镜像的大小
<a name="_minimize_the_size_of_container_image"></a>

部署容器后，容器镜像将作为多层缓存在主机上。通过减小图像的大小，可以减少主机上所需的存储量。

通过从一开始就使用精简版的基础映像，例如暂存映像或[无发行版](https://github.com/GoogleContainerTools/distroless)容器镜像（仅包含您的应用程序及其运行时依赖项），*除了可以减少攻击面积和缩短图像提取时间等其他附带优势外，还可以降低存储成本*。

您还应该考虑使用开源工具，例如 [Slim.ai](https://www.slim.ai/docs/quickstart)，它提供了一种简单、安全的方法来创建最少的图像。

多层包、工具、应用程序依赖关系、库可以很容易地膨胀容器镜像的大小。通过使用多阶段构建，您可以有选择地将工件从一个阶段复制到另一个阶段，将最终图像中不需要的所有内容排除在外。[您可以在此处查看更多图像构建最佳实践。](https://docs.docker.com/get-started/09_image_best/)

需要考虑的另一件事是将缓存的图像保留多长时间。当使用一定数量的磁盘时，您可能需要从图像缓存中清理陈旧的图像。这样做将有助于确保有足够的空间供主机操作。默认情况下，[kubelet](https://kubernetes.io/docs/reference/generated/kubelet) 每五分钟对未使用的图像执行一次垃圾回收，每分钟对未使用的容器执行一次垃圾回收。

 *要为未使用的容器和镜像垃圾收集配置选项，请使用[配置文件](https://kubernetes.io/docs/tasks/administer-cluster/kubelet-config-file/)调整 kubelet，并使用[https://kubernetes.io/docs/reference/config-api/kubelet-config.v1beta1/](https://kubernetes.io/docs/reference/config-api/kubelet-config.v1beta1/)资源类型更改与垃圾收集相关的参数。*

[你可以在 Kubernetes 文档中了解更多相关信息。](https://kubernetes.io/docs/concepts/architecture/garbage-collection/#containers-images)

# 可观察性
<a name="cost-opt-observability"></a>

## 简介
<a name="_introduction"></a>

可观测性工具可帮助您高效检测、修复和调查您的工作负载。随着您使用EKS的增加，遥测数据的成本自然会增加。有时，要平衡运营需求和衡量对业务至关重要的因素并控制可观察性成本，可能是一项艰巨的任务。本指南重点介绍可观测性的三个支柱的成本优化策略：日志、指标和跟踪。这些最佳实践中的每一种都可以独立应用，以适应组织的优化目标。

## 日志记录
<a name="_logging"></a>

日志在监控集群中的应用程序并对其进行故障排除方面起着至关重要的作用。有几种策略可以用来优化日志成本。下面列出的最佳实践策略包括检查您的日志保留策略以对日志数据的保留时间实施精细控制，根据重要性将日志数据发送到不同的存储选项，以及利用日志筛选来缩小存储的日志消息的类型。高效管理日志遥测可以为您的环境节省成本。

## EKS 控制飞机
<a name="_eks_control_plane"></a>

### 优化您的控制平面日志
<a name="_optimize_your_control_plane_logs"></a>

[Kubernetes 控制平面是一组用于管理集群[的组件](https://kubernetes.io/docs/concepts/overview/components/#control-plane-components)，这些组件将不同类型的信息作为日志流发送到 Amazon 中的日志组。 CloudWatch](https://aws.amazon.com/cloudwatch/)虽然启用所有控制平面日志类型有好处，但您应该了解每个日志中的信息以及存储所有日志遥测数据的相关成本。对于从您的集群发送到 Ama CloudWatch zon [CloudWatch Logs 的日志，您需要支付标准日志数据摄取和存储费用](https://aws.amazon.com/cloudwatch/pricing/)。在启用它们之前，请评估是否需要每个日志流。

例如，在非生产集群中，有选择地启用特定的日志类型，例如 api 服务器日志，仅用于分析，然后停用。但是对于生产集群，您可能无法重现事件，并且解决问题需要更多的日志信息，则可以启用所有日志类型。更多控制平面成本优化的实施细节请参见这篇[博客](https://aws.amazon.com/blogs/containers/understanding-and-cost-optimizing-amazon-eks-control-plane-logs/)文章。

#### 将日志流式传输到 S3
<a name="_stream_logs_to_s3"></a>

另一种成本优化最佳实践是通过 CloudWatch 日志订阅将控制平面日志流式传输到 S3。利用 CloudWatch 日志[订阅](https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/Subscriptions.html)，您可以有选择地将日志转发到 S3，与无限期保留日志相比，S3 提供了更具成本效益的长期存储。 CloudWatch例如，对于生产集群，您可以创建一个关键日志组，并利用订阅在 15 天后将这些日志流式传输到 S3。这将确保您可以快速访问日志进行分析，还可以通过将日志移动到更具成本效益的存储空间来节省成本。

**重要**  
自 2023 年 9 月 5 日起，EKS 日志在 Amazon 日志中被归类为销售日志。 CloudWatch Vended Logs 是 AWS 服务代表客户在本地发布的特定 AWS 服务日志，按批量折扣定价提供。请访问 [Amazon CloudWatch 定价页面](https://aws.amazon.com/cloudwatch/pricing/)，了解有关 Vended Logs 定价的更多信息。

## EKS 数据平面
<a name="_eks_data_plane"></a>

### 日志保留
<a name="_log_retention"></a>

Amazon CloudWatch 的默认保留政策是无限期保留日志且永不过期，这会产生适用于您的 AWS 地区的存储成本。为了降低存储成本，您可以根据工作负载要求为每个日志组自定义保留策略。

在开发环境中，可能不需要很长的保留期。但是在生产环境中，您可以设置更长的保留期策略以满足故障排除、合规性和容量规划要求。例如，如果您在假日旺季运行电子商务应用程序，则系统负载较重，并且可能会出现可能无法立即注意到的问题，则需要设置更长的日志保留时间，以便进行详细的故障排除和事件后分析。

[您可以在 AWS CloudWatch 控制台或 AW [S API](https://docs.aws.amazon.com/cli/latest/reference/logs/put-retention-policy.html) 中根据每个日志组将保留期配置](https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/Working-with-log-groups-and-streams.html#SettingLogRetention)为 1 天到 10 年不等。灵活的保留期可以节省日志存储成本，同时还可以维护关键日志。

### 日志存储选项
<a name="_log_storage_options"></a>

存储是可观测性成本的重要驱动因素，因此优化日志存储策略至关重要。您的策略应与您的工作负载需求保持一致，同时保持性能和可扩展性。降低存储日志成本的一种策略是利用 AWS S3 存储桶及其不同的存储层。

#### 将日志直接转发到 S3
<a name="_forward_logs_directly_to_s3"></a>

考虑将不太重要的日志（例如开发环境）直接转发到 S3 而不是 Cloudwatch。这可能会对日志存储成本产生直接影响。一种选择是使用 Fluentbit 将日志直接转发到 S3。您可以在 “ FluentBit 传输容器日志以进行保留的目的地” 一`[OUTPUT]`节中对此进行定义。[在此处](https://docs.fluentbit.io/manual/pipeline/outputs/s3#worker-support)查看其他配置参数。

```
[OUTPUT]
        Name eks_to_s3
        Match application.*
        bucket $S3_BUCKET name
        region us-east-2
        store_dir /var/log/fluentbit
        total_file_size 30M
        upload_timeout 3m
```

#### 将日志转发到 CloudWatch 仅用于短期分析
<a name="_forward_logs_to_cloudwatch_only_for_short_term_analysis"></a>

对于更重要的日志，例如可能需要对数据进行即时分析的生产环境，可以考虑将日志转发到 CloudWatch。您可以在 “ FluentBit 传输容器日志以进行保留的目的地” 一`[OUTPUT]`节中对此进行定义。[在此处](https://docs.fluentbit.io/manual/pipeline/outputs/cloudwatch)查看其他配置参数。

```
[OUTPUT]
        Name eks_to_cloudwatch_logs
        Match application.*
        region us-east-2
        log_group_name fluent-bit-cloudwatch
        log_stream_prefix from-fluent-bit-
        auto_create_group On
```

但是，这不会立即影响您的成本节约。为了节省更多费用，您必须将这些日志导出到 Amazon S3。

#### 从以下地址导出到亚马逊 S3 CloudWatch
<a name="_export_to_amazon_s3_from_cloudwatch"></a>

为了长期存储亚马逊 CloudWatch 日志，我们建议将您的亚马逊 EKS CloudWatch 日志导出到亚马逊简单存储服务 (Amazon S3) Simple S3 Service。您可以通过[控制台](https://docs.aws.amazon.com/AmazonCloudWatch/latest/logs/S3ExportTasksConsole.html)或 API 创建导出任务，将日志转发到 Amazon S3 存储桶。完成此操作后，Amazon S3 提供了许多选项来进一步降低成本。您可以定义自己的 [Amazon S3 生命周期规则](https://docs.aws.amazon.com/AmazonS3/latest/userguide/object-lifecycle-mgmt.html)，将日志移动到符合您需求的存储类别，或者利用 A [mazon S3 智能分层](https://aws.amazon.com/s3/storage-classes/intelligent-tiering/)存储类让 AWS 根据您的使用模式自动将数据移至长期存储。有关更多详细信息，请参阅此[博客](https://aws.amazon.com/blogs/containers/understanding-and-cost-optimizing-amazon-eks-control-plane-logs/)。例如，对于您的生产环境，日志存放时间超过 30 天，然后导出到 Amazon S3 存储桶。 CloudWatch 然后，如果您需要在以后参考日志，则可以使用 Amazon Athena 来查询 Amazon S3 存储桶中的数据。

### 降低日志级别
<a name="_reduce_log_levels"></a>

为您的应用程序练习选择性日志记录。默认情况下，您的应用程序和节点都会输出日志。对于应用程序日志，请调整日志级别，使其与工作负载和环境的重要性保持一致。例如，下面的 java 应用程序正在输出`INFO`日志，这是典型的默认应用程序配置，根据代码的不同，可能会生成大量的日志数据。

```
import org.apache.log4j.*;

public class LogClass {
   private static org.apache.log4j.Logger log = Logger.getLogger(LogClass.class);

public static void main(String[] args) {
      log.setLevel(Level.INFO);

   log.debug("This is a DEBUG message, check this out!");
   log.info("This is an INFO message, nothing to see here!");
   log.warn("This is a WARN message, investigate this!");
   log.error("This is an ERROR message, check this out!");
   log.fatal("This is a FATAL message, investigate this!");    } }
```

在开发环境中，将日志级别更改为`DEBUG`，因为这可以帮助你调试问题，或者在潜在问题进入生产之前抓住它们。

```
      log.setLevel(Level.DEBUG);
```

在生产环境中，可以考虑将日志级别修改为`ERROR`或`FATAL`。只有当您的应用程序出现错误时，它才会输出日志，从而减少日志输出，并帮助您专注于有关应用程序状态的重要数据。

```
      log.setLevel(Level.ERROR);
```

你可以微调各种 Kubernetes 组件的日志级别。例如，如果您使用 [Bottlerocket](https://bottlerocket.dev/) 作为 EKS 节点操作系统，则有一些配置设置允许您调整 kubelet 进程日志级别。此配置设置的片段如下所示。请注意，默认[日志级别](https://github.com/bottlerocket-os/bottlerocket/blob/3f716bd68728f7fd825eb45621ada0972d0badbb/README.md?plain=1#L528)为 **2**，它会调整进程的日志详细程度。`kubelet`

```
[settings.kubernetes]
log-level = "2"
image-gc-high-threshold-percent = "85"
image-gc-low-threshold-percent = "80"
```

对于开发环境，您可以将日志级别设置为大于 **2** 以查看其他事件，这有利于调试。对于生产环境，您可以将级别设置**为 0**，以便仅查看关键事件。

### 利用过滤器
<a name="_leverage_filters"></a>

使用默认 EKS Fluentbit 配置将容器日志发送到 Cloudwatch 时，请 FluentBit 捕获**所有**富含 Kubernetes 元数据的应用程序容器日志并将其发送到 Cloudwatch，如下面的配置块所示。`[INPUT]`

```
 [INPUT]
     Name                tail
     Tag                 application.*
     Exclude_Path        /var/log/containers/cloudwatch-agent*, /var/log/containers/fluent-bit*, /var/log/containers/aws-node*, /var/log/containers/kube-proxy*
     Path                /var/log/containers/*.log
     Docker_Mode         On
     Docker_Mode_Flush   5
     Docker_Mode_Parser  container_firstline
     Parser              docker
     DB                  /var/fluent-bit/state/flb_container.db
     Mem_Buf_Limit       50MB
     Skip_Long_Lines     On
     Refresh_Interval    10
     Rotate_Wait         30
     storage.type        filesystem
     Read_from_Head      ${READ_FROM_HEAD}
```

上面的`[INPUT]`部分正在摄取所有容器日志。这可能会生成大量可能不是必需的数据。筛选出这些数据可以减少发送到的日志数据量， CloudWatch 从而降低成本。您可以先对日志应用过滤器，然后再将其输出到 CloudWatch。Fluentbit 在本节中对此进行了定义。`[FILTER]`例如，过滤掉 Kubernetes 元数据以使其不被附加到日志事件可以减少日志量。

```
    [FILTER]
        Name                nest
        Match               application.*
        Operation           lift
        Nested_under        kubernetes
        Add_prefix          Kube.

    [FILTER]
        Name                modify
        Match               application.*
        Remove              Kube.<Metadata_1>
        Remove              Kube.<Metadata_2>
        Remove              Kube.<Metadata_3>

    [FILTER]
        Name                nest
        Match               application.*
        Operation           nest
        Wildcard            Kube.*
        Nested_under        kubernetes
        Remove_prefix       Kube.
```

## Metrics
<a name="_metrics"></a>

 [指标](https://aws-observability.github.io/observability-best-practices/signals/metrics/)提供了有关系统性能的宝贵信息。通过将所有与系统相关的或可用的资源指标整合到一个集中的位置，您可以比较和分析性能数据。这种集中式方法使您能够做出更明智的战略决策，例如扩大或缩减资源。此外，指标在评估资源运行状况方面起着至关重要的作用，使您能够在必要时采取主动措施。通常，可观测性成本会随着遥测数据的收集和保留而增加。以下是您可以实施的几种策略来降低公制遥测的成本：仅收集重要的指标，降低遥测数据的基数，以及微调遥测数据收集的粒度。

### 监控重要内容，只收集你需要的东西
<a name="_monitor_what_matters_and_collect_only_what_you_need"></a>

第一种降低成本的策略是减少您收集的指标数量，进而降低留存成本。

1. 首先，从您和/或利益相关者的要求向后推进[，以确定最重要的指标](https://aws-observability.github.io/observability-best-practices/guides/#monitor-what-matters)。每个人的成功指标都不一样！知道*好*看是什么样子，并据此进行衡量。

1. 考虑深入研究你所支持的工作负载，并确定其关键性能指标 (KPIs)，又名 “黄金信号”。这些应符合业务和利益相关者的要求。计算 SLIs SLOs、和 SLAs 使用 Amazon CloudWatch 和 Metric Math 对于管理服务可靠性至关重要。遵循本[指南](https://aws-observability.github.io/observability-best-practices/guides/operational/business/key-performance-indicators/#10-understanding-kpis-golden-signals)中概述的最佳实践，以有效监控和维护 EKS 环境的性能。

1. 然后继续浏览基础设施的不同层，[将 EKS 集群、节点和其他基础设施指标与您的工作负载 KPIs关联起来](https://aws-observability.github.io/observability-best-practices/signals/metrics/#correlate-with-operational-metric-data)。将您的业务指标和运营指标存储在系统中，您可以将它们关联在一起，并根据观察到的对两者的影响得出结论。

1. EKS 公开来自控制平面、集群 kube-state-metrics、Pod 和节点的指标。所有这些指标的相关性取决于您的需求，但是您可能不需要跨不同层次的每一个指标。您可以使用此 [EKS 基本指标](https://aws-observability.github.io/observability-best-practices/guides/containers/oss/eks/best-practices-metrics-collection/)指南作为监控 EKS 集群和工作负载整体运行状况的基准。

以下是 prometheus 抓`relabel_config`取配置的示例，我们在其中使用仅保留 kubelet 指标并`metric_relabel_config`删除所有容器指标。

```
  kubernetes_sd_configs:
  - role: endpoints
    namespaces:
      names:
      - kube-system
  bearer_token_file: /var/run/secrets/kubernetes.io/serviceaccount/token
  tls_config:
    insecure_skip_verify: true
  relabel_configs:
  - source_labels: [__meta_kubernetes_service_label_k8s_app]
    regex: kubelet
    action: keep

  metric_relabel_configs:
  - source_labels: [__name__]
    regex: container_(network_tcp_usage_total|network_udp_usage_total|tasks_state|cpu_load_average_10s)
    action: drop
```

### 在适用的情况下减少基数
<a name="_reduce_cardinality_where_applicable"></a>

基数是指特定指标集的数据值与其维度（例如 prometheus 标签）相结合的唯一性。高基数指标具有多个维度，每个维度指标组合具有更高的唯一性。更高的基数会导致更大的公制遥测数据大小和存储需求，从而增加成本。

在下面的高基数示例中，我们看到指标 “延迟” 具有维度、requestID、CustomerID 和服务，每个维度都有许多唯一的值。基数是衡量每个维度可能值的数量组合的指标。在 Prometheus 中，每组唯一的维度/标签都被视为一个新的指标，因此高基数意味着更多的指标。

在每个指标（集群、命名空间、服务、Pod、容器等）都有许多指标和维度/标签的 EKS 环境中，基数往往会增长。为了优化成本，请仔细考虑您正在收集的指标的基数。例如，如果您要在集群级别聚合用于可视化的特定指标，则可以删除位于较低层的其他标签，例如命名空间标签。

为了识别 prometheus 中的高基数指标，您可以运行以下 PROMQL 查询来确定哪些抓取目标的指标数量最多（基数）：

```
topk_max(5, max_over_time(scrape_samples_scraped[1h]))
```

以下 PROMQL 查询可以帮助您确定哪些抓取目标的指标流失率最高（在给定的抓取中创建了多少新指标系列）：

```
topk_max(5, max_over_time(scrape_series_added[1h]))
```

如果你使用的是 grafana，你可以使用 Grafana Lab 的 Mimirtool 来分析你的 grafana 仪表板，使用 prometheus 规则来识别未使用的高基数指标。按照[本指南](https://grafana.com/docs/grafana-cloud/account-management/billing-and-usage/control-prometheus-metrics-usage/usage-analysis-mimirtool/?pg=blog&plcmt=body-txt#analyze-and-reduce-metrics-usage-with-grafana-mimirtool)，了解如何使用`mimirtool analyze`和`mimirtool analyze prometheus`命令来识别仪表板中未引用的活动指标。

### 考虑指标粒度
<a name="_consider_metric_granularity"></a>

以更高的精度（例如每秒与每分钟）收集指标可能会对收集和存储的遥测数据产生重大影响，从而增加成本。确定合理的抓取或指标收集间隔，在足够大的粒度以查看暂时性问题和足够低的粒度之间取得平衡，从而具有成本效益。降低用于容量规划和更大时间窗分析的指标的粒度。

[以下是默认的 AWS Distro for Opentelemetry (ADOT) EKS 插件收集器配置的片段。](https://docs.aws.amazon.com/eks/latest/userguide/deploy-deployment.html)

**重要**  
全局 prometheus 抓取间隔设置为 15 秒。此抓取间隔可以增加，从而减少在 prometheus 中收集的指标数据量。

```
apiVersion: opentelemetry.io/v1alpha1
kind: OpenTelemetryCollector
metadata:
  name: my-collector-amp

...

config: |
    extensions:
      sigv4auth:
        region: "+++<YOUR_AWS_REGION>+++" service: "aps"+++</YOUR_AWS_REGION>+++

 receivers:
   #
   # Scrape configuration for the Prometheus Receiver
   # This is the same configuration used when Prometheus is installed using the community Helm chart
   #
   prometheus:
     config:
       global:   scrape_interval: 15s
         scrape_timeout: 10s
```

## 跟踪
<a name="_tracing"></a>

与追踪相关的主要成本源于痕量存储的生成。通过跟踪，目的是收集足够的数据来诊断和了解性能方面。但是，由于 X-Ray 追踪的成本基于转发到 X-Ray 的数据，因此在转发轨迹后删除跟踪不会降低您的成本。让我们回顾一下在维护数据以便进行适当分析的同时降低追踪成本的方法。

### 应用采样规则
<a name="_apply_sampling_rules"></a>

默认情况下，X-Ray 采样率是保守的。定义采样规则，您可以在其中控制所收集的数据量。这将提高性能效率，同时降低成本。通过[降低采样率](https://docs.aws.amazon.com/xray/latest/devguide/xray-console-sampling.html#xray-console-custom)，您可以仅从请求中收集工作负载所需的跟踪，同时保持较低的成本结构。

例如，你有一个 java 应用程序，你想调试 1 条有问题的路由的所有请求的跟踪。

 **通过 SDK 进行配置以从 JSON 文档加载采样规则** 

```
{
"version": 2,
  "rules": [
    {
"description": "debug-eks",
      "host": "*",
      "http_method": "PUT",
      "url_path": "/history/*",
      "fixed_target": 0,
      "rate": 1,
      "service_type": "debug-eks"
    }
  ],
  "default": {
"fixed_target": 1,
    "rate": 0.1
  }
}
```

 **通过控制台** 

### 使用 AWS Distro 应用尾部采样适用于 OpenTelemetry (ADOT)
<a name="_apply_tail_sampling_with_aws_distro_for_opentelemetry_adot"></a>

ADOT Tail Sampling 允许您控制服务中摄取的迹线量。但是，Tail Sampling 允许您在请求中的所有跨度都完成之后而不是在开始时定义采样策略。这进一步限制了传输到的原始数据量 CloudWatch，从而降低了成本。

例如，如果您对登录页面流量的 1% 和 10% 的付款页面请求进行采样，则可能会在 30 分钟内留下 300 条跟踪记录。使用过滤特定错误的 ADOT Tail Sampling 规则，您可能只剩下 200 条轨迹，从而减少存储的跟踪数量。

```
processors:
  groupbytrace:
    wait_duration: 10s
    num_traces: 300
    tail_sampling:
    decision_wait: 1s # This value should be smaller than wait_duration
    policies:
      - ..... # Applicable policies**
  batch/tracesampling:
    timeout: 0s # No need to wait more since this will happen in previous processors
    send_batch_max_size: 8196 # This will still allow us to limit the size of the batches sent to subsequent exporters

service:
  pipelines:
    traces/tailsampling:
      receivers: [otlp]
      processors: [groupbytrace, tail_sampling, batch/tracesampling]
      exporters: [awsxray]
```

### 利用亚马逊 S3 存储选项
<a name="_leverage_amazon_s3_storage_options"></a>

您应该利用 AWS S3 存储桶及其不同的存储类来存储跟踪。在保留期到期之前将跟踪导出到 S3。使用 Amazon S3 生命周期规则将跟踪数据移至符合您要求的存储类别。

例如，如果您的跟踪记录已存在 90 天，[Amazon S3 智能分层](https://aws.amazon.com/s3/storage-classes/intelligent-tiering/)可以根据您的使用模式自动将数据移至长期存储。如果您需要稍后再参考跟踪记录，则可以使用 [Ama](https://aws.amazon.com/athena/) zon Athena 来查询 Amazon S3 中的数据。这可以进一步降低分布式跟踪的成本。

## 其他资源：
<a name="_additional_resources"></a>
+  [可观测性最佳实践指南](https://aws-observability.github.io/observability-best-practices/guides/) 
+  [最佳实践指标收集](https://aws-observability.github.io/observability-best-practices/guides/containers/oss/eks/) 
+  [AWS re: Invent 2022-亚马逊的可观察性最佳实践 () COP343](https://www.youtube.com/watch?v=zZPzXEBW4P8) 
+  [AWS re: Invent 2022-可观察性：现代应用程序的最佳实践 () COP344](https://www.youtube.com/watch?v=YiegAlC_yyc) 