View a markdown version of this page

Kubernetes 数据平面 - Amazon EKS

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

Kubernetes 数据平面

选择 EC2 实例类型可能是客户面临的最艰难的决定之一,因为在具有多个工作负载的集群中。没有放之四海而皆准的解决方案。以下提示可帮助您避免扩展计算时出现的常见陷阱。

自动节点自动缩放

我们建议您使用节点自动缩放来减少工作量并与 Kubernetes 深度集成。对于大规模集群,建议使用托管节点组和 Karpenter

托管节点组将为您提供 Amazon EC2 Auto 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。如果你的 pod 每个 pod 使用 4 个内核,那么这可能是意料之中的(4 个内核 x 110 = 440 cores/node)。对于 3 节点集群,您处理实例事件的能力会很低,因为 1 个实例中断可能会影响 1/3 集群。你应该在工作负载中指定节点要求和容器分布,这样 Kubernetes 调度器才能正确放置工作负载。

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

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

要强制工作负载通过调度器分散并在可用区之间创建新节点,您应该使用拓扑SpreadConstraints:

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

使用相似的节点大小来实现稳定的工作负载性能

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

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

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

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

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 优化的 Amazon Linux 2 亚马逊 EKS 优化的 Bottlerocket AMI 作为节点映像。Karpenter 将自动使用最新的可用 AMI 在集群中配置新节点。托管节点组将在节点组更新期间更新 AMI,但不会在节点配置时更新 AMI ID。

对于托管节点组,当新的 AMI ID 可用于补丁版本时,您需要使用新的 AMI ID 更新 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 卷

重要

仅在 AL2 上支持此功能;AL2023 尚不支持此功能。

根据卷的类型 input/output (例如 gp3I/O)和磁盘的大小,EBS 卷有 () 配额。如果您的应用程序与主机共享一个 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 地形蓝图中的示例。如果您使用 Karpenter 来配置节点,则可以将节点用户数据blockDeviceMappings与节点用户数据一起使用来添加更多卷。

要将 EBS 卷直接挂载到您的 pod 上,您应该使用 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 ]

在需要操作系统更新速度时补丁实例

重要

只有在需要时才可以就地修补实例。亚马逊建议将基础设施视为不可变的,并像应用程序一样对通过较低环境推广的更新进行全面测试。本节在不可能的情况下适用。

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

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

亚马逊建议使用在自动声明式系统上构建、测试和推广的不可变基础设施,但是如果您需要快速修补系统,则需要为系统打补丁,并在新 AMI 可用时进行更换。由于修补和更换系统之间的时差很大,我们建议使用 AWS Systems Manager 补丁管理器在需要时自动修补节点。

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