Kubernetes 数据平面 - Amazon EKS

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

Kubernetes 数据平面

选择 EC2 实例类型可能是客户面临的最艰难的决定之一,因为在具有多个工作负载的集群中。没有万能 one-size-fits的解决办法。以下是一些技巧,可帮助您避免在扩展计算时遇到的常见陷阱。

自动节点自动缩放

我们建议您使用节点自动缩放,这样可以减少工作量并与 Kubernetes 深度集成。对于大型@@ 集群,建议使用托管节点组Karpenter

托管节点组将为您提供 Amazon A EC2 uto Scaling 组的灵活性,并在托管升级和配置方面获得更多好处。它可以使用 Kubernetes 集群自动扩缩器进行扩展,对于有各种计算需求的集群来说,这是一种常见的选择。

Karpenter 是一款由 AWS 创建的开源、工作负载原生节点自动扩缩器。它根据资源(例如 GPU)的工作负载要求以及污点和容忍度(例如区域分布)来扩展集群中的节点,而无需管理节点组。节点是直接从中创建的 EC2 ,避免了默认的节点组配额(每组 450 个节点),并提供了更大的实例选择灵活性和更少的操作开销。我们建议客户尽可能使用 Karpenter。

使用许多不同的 EC2 实例类型

每个 AWS 区域每种实例类型的可用实例数量有限。如果您创建的集群仅使用一种实例类型,并且将节点数量扩展到该区域的容量之外,则会收到一条错误消息,提示没有可用的实例。为避免此问题,您不应任意限制可在集群中使用的实例类型。

默认情况下,Karpenter 将使用一系列兼容的实例类型,并将在配置时根据待处理的工作负载要求、可用性和成本选择实例。您可以扩大karpenter.k8s.aws/instance-category密钥中使用的实例类型的列表NodePools

Kubernetes 集群自动扩缩器要求节点组的大小必须相似,这样它们才能持续扩展。您应该根据 CPU 和内存大小创建多个组,并分别对其进行扩展。使用 ec2-instance-selector 来识别您的节点组大小相似的实例。

ec2-instance-selector --service eks --vcpus-min 8 --memory-min 16
a1.2xlarge
a1.4xlarge
a1.metal
c4.4xlarge
c4.8xlarge
c5.12xlarge
c5.18xlarge
c5.24xlarge
c5.2xlarge
c5.4xlarge
c5.9xlarge
c5.metal

最好使用更大的节点来减少 API 服务器的负载

在决定使用哪些实例类型时,较少的大型节点会减少 Kubernetes 控制平面的负载,因为运行的 kubelet 会更少。 DaemonSets 但是,大型节点可能无法像较小的节点那样得到充分利用。应根据您的工作负载可用性和规模要求来评估节点大小。

一个包含三个 u-24tb1.metal 实例(24 TB 内存和 448 个内核)的集群有 3 个 kubelet,默认情况下每个节点的容量限制为 110 个。如果你的 pod 每个使用 4 个内核,那么这可能是预料之中的(4 个内核 x 110 = 440 个内核/节点)。对于 3 节点集群,您处理实例事件的能力会很低,因为 1 个实例中断可能会影响 1/3 的集群。你应该在工作负载中指定节点要求和 Pod 分布,这样 Kubernetes 调度器就可以正确放置工作负载。

工作负载应通过污点、容忍度和,来定义他们需要的资源和所需的可用性。PodTopologySpread他们应该选择可以充分利用并满足可用性目标的最大节点,以减少控制平面负载、降低操作和降低成本。

如果资源可用,Kubernetes 调度器将自动尝试将工作负载分散到可用区和主机上。如果没有可用容量,Kubernetes 集群自动扩缩程序将尝试在每个可用区中均匀添加节点。除非工作负载指定了其他要求,否则 Karpenter 将尝试以尽可能快和低廉的价格添加节点。

要强制工作负载随调度器分散并跨可用区创建新节点,应使用 topologySpreadConstraints:

