

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

# 在 EKS 上 SageMaker HyperPod 自动缩放
<a name="sagemaker-hyperpod-eks-autoscaling"></a>

Amazon SageMaker HyperPod 为使用 EKS 编排创建的集群提供了基于 Karpenter 的托管节点自动扩展解决方案。[Karpenter](https://karpenter.sh/) 是一款开源的 Kubernetes 节点生命周期管理器，由 AWS 它构建，可优化集群扩展和成本效率。与自我管理的 Karpenter 部署不同， SageMaker HyperPod它的托管实施消除了安装、配置和维护 Karpenter 控制器的运营开销，同时提供了集成的弹性和容错能力。这种托管式自动扩展解决方案建立在[持续配置](sagemaker-hyperpod-scaling-eks.md)功能 HyperPod之上，使您能够通过自动故障处理和恢复来高效扩展用于训练和推理工作负载的计算资源。

您仅需按实际用量付费。您负责根据标准 SageMaker HyperPod定价为通过自动扩缩自动配置的所有计算实例付费。有关详细定价信息，请参阅 [Amazon SageMaker AI](https://aws.amazon.com/sagemaker/ai/pricing/)。

通过启用基于 Karpenter 的自动缩放 HyperPod，您可以访问：
+ **服务管理生命周期**- HyperPod 处理 Karpenter 的安装、更新和维护，从而消除运营开销。
+ **即时预调配** – Karpenter 将观察待处理的容器组（pod），并从按需池中为工作负载预调配所需的计算。
+ **扩展为零** – 无需维护专用的控制器基础设施，即可缩减至零节点。
+ **工作负载感知型节点选择** – Karpenter 会根据容器组（pod）要求、可用区和定价选择最佳实例类型，以最大限度地降低成本。
+ **自动节点整合** – Karpenter 会定期评估集群以寻找优化机会，并通过迁移工作负载来移除未充分利用的节点。
+ **集成弹性**-利用内置 HyperPod的容错和节点恢复机制。

以下主题说明了如何使用 Karpent HyperPod er 启用自动缩放。

**Topics**
+ [先决条件](#sagemaker-hyperpod-eks-autoscaling-prereqs)
+ [使用 Karpenter 创建用于 HyperPod 自动扩缩的 IAM 角色](sagemaker-hyperpod-eks-autoscaling-iam.md)
+ [使用 Karpenter 自动扩缩功能创建和配置 HyperPod 集群](sagemaker-hyperpod-eks-autoscaling-cluster.md)
+ [创建一个 NodeClass](sagemaker-hyperpod-eks-autoscaling-nodeclass.md)
+ [创建一个 NodePool](sagemaker-hyperpod-eks-autoscaling-nodepool.md)
+ [部署工作负载](sagemaker-hyperpod-eks-autoscaling-workload.md)

## 先决条件
<a name="sagemaker-hyperpod-eks-autoscaling-prereqs"></a>
+ 在您的 HyperPod 集群上启用持续配置。通过在创建 SageMaker HyperPod 集群`Continuous`时`--node-provisioning-mode`将设置为来启用持续预配。有关更多信息，请参阅 [Amazon EKS 上用于增强集群操作的持续预调配功能](sagemaker-hyperpod-scaling-eks.md)。
+ 已安装运行状况监控代理版本 1.0.742.0\$11.0.241.0 或更高版本。 HyperPod 群集操作和监控所必需的。在启用 Karpenter 自动扩缩之前，必须先配置此代理，以确保实现正确的集群运行状况报告和节点生命周期管理。有关更多信息，请参阅 [Health 监控系统](sagemaker-hyperpod-eks-resiliency-health-monitoring-agent.md)。
+ 仅当您的 Amazon EKS 集群上运行了 Karpenter 时，Karpenter `NodePool` 和 `NodeClaim` 版本需为 v1。
+ `NodeRecovery` 设置为自动。有关更多信息，请参阅 [自动节点恢复](sagemaker-hyperpod-eks-resiliency-node-recovery.md)。

# 使用 Karpenter 创建用于 HyperPod 自动扩缩的 IAM 角色
<a name="sagemaker-hyperpod-eks-autoscaling-iam"></a>

在以下步骤中，您将创建一个 IAM 角色，该角色允许通过基于 Karpenter 的自动扩展 SageMaker HyperPod 来管理集群中的 Kubernetes 节点。此角色为根据工作负载需求自动 HyperPod 添加和删除群集节点提供了必要的权限。

**打开 IAM 控制台**

1. 登录 AWS 管理控制台 并在 console.aws.amazon.com 上打开 IAM 控制台。

1. 在导航窗格中，选择**角色**。

1. 选择**创建角色**。

**配置信任策略**

1. 对于**可信实体类型**，选择**自定义信任策略**。

1. 在**自定义信任策略**编辑器中，将默认策略替换为以下内容：

------
#### [ JSON ]

****  

   ```
   {
       "Version":"2012-10-17",		 	 	 
       "Statement": [
           {
               "Effect": "Allow",
               "Principal": {
                   "Service": [
                       "hyperpod.sagemaker.amazonaws.com"
                   ]
               },
               "Action": "sts:AssumeRole"
           }
       ]
   }
   ```

------

1. 选择**下一步**。

**创建并附加权限策略**

由于 SageMaker HyperPod 需要 AWS 托管策略中没有的特定权限，因此您必须创建自定义策略。

1. 选择**创建策略**。这将打开一个新的浏览器标签页。

1. 选择 **JSON** 选项卡。

1. 将默认策略替换为以下内容：

------
#### [ JSON ]

****  

   ```
   {
       "Version":"2012-10-17",		 	 	 
       "Statement": [
           {
               "Effect": "Allow",
               "Action": [
                   "sagemaker:BatchAddClusterNodes",
                   "sagemaker:BatchDeleteClusterNodes"
               ],
               "Resource": "arn:aws:sagemaker:*:*:cluster/*",
               "Condition": {
                   "StringEquals": {
                       "aws:ResourceAccount": "${aws:PrincipalAccount}"
                   }
               }
           },
           {
               "Effect": "Allow",
               "Action": [
                   "kms:CreateGrant",
                   "kms:DescribeKey"
               ],
               "Resource": "arn:aws:kms:*:*:key/*",
               "Condition": {
                   "StringLike": {
                       "kms:ViaService": "sagemaker.*.amazonaws.com"
                   },
                   "Bool": {
                       "kms:GrantIsForAWSResource": "true"
                   },
                   "ForAllValues:StringEquals": {
                       "kms:GrantOperations": [
                           "CreateGrant",
                           "Decrypt",
                           "DescribeKey",
                           "GenerateDataKeyWithoutPlaintext",
                           "ReEncryptTo",
                           "ReEncryptFrom",
                           "RetireGrant"
                       ]
                   }
               }
           }
       ]
   }
   ```

------

1. 选择**下一步**。

1. 对于**策略名称**，输入 **SageMakerHyperPodKarpenterPolicy**。

1. （可选）对于**描述**，输入策略的描述。

1. 选择**创建策略**。

1. 返回到角色创建选项卡并刷新策略列表。

1. 搜索并选择您**SageMakerHyperPodKarpenterPolicy**刚刚创建的。

1. 选择**下一步**。

**命名并创建角色**

1. 对于**角色名称**，输入 `SageMakerHyperPodKarpenterRole`。

1. （可选）对于**描述**，输入角色的描述。

1. 在**步骤 1：选择可信实体**部分，确认信任策略显示了正确的服务主体。

1. 在**步骤 2：添加权限**部分，确认已附加 `SageMakerHyperPodKarpenterPolicy`。

1. 选择**创建角色**。

**记录角色 ARN**

在成功创建角色后：

1. 在**角色**列表中，选择角色名称 `SageMakerHyperPodKarpenterRole`。

1. 复制**摘要**部分中的**角色 ARN**。创建集群时需要此 ARN。 HyperPod

角色 ARN 遵循以下格式：`arn:aws:iam::ACCOUNT-ID:role/SageMakerHyperPodKarpenterRole`。

# 使用 Karpenter 自动扩缩功能创建和配置 HyperPod 集群
<a name="sagemaker-hyperpod-eks-autoscaling-cluster"></a>

在以下步骤中，您将创建一个启用了持续配置的 SageMaker HyperPod 集群，并将其配置为使用基于 Karpenter 的自动扩展。

**创建集 HyperPod 群**

1. 加载您的环境配置并从 CloudFormation堆栈中提取值。

   ```
   source .env
   SUBNET1=$(cfn-output $VPC_STACK_NAME PrivateSubnet1)
   SUBNET2=$(cfn-output $VPC_STACK_NAME PrivateSubnet2)
   SUBNET3=$(cfn-output $VPC_STACK_NAME PrivateSubnet3)
   SECURITY_GROUP=$(cfn-output $VPC_STACK_NAME NoIngressSecurityGroup)
   EKS_CLUSTER_ARN=$(cfn-output $EKS_STACK_NAME ClusterArn)
   EXECUTION_ROLE=$(cfn-output $SAGEMAKER_STACK_NAME ExecutionRole)
   SERVICE_ROLE=$(cfn-output $SAGEMAKER_STACK_NAME ServiceRole)
   BUCKET_NAME=$(cfn-output $SAGEMAKER_STACK_NAME Bucket)
   HP_CLUSTER_NAME="hyperpod-eks-test-$(date +%s)"
   EKS_CLUSTER_NAME=$(cfn-output $EKS_STACK_NAME ClusterName)
   HP_CLUSTER_ROLE=$(cfn-output $SAGEMAKER_STACK_NAME ClusterRole)
   ```

1. 将节点初始化脚本上传到 Amazon S3 存储桶。

   ```
   aws s3 cp lifecyclescripts/on_create_noop.sh s3://$BUCKET_NAME
   ```

1. 使用环境变量创建集群配置文件。

   ```
   cat > cluster_config.json << EOF
   {
       "ClusterName": "$HP_CLUSTER_NAME",
       "InstanceGroups": [
           {
               "InstanceCount": 1,
               "InstanceGroupName": "system",
               "InstanceType": "ml.c5.xlarge",
               "LifeCycleConfig": {
                   "SourceS3Uri": "s3://$BUCKET_NAME",
                   "OnCreate": "on_create_noop.sh"
               },
               "ExecutionRole": "$EXECUTION_ROLE"
           },
           {
               "InstanceCount": 0,
               "InstanceGroupName": "auto-c5-az1",
               "InstanceType": "ml.c5.xlarge",
               "LifeCycleConfig": {
                   "SourceS3Uri": "s3://$BUCKET_NAME",
                   "OnCreate": "on_create_noop.sh"
               },
               "ExecutionRole": "$EXECUTION_ROLE"
           },
           {
               "InstanceCount": 0,
               "InstanceGroupName": "auto-c5-4xaz2",
               "InstanceType": "ml.c5.4xlarge",
               "LifeCycleConfig": {
                   "SourceS3Uri": "s3://$BUCKET_NAME",
                   "OnCreate": "on_create_noop.sh"
               },
               "ExecutionRole": "$EXECUTION_ROLE",
               "OverrideVpcConfig": {
                   "SecurityGroupIds": [
                       "$SECURITY_GROUP"
                   ],
                   "Subnets": [
                       "$SUBNET2"
                   ]
               }
           },
           {
               "InstanceCount": 0,
               "InstanceGroupName": "auto-g5-az3",
               "InstanceType": "ml.g5.xlarge",
               "LifeCycleConfig": {
                   "SourceS3Uri": "s3://$BUCKET_NAME",
                   "OnCreate": "on_create_noop.sh"
               },
               "ExecutionRole": "$EXECUTION_ROLE",
               "OverrideVpcConfig": {
                   "SecurityGroupIds": [
                       "$SECURITY_GROUP"
                   ],
                   "Subnets": [
                       "$SUBNET3"
                   ]
               }
           }
       ],
       "VpcConfig": {
           "SecurityGroupIds": [
               "$SECURITY_GROUP"
           ],
           "Subnets": [
               "$SUBNET1"
           ]
       },
       "Orchestrator": {
           "Eks": {
               "ClusterArn": "$EKS_CLUSTER_ARN"
           }
       },
       "ClusterRole": "$HP_CLUSTER_ROLE",
       "AutoScaling": {
           "Mode": "Enable",
           "AutoScalerType": "Karpenter"
       },
       "NodeProvisioningMode": "Continuous"
   }
   EOF
   ```

1. 运行以下命令来创建您的 HyperPod 集群。

   ```
   aws sagemaker create-cluster --cli-input-json file://./cluster_config.json
   ```

1. 集群创建过程大约需要 20 分钟。监控集群状态，直到两者都 ClusterStatus 显示， AutoScaling.Status 都显示出来 InService。

1. 保存集群 ARN 以供后续操作使用。

   ```
   HP_CLUSTER_ARN=$(aws sagemaker describe-cluster --cluster-name $HP_CLUSTER_NAME \
      --output text --query ClusterArn)
   ```

**启用 Karpenter 自动扩缩**

1. 运行以下命令，在任意具有持续节点预调配模式的预先存在的集群上，启用基于 Karpenter 的自动扩缩。

   ```
   aws sagemaker update-cluster \
       --cluster-name $HP_CLUSTER_NAME \
       --auto-scaling Mode=Enable,AutoScalerType=Karpenter \
       --cluster-role $HP_CLUSTER_ROLE
   ```

1. 确认已成功启用 Karpenter：

   ```
   aws sagemaker describe-cluster --cluster-name $HP_CLUSTER_NAME --query 'AutoScaling'
   ```

1. 预期输出：

   ```
   {
       "Mode": "Enable",
       "AutoScalerType": "Karpenter",
       "Status": "InService"
   }
   ```

等待显示`Status``InService`后再继续配置 NodeClass 和 NodePool。

# 创建一个 NodeClass
<a name="sagemaker-hyperpod-eks-autoscaling-nodeclass"></a>

**重要**  
您的实例组必须从 0 个节点开始，并让 Karpenter 处理自动扩缩。如果初始节点数大于 0，Karpenter 会将其缩减至 0。

节点类（`NodeClass`）定义了适用于 Amazon EKS 集群中节点组的基础设施级别设置，包括网络配置、存储设置和资源标记等。A `HyperPodNodeClass` 是一种自定义项`NodeClass`，它映射到中预先创建的实例组 SageMaker HyperPod，它定义了在 Karpenter 的自动扩展决策中支持哪些实例类型和可用区的限制。

**创建节点类的注意事项**
+ 您可以在 `NodeClass` 中最多指定 10 个实例组。
+ 在 MIG（多实例 GPU）中使用 GPU 分区时，Karpenter 可以自动为节点配置支持 MiG 的实例组。确保您的实例组包含 MIG 支持的实例类型（ml.p4d.24xlarge、ml.p5.48xlarge 或 ml.p5e/p5en.48xlarge），并在创建集群时配置相应的 MIG 标签。有关配置 GPU 分区的更多信息，请参阅[在亚马逊中使用 GPU 分区 SageMaker HyperPod](sagemaker-hyperpod-eks-gpu-partitioning.md)。
+ 如果将自定义标签应用于实例组，则可以在查询`HyperpodNodeClass`状态时在`desiredLabels`字段中查看它们。这包括 MIG 配置标签，例如。`nvidia.com/mig.config`当传入的任务请求 MIG 资源时，Karpenter 将使用相应的 MIG 标签自动扩展实例。
+ 如果您选择删除实例组，我们建议您先将其从您的集群中删除，`NodeClass`然后再将其从 HyperPod集群中删除。如果删除一个正在 `NodeClass` 中使用的实例组，则 `NodeClass` 将被标记非 `Ready` 状态且无法进行预调配，并且在从 `NodeClass` 中移除该实例组之前，该实例组不会用于后续扩展操作。
+ 当您从 `NodeClass` 中移除实例组时，Karpenter 将检测到实例组中由 Karpenter 管理的节点存在偏差，并将根据中断预算控制措施中断节点。
+ 实例组所使用的子网应属于同一个可用区。子网是通过 `OverrideVpcConfig` 在实例组级别或集群级别指定的。默认情况下，将使用 `VpcConfig`。
+ 此时仅支持按需容量。不支持具有训练计划或预留容量的实例组。
+ 不支持带 `DeepHealthChecks (DHC)` 的实例组。这是因为 DHC 大约需要 60-90 分钟才能完成，在此期间，容器组（pod）将保持待处理状态，这可能会导致过度预调配。

以下步骤展示了如何创建 `NodeClass`。

1. 创建一个包含 `NodeClass` 配置的 YAML 文件（例如 nodeclass.yaml）。

1. 使用 kubectl 将此配置应用于集群。

1. 在 `NodePool` 配置中引用 `NodeClass`。

1. 以下示例 `NodeClass` 使用 ml.c5.xlarge 和 ml.c5.4xlarge 实例类型：

   ```
   apiVersion: karpenter.sagemaker.amazonaws.com/v1
   kind: HyperpodNodeClass
   metadata:
     name: sample-nc
   spec:
     instanceGroups:
       # name of InstanceGroup in HyperPod cluster. InstanceGroup needs to pre-created
       # MaxItems: 10
       - auto-c5-xaz1
       - auto-c5-4xaz2
   ```

1. 应用配置：

   ```
   kubectl apply -f nodeclass.yaml
   ```

1. 监控 NodeClass 状态以确保状态中的 “就绪” 条件设置为 True：

   ```
   kubectl get hyperpodnodeclass sample-nc -o yaml
   ```

   ```
   apiVersion: karpenter.sagemaker.amazonaws.com/v1
   kind: HyperpodNodeClass
   metadata:
     creationTimestamp: "<timestamp>"
     name: sample-nc
     uid: <resource-uid>
   spec:
     instanceGroups:
     - auto-c5-az1
     - auto-c5-4xaz2
   status:
     conditions:
     // true when all IGs in the spec are present in SageMaker cluster, false otherwise
     - lastTransitionTime: "<timestamp>"
       message: ""
       observedGeneration: 3
       reason: InstanceGroupReady
       status: "True"
       type: InstanceGroupReady
     // true if subnets of IGs are discoverable, false otherwise
     - lastTransitionTime: "<timestamp>"
       message: ""
       observedGeneration: 3
       reason: SubnetsReady
       status: "True"
       type: SubnetsReady
     // true when all dependent resources are Ready [InstanceGroup, Subnets]
     - lastTransitionTime: "<timestamp>"
       message: ""
       observedGeneration: 3
       reason: Ready
       status: "True"
       type: Ready
     instanceGroups:
     - desiredLabels:
       - key: <custom_label_key>
         value: <custom_label_value>
       - key: nvidia.com/mig.config
         value: all-1g.5gb
       instanceTypes:
       - ml.c5.xlarge
       name: auto-c5-az1
       subnets:
       - id: <subnet-id>
         zone: <availability-zone-a>
         zoneId: <zone-id-a>
     - instanceTypes:
       - ml.c5.4xlarge
       name: auto-c5-4xaz2
       subnets:
       - id: <subnet-id>
         zone: <availability-zone-b>
         zoneId: <zone-id-b>
   ```

# 创建一个 NodePool
<a name="sagemaker-hyperpod-eks-autoscaling-nodepool"></a>

`NodePool` 对 Karpenter 可创建的节点，以及可在这些节点上运行的容器组（pod）设置了限制。可将 `NodePool` 配置为执行以下操作：
+ 将节点创建限制为特定的区域、实例类型和计算机架构。
+ 定义标签或污点以限制可在 Karpenter 所创建的节点上运行的容器组（pod）。

**注意**  
HyperPod 提供者支持一组有限的众所周知的 Kubernetes 和 Karpenter 要求，如下所述。

以下步骤展示了如何创建 `NodePool`。

1. 创建一个名为 nodepool.yaml 的 YAML 文件，该文件包含所需的 `NodePool` 配置。

1. 您可以使用以下示例配置。

   在 `Conditions` 下方查找 `Ready` 以确认所有依赖资源均运行正常。

   ```
   apiVersion: karpenter.sh/v1
   kind: NodePool
   metadata:
    name: sample-np
   spec:
    template:
      spec:
        nodeClassRef:
         group: karpenter.sagemaker.amazonaws.com
         kind: HyperpodNodeClass
         name: multiazc5
        expireAfter: Never
        requirements:
           - key: node.kubernetes.io/instance-type
             operator: Exists
   ```

1. 将 `NodePool` 应用于集群：

   ```
   kubectl apply -f nodepool.yaml
   ```

1. 监控 `NodePool` 状态，确保状态中的 `Ready` 条件设置为 `True`：

   ```
   kubectl get nodepool sample-np -oyaml
   ```

   ```
   apiVersion: karpenter.sh/v1
   kind: NodePool
   metadata:
     name: <nodepool-name>
     uid: <resource-uid>
     ...
   spec:
     disruption:
       budgets:
       - nodes: 90%
       consolidateAfter: 0s
       consolidationPolicy: WhenEmptyOrUnderutilized
     template:
       spec:
         expireAfter: 720h
         nodeClassRef:
           group: karpenter.sagemaker.amazonaws.com
           kind: HyperpodNodeClass
           name: <nodeclass-name>
         requirements:
         - key: node.kubernetes.io/instance-type
           operator: Exists
   status:
     conditions:
     - lastTransitionTime: "<timestamp>"
       message: ""
       observedGeneration: 2
       reason: ValidationSucceeded
       status: "True"
       type: ValidationSucceeded
     - lastTransitionTime: "<timestamp>"
       message: ""
       observedGeneration: 2
       reason: NodeClassReady
       status: "True"
       type: NodeClassReady
     - lastTransitionTime: "<timestamp>"
       message: ""
       observedGeneration: 2
       reason: Ready
       status: "True"
       type: Ready
   ```

**Karpenter 提供商 HyperPod支持的标签**

这些是您可以在 `NodePool` 配置中指定的可选约束和要求。


|  要求类型  |  用途  |  使用 Case/Supported 值  |  建议  | 
| --- | --- | --- | --- | 
|  实例类型（`node.kubernetes.io/instance-type`）  |  控制 Karpenter 可以从哪些 SageMaker 实例类型中进行选择  |  不要仅限定于 ml.c5.xlarge，而是让 Karpenter 从实例组中的所有可用类型中进行选择  |  将此项保留为未定义状态，或使用 Exists 操作符，以便 Karpenter 在选择高性价比实例类型时拥有最大灵活性。  | 
|  可用区（`topology.kubernetes.io/zone`）  |  控制可以在哪些 AWS 可用区中创建节点  |  特定的区域名称，例如 us-east-1c。当您出于延迟或合规性原因，需要容器组（pod）在特定区域内运行时使用。  | 不适用 | 
|  架构（`kubernetes.io/arch`）  |  指定 CPU 架构  |  仅 amd64（目前不支持 ARM）  |  不适用  | 

# 部署工作负载
<a name="sagemaker-hyperpod-eks-autoscaling-workload"></a>

以下示例演示了使用 Karpenter 进行 HyperPod 自动缩放如何根据工作负载需求自动配置节点。这些示例展示了基本扩展行为和多可用区域分布模式。

**部署简单的工作负载**

1. 以下 Kubernetes 部署包括的容器组（pod）为每个副本或容器组（pod）请求 1 个 CPU 和 256M 内存。在此场景中，容器组（pod）尚未启动。

   ```
   kubectl apply -f https://raw.githubusercontent.com/aws/karpenter-provider-aws/refs/heads/main/examples/workloads/inflate.yaml
   ```

1. 要测试纵向扩展过程，请运行以下命令。Karpenter 将向集群添加新节点。

   ```
   kubectl scale deployment inflate --replicas 10
   ```

1. 要测试缩减过程，请运行以下命令。Karpenter 将从集群中移除节点。

   ```
   kubectl scale deployment inflate --replicas 0
   ```

**将工作负载部署到多个工作负载 AZs**

1. 运行以下命令部署运行 Kubernetes 部署的工作负载，其中部署中的容器组（pod）需要在不同的可用区之间均匀分布，且最大偏差值为 1。

   ```
   kubectl apply -f https://raw.githubusercontent.com/aws/karpenter-provider-aws/refs/heads/main/examples/workloads/spread-zone.yaml
   ```

1. 运行以下命令调整容器组（pod）数：

   ```
   kubectl scale deployment zone-spread --replicas 15
   ```

   Karpenter 将向集群中添加新节点，且至少会在一个不同的可用区中添加一个节点。

有关更多示例，请参阅上的 [Karpenter 示例工作负载](https://github.com/aws/karpenter-provider-aws/tree/main/examples/workloads)。 GitHub