

 **帮助改进此页面** 

要帮助改进本用户指南，请选择位于每个页面右侧窗格中的**在 GitHub 上编辑此页面**链接。

# 自定义 Amazon EKS 节点中的辅助网络接口
<a name="cni-custom-network-tutorial"></a>

开始教程前，请完成以下任务：
+ 查看注意事项
+ 了解适用于 Kubernetes 的 Amazon VPC CNI 插件如何创建辅助网络接口，并将 IP 地址分配给容器组（pod）。有关更多信息，请参阅 GitHub 上的 [ENI 分配](https://github.com/aws/amazon-vpc-cni-k8s#eni-allocation)。
+ 在您的设备或 AWS CloudShell 上安装和配置 AWS 命令行界面（AWS CLI）的版本 `2.12.3` 或更高版本，或版本 `1.27.160` 或更高版本。要查看当前版本，请使用 `aws --version | cut -d / -f2 | cut -d ' ' -f1`。`yum`、`apt-get` 或适用于 macOS 的 Homebrew 等软件包管理器通常比 AWS CLI 的最新版本落后几个版本。要安装最新版本，请参阅《AWS 命令行界面用户指南》**中的[安装](https://docs.aws.amazon.com/cli/latest/userguide/cli-chap-install.html)和[使用 aws configure 快速配置](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-quickstart.html#cli-configure-quickstart-config)。AWS CloudShell 中安装的 AWS CLI 版本也可能比最新版本落后几个版本。要对其进行更新，请参阅《AWS CloudShell 用户指南》**中的[将 AWS CLI 安装到您的主目录](https://docs.aws.amazon.com/cloudshell/latest/userguide/vm-specs.html#install-cli-software)。
+ 您的设备或 AWS CloudShell 上安装了 `kubectl` 命令行工具。要安装或升级 `kubectl`，请参阅 [设置 `kubectl` 和 `eksctl`](install-kubectl.md)。
+ 我们建议您在 Bash Shell 中完成本主题中的步骤。如果您没有使用 Bash Shell，则某些脚本命令（例如行延续字符以及变量的设置和使用方式）需要调整 Shell。此外，您的 Shell 的引用和转义规则可能有所不同。有关更多信息，请参阅《AWS 命令行界面用户指南》中的[在 AWS CLI 中将引号和字符串结合使用](https://docs.aws.amazon.com/cli/latest/userguide/cli-usage-parameters-quoting-strings.html)。

在本教程中，我们建议使用 example values，除非有说明要替换它们。您可以在完成生成集群的步骤时替换任何示例值。我们建议在同一终端完成所有步骤。这是因为变量是在整个步骤中设置和使用的，并且不会存在于不同的终端中。

本主题中的命令使用[使用 AWS CLI 示例](https://docs.aws.amazon.com/cli/latest/userguide/welcome-examples.html)中列出的惯例进行格式化。如果从命令行运行命令，且该命令行针对的资源位于与您正在使用的 AWS CLI [配置文件](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-quickstart.html#cli-configure-quickstart-profiles)中定义的默认 AWS 区域不同的 AWS 区域，则需要向命令添加 `--region us-west-2`，并将 `us-west-2` 替换为 AWS 区域。

当您想将自定义联网部署到生产集群时，请跳至 [步骤 2：配置 VPC](#custom-networking-configure-vpc)。

## 步骤 1：创建测试 VPC 和集群
<a name="custom-networking-create-cluster"></a>

以下步骤帮助您创建测试 VPC 和集群并为该集群配置自定义联网。我们不建议将测试集群用于生产工作负载，因为本主题没有涵盖在生产集群上可能使用的几种不相关的功能。有关更多信息，请参阅 [创建一个 Amazon EKS 集群。](create-cluster.md)。

1. 运行以下命令以定义 `account_id` 变量。

   ```
   account_id=$(aws sts get-caller-identity --query Account --output text)
   ```

1. 创建 VPC。

   1. 如果您要部署到测试系统，则请使用 Amazon EKS AWS CloudFormation 模板创建 VPC。

      ```
      aws cloudformation create-stack --stack-name my-eks-custom-networking-vpc \
        --template-url https://s3.us-west-2.amazonaws.com/amazon-eks/cloudformation/2020-10-29/amazon-eks-vpc-private-subnets.yaml \
        --parameters ParameterKey=VpcBlock,ParameterValue=192.168.0.0/24 \
        ParameterKey=PrivateSubnet01Block,ParameterValue=192.168.0.64/27 \
        ParameterKey=PrivateSubnet02Block,ParameterValue=192.168.0.96/27 \
        ParameterKey=PublicSubnet01Block,ParameterValue=192.168.0.0/27 \
        ParameterKey=PublicSubnet02Block,ParameterValue=192.168.0.32/27
      ```

   1. AWS CloudFormation 堆栈需要几分钟的时间来创建。要检查堆栈的部署状态，请运行以下命令。

      ```
      aws cloudformation describe-stacks --stack-name my-eks-custom-networking-vpc --query Stacks\[\].StackStatus  --output text
      ```

      在命令的输出变成 `CREATE_COMPLETE` 之前，请勿继续执行下一步。

   1. 使用模板创建的私有子网 ID 的值定义变量。

      ```
      subnet_id_1=$(aws cloudformation describe-stack-resources --stack-name my-eks-custom-networking-vpc \
          --query "StackResources[?LogicalResourceId=='PrivateSubnet01'].PhysicalResourceId" --output text)
      subnet_id_2=$(aws cloudformation describe-stack-resources --stack-name my-eks-custom-networking-vpc \
          --query "StackResources[?LogicalResourceId=='PrivateSubnet02'].PhysicalResourceId" --output text)
      ```

   1. 使用上一步中检索到的子网的可用区定义变量。

      ```
      az_1=$(aws ec2 describe-subnets --subnet-ids $subnet_id_1 --query 'Subnets[*].AvailabilityZone' --output text)
      az_2=$(aws ec2 describe-subnets --subnet-ids $subnet_id_2 --query 'Subnets[*].AvailabilityZone' --output text)
      ```

1. 创建集群 IAM 角色。

   1. 运行以下命令以创建 IAM 信任策略 JSON 文件。

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

   1. 创建 Amazon EKS 集群 IAM 角色。如有必要，使用您在上一步中将文件写入到的计算机上的路径为 `eks-cluster-role-trust-policy.json` 添加前缀。该命令将您在上一步中创建的信任策略与角色关联。要创建 IAM 角色，必须为正在创建角色的 [IAM 主体](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles.html#iam-term-principal)分配 `iam:CreateRole` 操作（权限）。

      ```
      aws iam create-role --role-name myCustomNetworkingAmazonEKSClusterRole --assume-role-policy-document file://"eks-cluster-role-trust-policy.json"
      ```

   1. 将名为 [AmazonEKSClusterPolicy](https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AmazonEKSClusterPolicy.html#AmazonEKSClusterPolicy-json) 的 Amazon EKS 托管 IAM 策略附加到角色。要将 IAM policy 附加到某个 [IAM 主体](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles.html#iam-term-principal)，必须为附加该策略的主体分配以下 IAM 操作（权限）之一：`iam:AttachUserPolicy` 或 `iam:AttachRolePolicy`。

      ```
      aws iam attach-role-policy --policy-arn arn:aws:iam::aws:policy/AmazonEKSClusterPolicy --role-name myCustomNetworkingAmazonEKSClusterRole
      ```

1. 创建 Amazon EKS 集群并配置您的设备以与其进行通信。

   1. 创建集群。

      ```
      aws eks create-cluster --name my-custom-networking-cluster \
         --role-arn arn:aws:iam::$account_id:role/myCustomNetworkingAmazonEKSClusterRole \
         --resources-vpc-config subnetIds="$subnet_id_1","$subnet_id_2"
      ```
**注意**  
您可能会收到一个错误，指示请求中的可用区之一没有足够容量来创建 Amazon EKS 集群。如果发生这种情况，错误输出将包含可支持新集群的可用区。再次尝试使用至少两个位于您账户中支持的可用区的子网创建集群。有关更多信息，请参阅 [容量不足](troubleshooting.md#ice)。

   1. 创建集群需要几分钟时间。要检查集群的部署状态，请运行以下命令。

      ```
      aws eks describe-cluster --name my-custom-networking-cluster --query cluster.status
      ```

      在命令的输出变成 `"ACTIVE"` 之前，请勿继续执行下一步。

   1. 配置 `kubectl` 以与集群通信。

      ```
      aws eks update-kubeconfig --name my-custom-networking-cluster
      ```

## 步骤 2：配置 VPC
<a name="custom-networking-configure-vpc"></a>

本教程需要在 [步骤 1：创建测试 VPC 和集群](#custom-networking-create-cluster) 中创建的 VPC。对于生产集群，通过将所有示例值替换为您自己的值来相应调整 VPC 的步骤。

1. 确认当前安装的适用于 Kubernetes 的 Amazon VPC CNI 插件版本为最新版本。要确定 Amazon EKS 附加组件类型的最新版本并将您的版本更新至此版本，请参阅 [更新 Amazon EKS 附加组件](updating-an-add-on.md)。要确定自行管理的附加组件类型的最新版本并将您的版本更新至此版本，请参阅 [使用 Amazon VPC CNI 将 IP 分配给容器组（pod）](managing-vpc-cni.md)。

1. 检索您的集群 VPC 的 ID，并将其存储在变量中，以便在后续步骤中使用。

   ```
   vpc_id=$(aws eks describe-cluster --name my-custom-networking-cluster --query "cluster.resourcesVpcConfig.vpcId" --output text)
   ```

1. 将另一个无类别域间路由（CIDR）块与集群的 VPC 关联。CIDR 块不能与任何现有关联的 CIDR 块重叠。

   1. 查看与您的 VPC 关联的当前 CIDR 块。

      ```
      aws ec2 describe-vpcs --vpc-ids $vpc_id \
          --query 'Vpcs[*].CidrBlockAssociationSet[*].{CIDRBlock: CidrBlock, State: CidrBlockState.State}' --out table
      ```

      示例输出如下。

      ```
      ----------------------------------
      |          DescribeVpcs          |
      +-----------------+--------------+
      |    CIDRBlock    |    State     |
      +-----------------+--------------+
      |  192.168.0.0/24 |  associated  |
      +-----------------+--------------+
      ```

   1. 将额外 CIDR 块与 VPC 关联。在以下命令中，替换 CIDR 块的值。有关更多信息，请参阅《Amazon VPC 用户指南》中的[将额外的 IPv4 CIDR 块与 VPC 关联](https://docs.aws.amazon.com/vpc/latest/userguide/modify-vpcs.html#add-ipv4-cidr)。

      ```
      aws ec2 associate-vpc-cidr-block --vpc-id $vpc_id --cidr-block 192.168.1.0/24
      ```

   1. 确认新区块已关联。

      ```
      aws ec2 describe-vpcs --vpc-ids $vpc_id --query 'Vpcs[*].CidrBlockAssociationSet[*].{CIDRBlock: CidrBlock, State: CidrBlockState.State}' --out table
      ```

      示例输出如下。

      ```
      ----------------------------------
      |          DescribeVpcs          |
      +-----------------+--------------+
      |    CIDRBlock    |    State     |
      +-----------------+--------------+
      |  192.168.0.0/24 |  associated  |
      |  192.168.1.0/24 |  associated  |
      +-----------------+--------------+
      ```

   在您的新 CIDR 区块的 `State` 为 `associated` 之前，请勿继续执行下一步。

1. 在现有子网所在的每个可用区中创建要使用的任意数量的子网。指定一个在之前的步骤中与 VPC 关联的 CIDR 块内的 CIDR 块。

   1. 创建新子网。在以下命令中，替换 CIDR 块的值。子网必须在不同于现有子网所在的 VPC CIDR 块中创建子网，但与现有子网位于同一可用区中。在此示例中，在当前私有子网所在的每个可用区的新 CIDR 块中创建一个子网。创建的子网的 ID 存储在变量中以供后续步骤使用。`Name` 值与分配给上一步中使用 Amazon EKS VPC 模板创建的子网的值相匹配。名称不是必填项。您可以使用不同的名称。

      ```
      new_subnet_id_1=$(aws ec2 create-subnet --vpc-id $vpc_id --availability-zone $az_1 --cidr-block 192.168.1.0/27 \
          --tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=my-eks-custom-networking-vpc-PrivateSubnet01},{Key=kubernetes.io/role/internal-elb,Value=1}]' \
          --query Subnet.SubnetId --output text)
      new_subnet_id_2=$(aws ec2 create-subnet --vpc-id $vpc_id --availability-zone $az_2 --cidr-block 192.168.1.32/27 \
          --tag-specifications 'ResourceType=subnet,Tags=[{Key=Name,Value=my-eks-custom-networking-vpc-PrivateSubnet02},{Key=kubernetes.io/role/internal-elb,Value=1}]' \
          --query Subnet.SubnetId --output text)
      ```
**重要**  
默认情况下，您的新子网与您的 VPC 的[主路由表](https://docs.aws.amazon.com/vpc/latest/userguide/VPC_Route_Tables.html#RouteTables)隐式关联。此路由表允许在 VPC 中部署的所有资源之间进行通信。但是，它不允许与 IP 地址位于与您的 VPC 关联的 CIDR 块之外的资源进行通信。您可以将自己的路由表关联到子网以改变此行为。有关更多信息，请参阅《Amazon VPC 用户指南》中的[子网路由表](https://docs.aws.amazon.com/vpc/latest/userguide/VPC_Route_Tables.html#subnet-route-tables)。

   1. 查看 VPC 中的当前子网。

      ```
      aws ec2 describe-subnets --filters "Name=vpc-id,Values=$vpc_id" \
          --query 'Subnets[*].{SubnetId: SubnetId,AvailabilityZone: AvailabilityZone,CidrBlock: CidrBlock}' \
          --output table
      ```

      示例输出如下。

      ```
      ----------------------------------------------------------------------
      |                           DescribeSubnets                          |
      +------------------+--------------------+----------------------------+
      | AvailabilityZone |     CidrBlock      |         SubnetId           |
      +------------------+--------------------+----------------------------+
      |  us-west-2d      |  192.168.0.0/27    |     subnet-example1        |
      |  us-west-2a      |  192.168.0.32/27   |     subnet-example2        |
      |  us-west-2a      |  192.168.0.64/27   |     subnet-example3        |
      |  us-west-2d      |  192.168.0.96/27   |     subnet-example4        |
      |  us-west-2a      |  192.168.1.0/27    |     subnet-example5        |
      |  us-west-2d      |  192.168.1.32/27   |     subnet-example6        |
      +------------------+--------------------+----------------------------+
      ```

      您可以看到您创建的 `192.168.1.0` CIDR 块中的子网与 `192.168.0.0` CIDR 块中的子网在同一个可用区中。

## 步骤 3：配置 Kubernetes 资源
<a name="custom-networking-configure-kubernetes"></a>

1. 将 `AWS_VPC_K8S_CNI_CUSTOM_NETWORK_CFG` 环境变量设置为 `aws-node` DaemonSet 中的 `true`。

   ```
   kubectl set env daemonset aws-node -n kube-system AWS_VPC_K8S_CNI_CUSTOM_NETWORK_CFG=true
   ```

1. 检索[集群安全组](sec-group-reqs.md)的 ID，并将其存储在变量中，以便在后续步骤中使用。当您创建集群时，Amazon EKS 会自动创建此安全组。

   ```
   cluster_security_group_id=$(aws eks describe-cluster --name my-custom-networking-cluster --query cluster.resourcesVpcConfig.clusterSecurityGroupId --output text)
   ```

1.  为希望在其中部署容器组（pod）的每个子网创建 `ENIConfig` 自定义资源。

   1. 为每个网络接口配置创建一个唯一的文件。

      以下命令为您在上一步中创建的两个子网创建单独的 `ENIConfig` 文件。`name` 的值必须是唯一的。该名称与子网所在的可用区相同。将集群安全组分配给 `ENIConfig`。

      ```
      cat >$az_1.yaml <<EOF
      apiVersion: crd.k8s.amazonaws.com/v1alpha1
      kind: ENIConfig
      metadata:
        name: $az_1
      spec:
        securityGroups:
          - $cluster_security_group_id
        subnet: $new_subnet_id_1
      EOF
      ```

      ```
      cat >$az_2.yaml <<EOF
      apiVersion: crd.k8s.amazonaws.com/v1alpha1
      kind: ENIConfig
      metadata:
        name: $az_2
      spec:
        securityGroups:
          - $cluster_security_group_id
        subnet: $new_subnet_id_2
      EOF
      ```

      对于生产集群，您可以对以前的命令进行以下更改：
      + 将 \$1cluster\$1security\$1group\$1id 替换为希望用于每个 `ENIConfig` 的现有[安全组](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-security-groups.html)的 ID。
      + 我们建议尽可能将 `ENIConfigs` 命名为与您将使用 `ENIConfig` 的可用区相同的名称。您可能需要出于各种原因为您的 `ENIConfigs` 使用与可用区名称不同的名称。例如，如果您在同一可用区中有两个以上的子网，并且想将它们同时用于自定义联网，则需要将多个 `ENIConfigs` 用于同一个可用区。由于每个 `ENIConfig` 都需要一个唯一名称，您不能使用可用区名称命名多个 `ENIConfigs`。

        如果 `ENIConfig` 名称与可用区名称不同，请将 \$1az\$11 和 \$1az\$12 替换为上一个命令中您自己的名称，并且稍后在本教程中[使用 ENIConfig 注释节点](#custom-networking-annotate-eniconfig)。
**注意**  
如果未指定与生产集群结合使用的有效安全组并且您使用的是：
      + 版本 `1.8.0` 或更高版本的适用于 Kubernetes 的 Amazon VPC CNI 插件，则会使用与节点的主弹性网络接口关联的安全组。
      + `1.8.0` 之前的适用于 Kubernetes 的 Amazon VPC CNI 插件版本，则 VPC 的默认安全组将分配给辅助网络接口。
**重要**  
 `AWS_VPC_K8S_CNI_EXTERNALSNAT=false` 是适用于 Kubernetes 的 Amazon VPC CNI 插件配置中的默认设置。如果您使用的是默认设置，则发往不在与 VPC 关联的 CIDR 块之一内的 IP 地址的流量将使用节点主网络接口的安全组和子网。在用于创建辅助网络接口的 `ENIConfigs` 中定义的子网和安全组不用于此流量。有关该设置的更多信息，请参阅 [为容器组（pod）启用出站互联网访问权限](external-snat.md)。
如果您还将安全组用于容器组（pod），则会使用 `SecurityGroupPolicy` 中指定的安全组而不是 `ENIConfigs` 中指定的安全组。有关更多信息，请参阅 [将安全组分配给各个容器组（pod）](security-groups-for-pods.md)。

   1. 使用以下命令将您创建的每个自定义资源文件应用于您的集群。

      ```
      kubectl apply -f $az_1.yaml
      kubectl apply -f $az_2.yaml
      ```

1. 确认您的 `ENIConfigs` 已创建。

   ```
   kubectl get ENIConfigs
   ```

   示例输出如下。

   ```
   NAME         AGE
   us-west-2a   117s
   us-west-2d   105s
   ```

1. 如果您在生产集群上启用自定义联网并将您的 `ENIConfigs` 命名为您将它们用于可用区之外的其他名称，然后跳到[下一步](#custom-networking-deploy-nodes)以部署 Amazon EC2 节点。

   启用 Kubernetes 以将可用区的 `ENIConfig` 自动应用于在您的集群中创建的任何新 Amazon EC2 节点。

   1. 对于本教程中的测试集群，请跳至[下一步](#custom-networking-automatically-apply-eniconfig)。

      对于生产集群，请检查带有 ` [ENI\$1CONFIG\$1ANNOTATION\$1DEF](https://github.com/aws/amazon-vpc-cni-k8s#eni_config_annotation_def) ` 环境变量的键 `k8s.amazonaws.com/eniConfig` 的注释是否存在于 `aws-node` DaemonSet 的容器规范中。

      ```
      kubectl describe daemonset aws-node -n kube-system | grep ENI_CONFIG_ANNOTATION_DEF
      ```

      如果返回输出，则注释存在。如果没有返回输出，则未设置此变量。对于生产集群，您可以使用此设置或以下步骤中的设置。如果使用此设置，它将覆盖以下步骤中的设置。在本教程中，将使用下一步中的设置。

   1.  更新 `aws-node` DaemonSet 以将可用区的 `ENIConfig` 自动应用于在集群中创建的任何新 Amazon EC2 节点。

      ```
      kubectl set env daemonset aws-node -n kube-system ENI_CONFIG_LABEL_DEF=topology.kubernetes.io/zone
      ```

## 步骤 4：部署 Amazon EC2 节点
<a name="custom-networking-deploy-nodes"></a>

1. 创建节点 IAM 角色。

   1. 运行以下命令以创建 IAM 信任策略 JSON 文件。

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

   1. 创建 IAM 角色并将返回的 Amazon 资源名称（ARN）存储在变量中以供后续步骤使用。

      ```
      node_role_arn=$(aws iam create-role --role-name myCustomNetworkingNodeRole --assume-role-policy-document file://"node-role-trust-relationship.json" \
          --query Role.Arn --output text)
      ```

   1. 将三个所需的 IAM 托管策略附加到 IAM 角色。

      ```
      aws iam attach-role-policy \
        --policy-arn arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy \
        --role-name myCustomNetworkingNodeRole
      aws iam attach-role-policy \
        --policy-arn arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly \
        --role-name myCustomNetworkingNodeRole
      aws iam attach-role-policy \
          --policy-arn arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy \
          --role-name myCustomNetworkingNodeRole
      ```
**重要**  
为简单起见，在本教程中，将 [AmazonEKS\$1CNI\$1Policy](https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AmazonEKS_CNI_Policy.html) 策略附加到节点 IAM 角色。但是，在生产集群中，我们建议将该策略附加到仅用于适用于 Kubernetes 的 Amazon VPC CNI 插件的单独 IAM 角色。有关更多信息，请参阅 [配置 Amazon VPC CNI 插件以使用 IRSA](cni-iam-role.md)。

1. 创建以下一种类型的节点组。要确定您想要部署的实例类型，请参阅 [选择最优的 Amazon EC2 节点实例类型](choosing-instance-type.md)。在本教程中，请完成 **Managed**（托管）、**Without a launch template or with a launch template without an AMI ID specified**（没有启动模板或带有未指定 AMI ID 的启动模板）选项。如果要将节点组用于生产工作负载，我们建议在部署节点组之前熟悉所有的[托管式节点组](create-managed-node-group.md)和[自主管理型节点组](worker.md)选项。
   +  **托管**：使用以下选项之一部署您的节点组：
     +  **没有启动模板或者带有未指定 AMI ID 的启动模板** – 运行以下命令。在本教程中，使用 example values。对于生产节点组，将所有的 example values 替换为您自己的值。节点组名称的长度不能超过 63 个字符。它必须以字母或数字开头，但也可以包括其余字符的连字符和下划线。

       ```
       aws eks create-nodegroup --cluster-name my-custom-networking-cluster --nodegroup-name my-nodegroup \
           --subnets $subnet_id_1 $subnet_id_2 --instance-types t3.medium --node-role $node_role_arn
       ```
     +  **使用具有指定 AMI ID 的启动模板** 

       1. 确定 Amazon EKS 为节点推荐的最大容器组（pod）数量。按照 中的说明进行操作，将 `--cni-custom-networking-enabled` 添加至该主题中的步骤 3。请记下输出的内容，以便在下一个步骤中使用。

       1. 在启动模板中，指定 Amazon EKS 优化的 AMI ID，或者指定基于 Amazon EKS 优化 AMI 构建的自定义 AMI，然后[使用启动模板部署节点组](launch-templates.md)并在启动模板中提供以下用户数据。此用户数据会将实际参数传递到 `NodeConfig` 规范中。有关 NodeConfig 的更多信息，请参阅 [NodeConfig API reference](https://awslabs.github.io/amazon-eks-ami/nodeadm/doc/api/#nodeconfig)。您可以将 `20` 替换为上一步的值（建议）或您自己的值。

          ```
          ---
          MIME-Version: 1.0
          Content-Type: multipart/mixed; boundary="BOUNDARY"
          --BOUNDARY
          Content-Type: application/node.eks.aws
          
          ---
          apiVersion: node.eks.aws/v1alpha1
          kind: NodeConfig
          spec:
            cluster:
              name: my-cluster
              ...
              kubelet:
                config:
                  maxPods: 20
          ```

          如果您创建的自定义 AMI 不是基于 Amazon EKS 优化版 AMI 构建的，则需要自行自定义创建配置。
   +  **自行管理** 

     1. 确定 Amazon EKS 为节点推荐的最大容器组（pod）数量。按照  中的说明进行操作，将 `--cni-custom-networking-enabled` 添加到该主题的步骤 3。请记下输出的内容，以便在下一个步骤中使用。

     1. 按照 [创建自行管理的 Amazon Linux 节点](launch-workers.md) 中的说明部署节点组。
**注意**  
如果您希望生产集群中的节点支持更高数量的容器组（pod），请再次运行  中的脚本。同时，将 `--cni-prefix-delegation-enabled` 选项添加到命令中。例如，将为 `m5.large` 实例类型返回 `110`。有关如何启用此功能的说明，请参阅 [为带前缀的 Amazon EKS 节点分配更多 IP 地址](cni-increase-ip-addresses.md)。您可以将此功能与自定义联网一起使用。

1. 节点组创建需要几分钟时间。您可以使用以下命令检查托管节点组创建的状态。

   ```
   aws eks describe-nodegroup --cluster-name my-custom-networking-cluster --nodegroup-name my-nodegroup --query nodegroup.status --output text
   ```

   在返回的输出为 `ACTIVE` 之前，请勿继续执行下一步。

1.  在本教程中，您可以跳过此步骤。

   对于生产集群，如果您没有将您的 `ENIConfigs` 命名为您将其用于的可用区相同，则必须使用应与节点结合使用的 `ENIConfig` 名称对节点进行注释。如果您在每个可用区中只有一个子网并且将 `ENIConfigs` 命名为与可用区相同的名称，则此步骤不是必需的。这是因为当您在[上一步](#custom-networking-automatically-apply-eniconfig)中启用适用于 Kubernetes 的 Amazon VPC CNI 插件以执行此操作后，它会自动为您将正确的 `ENIConfig` 与节点关联。

   1. 获取集群中的节点列表。

      ```
      kubectl get nodes
      ```

      示例输出如下。

      ```
      NAME                                          STATUS   ROLES    AGE     VERSION
      ip-192-168-0-126.us-west-2.compute.internal   Ready    <none>   8m49s   v1.22.9-eks-810597c
      ip-192-168-0-92.us-west-2.compute.internal    Ready    <none>   8m34s   v1.22.9-eks-810597c
      ```

   1. 确定每个节点所在的可用区。运行上一步中返回的每个节点的以下命令，根据之前的输出替换 IP 地址。

      ```
      aws ec2 describe-instances --filters Name=network-interface.private-dns-name,Values=ip-192-168-0-126.us-west-2.compute.internal \
      --query 'Reservations[].Instances[].{AvailabilityZone: Placement.AvailabilityZone, SubnetId: SubnetId}'
      ```

      示例输出如下。

      ```
      [
          {
              "AvailabilityZone": "us-west-2d",
              "SubnetId": "subnet-Example5"
          }
      ]
      ```

   1. 使用您为子网 ID 和可用区创建的 `ENIConfig` 注释每一个节点。您只能使用一个 `ENIConfig` 注释节点，尽管使用同一个 `ENIConfig` 可以注释多个节点。将 example values 替换为您自己的值。

      ```
      kubectl annotate node ip-192-168-0-126.us-west-2.compute.internal k8s.amazonaws.com/eniConfig=EniConfigName1
      kubectl annotate node ip-192-168-0-92.us-west-2.compute.internal k8s.amazonaws.com/eniConfig=EniConfigName2
      ```

1.  如果在切换到使用自定义联网功能之前，生产集群中有任何正在运行容器组（pod）的节点，请完成以下任务：

   1. 确保您有可用的节点正在使用自定义联网功能。

   1. 封锁并耗尽节点以正常关闭容器组（pod）。有关更多信息，请参阅 Kubernetes 文档中的[安全耗尽节点](https://kubernetes.io/docs/tasks/administer-cluster/safely-drain-node/)。

   1. 终止节点。如果节点位于现有的托管节点组中，则可以删除该节点组。运行如下命令。

      ```
      aws eks delete-nodegroup --cluster-name my-custom-networking-cluster --nodegroup-name my-nodegroup
      ```

   只有注册有 `k8s.amazonaws.com/eniConfig` 标注的新节点将使用新的自定义联网功能。

1. 确认已从 CIDR 块中为容器组（pod）分配一个 IP 地址，该地址与您在上一步中创建的其中一个子网相关联。

   ```
   kubectl get pods -A -o wide
   ```

   示例输出如下。

   ```
   NAMESPACE     NAME                       READY   STATUS    RESTARTS   AGE     IP              NODE                                          NOMINATED NODE   READINESS GATES
   kube-system   aws-node-2rkn4             1/1     Running   0          7m19s   192.168.0.92    ip-192-168-0-92.us-west-2.compute.internal    <none>           <none>
   kube-system   aws-node-k96wp             1/1     Running   0          7m15s   192.168.0.126   ip-192-168-0-126.us-west-2.compute.internal   <none>           <none>
   kube-system   coredns-657694c6f4-smcgr   1/1     Running   0          56m     192.168.1.23    ip-192-168-0-92.us-west-2.compute.internal    <none>           <none>
   kube-system   coredns-657694c6f4-stwv9   1/1     Running   0          56m     192.168.1.28    ip-192-168-0-92.us-west-2.compute.internal    <none>           <none>
   kube-system   kube-proxy-jgshq           1/1     Running   0          7m19s   192.168.0.92    ip-192-168-0-92.us-west-2.compute.internal    <none>           <none>
   kube-system   kube-proxy-wx9vk           1/1     Running   0          7m15s   192.168.0.126   ip-192-168-0-126.us-west-2.compute.internal   <none>           <none>
   ```

   您可以看到 coredns 容器组（pod）从您添加到 VPC 中的 `192.168.1.0` CIDR 块中分配到了 IP 地址。如果没有自定义联网，他们就会从 `192.168.0.0` CIDR 块分配地址，因为它是最初与 VPC 关联的唯一 CIDR 块。

   如果容器组（pod）的 `spec` 包含 `hostNetwork=true`，则会向其分配节点的主 IP 地址。不会从您添加的子网中向其分配地址。默认情况下，该值设置为 `false`。对于在集群上运行的 `kube-proxy` 和适用于 Kubernetes 的 Amazon VPC CNI 插件 (`aws-node`) 容器组（pod），此值设置为 `true`。这就是在之前的输出中没有向 `kube-proxy` 和插件的 `aws-node` 容器组（pod）分配 192.168.1.x 地址的原因。有关容器组（pod）`hostNetwork` 设置的更多信息，请参阅 Kubernetes API 参考中的 [PodSpec v1 core](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#podspec-v1-core)。

## 步骤 5：删除教程资源
<a name="custom-network-delete-resources"></a>

完成本教程后，我们建议您删除创建的资源。然后，您可以调整步骤以为生产集群启用自定义联网。

1. 如果您创建的节点组只是为了测试，那么请将其删除。

   ```
   aws eks delete-nodegroup --cluster-name my-custom-networking-cluster --nodegroup-name my-nodegroup
   ```

1. 即使在 AWS CLI 输出显示集群已删除，删除过程实际上可能尚未完成。删除过程需要几分钟时间。通过运行以下命令确认已完成。

   ```
   aws eks describe-nodegroup --cluster-name my-custom-networking-cluster --nodegroup-name my-nodegroup --query nodegroup.status --output text
   ```

   在返回的输出类似于以下输出之前，请勿继续执行。

   ```
   An error occurred (ResourceNotFoundException) when calling the DescribeNodegroup operation: No node group found for name: my-nodegroup.
   ```

1. 如果您创建的节点组只是为了测试，则请删除节点 IAM 角色。

   1. 将策略与角色分离。

      ```
      aws iam detach-role-policy --role-name myCustomNetworkingNodeRole --policy-arn arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy
      aws iam detach-role-policy --role-name myCustomNetworkingNodeRole --policy-arn arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly
      aws iam detach-role-policy --role-name myCustomNetworkingNodeRole --policy-arn arn:aws:iam::aws:policy/AmazonEKS_CNI_Policy
      ```

   1. 删除角色。

      ```
      aws iam delete-role --role-name myCustomNetworkingNodeRole
      ```

1. 请删除集群。

   ```
   aws eks delete-cluster --name my-custom-networking-cluster
   ```

   通过以下命令确认集群已删除。

   ```
   aws eks describe-cluster --name my-custom-networking-cluster --query cluster.status --output text
   ```

   返回类似以下内容的输出时，将成功删除集群。

   ```
   An error occurred (ResourceNotFoundException) when calling the DescribeCluster operation: No cluster found for name: my-custom-networking-cluster.
   ```

1. 删除集群 IAM 角色。

   1. 将策略与角色分离。

      ```
      aws iam detach-role-policy --role-name myCustomNetworkingAmazonEKSClusterRole --policy-arn arn:aws:iam::aws:policy/AmazonEKSClusterPolicy
      ```

   1. 删除角色。

      ```
      aws iam delete-role --role-name myCustomNetworkingAmazonEKSClusterRole
      ```

1. 删除您在上一步中创建的子网。

   ```
   aws ec2 delete-subnet --subnet-id $new_subnet_id_1
   aws ec2 delete-subnet --subnet-id $new_subnet_id_2
   ```

1. 删除您创建的 VPC。

   ```
   aws cloudformation delete-stack --stack-name my-eks-custom-networking-vpc
   ```