spec:
  topologySpreadConstraints:
    - maxSkew: 3
      topologyKey: "topology.kubernetes.io/zone"
      whenUnsatisfiable: ScheduleAnyway
      labelSelector:
        matchLabels:
          dev: my-deployment
    - maxSkew: 2
      topologyKey: "kubernetes.io/hostname"
      whenUnsatisfiable: ScheduleAnyway
      labelSelector:
        matchLabels:
          dev: my-deployment

使用相似的节点大小以获得一致的工作负载性能

工作负载应定义它们需要在多大小的节点上运行,以实现稳定的性能和可预测的扩展。请求 500 米 CPU 的工作负载在具有 4 个内核的实例和具有 16 个内核的实例上的性能会有所不同。避免使用 CPUs 像 T 系列实例那样使用可突发性能的实例类型。

为了确保您的工作负载获得稳定的性能,工作负载可以使用支持的 Karpenter 标签来定位特定的实例大小。

kind: deployment
...
spec:
  template:
    spec:
    containers:
    nodeSelector:
      karpenter.k8s.aws/instance-size: 8xlarge

使用 Kubernetes 集群自动扩缩器在集群中调度的工作负载应根据标签匹配将节点选择器与节点组进行匹配。

spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: eks.amazonaws.com/nodegroup
            operator: In
            values:
            - 8-core-node-group    # match your node group name

高效使用计算资源

计算资源包括 EC2 实例和可用区。有效使用计算资源将提高您的可扩展性、可用性和性能,并降低总成本。在具有多个应用程序的自动缩放环境中,很难预测资源的有效使用情况。Karpenter 旨在根据工作负载需求按需配置实例,从而最大限度地提高利用率和灵活性。

Karpenter 允许工作负载声明其所需的计算资源类型,而无需先创建节点组或为特定节点配置标签污点。有关更多信息,请参阅 Karpenter 最佳实践。考虑在 Karpenter 配置器中启用整合,以替换未充分利用的节点。

自动更新亚马逊系统映像 (AMI)

使工作节点组件保持最新状态将确保您拥有最新的安全补丁和与 Kubernetes API 兼容的功能。更新 kubelet 是 Kubernetes 功能最重要的组件,但是自动化操作系统、内核和本地安装的应用程序补丁将减少在扩展时的维护工作。

建议你为节点映像使用最新的亚马逊 EKS 优化的亚马逊 Linux 2亚马逊 EKS 优化的 Bottlerocket AM I。Karpenter 将自动使用最新的可用的 AMI 在集群中配置新节点。托管节点组将在节点组更新期间更新 AMI,但不会在节点配置时更新 AMI ID。

对于托管节点组,当补丁版本可用 IDs 时,您需要使用新 AMI 更新 Auto Scaling 组 (ASG) 启动模板。AMI 次要版本(例如 1.23.5 到 1.24.3)将作为节点组的升级在 EKS 控制台和 API 中提供。补丁发布版本(例如 1.23.5 到 1.23.6)不会作为节点组的升级提供。如果您想让您的节点组与 AMI 补丁版本保持同步,则需要创建新的启动模板版本,并让节点组用新的 AMI 版本替换实例。

您可以从此页面找到最新的可用的 AMI,也可以使用 AWS CLI。

aws ssm get-parameter \
  --name /aws/service/eks/optimized-ami/1.24/amazon-linux-2/recommended/image_id \
  --query "Parameter.Value" \
  --output text

为容器使用多个 EBS 卷

根据卷的类型 input/output (例如 gp3)和磁盘的大小,EBS 卷具有(I/O)配额。如果您的应用程序与主机共享一个 EBS 根卷,则可能会耗尽整个主机的磁盘配额,并导致其他应用程序等待可用容量。如果应用程序将文件写入其覆盖分区,从主机装载本地卷,以及登录到标准输出 (STDOUT),则会写入磁盘,具体取决于所使用的日志代理。

为避免磁盘 I/O 耗尽,您应该将第二个卷挂载到容器状态文件夹(例如 /run/containerd),使用单独的 EBS 卷存储工作负载,并禁用不必要的本地日志记录。

要使用 eksctl 将第二个卷挂载到您的 EC2 实例,您可以使用具有以下配置的节点组:

managedNodeGroups:
  - name: al2-workers
    amiFamily: AmazonLinux2
    desiredCapacity: 2
    volumeSize: 80
    additionalVolumes:
      - volumeName: '/dev/sdz'
        volumeSize: 100
    preBootstrapCommands:
    - |
      "systemctl stop containerd"
      "mkfs -t ext4 /dev/nvme1n1"
      "rm -rf /var/lib/containerd/*"
      "mount /dev/nvme1n1 /var/lib/containerd/"
      "systemctl start containerd"

如果你使用 terraform 来配置节点组,请参阅 EKS 蓝图中适用于 terraform 的示例。如果您使用 Karpenter 来配置节点,则可以使用blockDeviceMappings节点用户数据来添加其他卷。

要将 EBS 卷直接挂载到您的容器中,您应该使用 AWS EBS CSI 驱动程序并使用具有存储类的卷。

---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  name: ebs-sc
provisioner: ebs.csi.aws.com
volumeBindingMode: WaitForFirstConsumer
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: ebs-claim
spec:
  accessModes:
    - ReadWriteOnce
  storageClassName: ebs-sc
  resources:
    requests:
      storage: 4Gi
---
apiVersion: v1
kind: Pod
metadata:
  name: app
spec:
  containers:
  - name: app
    image: public.ecr.aws/docker/library/nginx
    volumeMounts:
    - name: persistent-storage
      mountPath: /data
  volumes:
  - name: persistent-storage
    persistentVolumeClaim:
      claimName: ebs-claim

如果工作负载使用 EBS 卷,请避开 EBS 连接限制较低的实例

EBS 是工作负载获得持久存储的最简单方法之一,但它也存在可扩展性限制。每种实例类型都有可连接的最大数量的 EBS 卷。工作负载需要声明它们应该在哪些实例类型上运行,并限制带有 Kubernetes 污染的单个实例上的副本数量。

禁用不必要的磁盘日志记录

不要在生产环境中运行带有调试日志的应用程序,并禁用频繁读写磁盘的日志记录,从而避免不必要的本地日志记录。Journald 是一种本地日志服务,它在内存中保留日志缓冲区并定期刷新到磁盘。Journald 比 syslog 更受青睐,后者会立即将每行记录到磁盘。禁用 syslog 还可以降低所需的存储总量,并避免需要复杂的日志轮换规则。要禁用 syslog,你可以将以下代码段添加到你的 cloud-init 配置中:

runcmd:
  - [ systemctl, disable, --now, syslog.service ]

当需要操作系统更新速度时,将实例修补到位

重要

只有在需要时才应在原地修补实例。Amazon 建议将基础设施视为不可变的,并像应用程序一样彻底测试在较低环境中推广的更新。当无法做到这一点时,本节适用。

在不中断容器化工作负载的情况下,在现有 Linux 主机上安装软件包需要几秒钟。无需封锁、耗尽或更换实例即可安装和验证软件包。

要替换实例,您首先需要创建、验证和分发新实例 AMIs。该实例需要创建替代实例,并且需要封锁和排空旧实例。然后,需要在新实例上创建工作负载,对其进行验证,然后重复所有需要修补的实例。在不中断工作负载的情况下安全更换实例需要数小时、数天或数周的时间。

Amazon 建议使用基于自动声明式系统构建、测试和升级的不可变基础设施,但是如果您需要快速修补系统,则需要对现有系统进行修补并在新 AMIs 系统问世时进行更换。由于修补和更换系统之间的时间差异很大,我们建议在需要时使用 AWS Systems Manager Patch Manager 自动修补节点。

在 AMI 更新后,通过修补节点,您可以快速推出安全更新并定期更换实例。如果您使用的操作系统具有只读根文件系统,例如 Flatcar Container LinuxBottlerocket OS,我们建议您使用适用于这些操作系统的更新运算符。Flatcar Linux 更新操作员Bottlerocket 更新操作员将重启实例,使节点自动保持最新状态。