

 **帮助改进此页面** 

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

# 了解 VPC CNI 模式和配置
<a name="pod-networking-use-cases"></a>

适用于 Kubernetes 的 Amazon VPC CNI 插件为容器组（pod）提供了联网。使用下表了解有关可用网络功能的详细信息。


| 网络功能 | 了解更多 | 
| --- | --- | 
|  配置集群以向集群、容器组（pod）和服务分配 IPv6 地址  |   [了解如何将 IPv6 地址分配给集群、容器组（pod）和服务](cni-ipv6.md)   | 
|  将 IPv4 源网络地址转换用于容器组（pod）  |   [为容器组（pod）启用出站互联网访问权限](external-snat.md)   | 
|  限制流入和流出容器组（pod）的网络流量  |   [使用 Kubernetes 网络策略限制容器组（pod）网络流量](cni-network-policy-configure.md)   | 
|  自定义节点中的辅助网络接口  |   [使用自定义网络在备用子网中部署容器组（pod）](cni-custom-network.md)   | 
|  增加节点的 IP 地址  |   [为带前缀的 Amazon EKS 节点分配更多 IP 地址](cni-increase-ip-addresses.md)   | 
|  将安全组用于容器组（pod）网络流量  |   [将安全组分配给各个容器组（pod）](security-groups-for-pods.md)   | 
|  使用容器组（pod）的多个网络接口  |   [将多个网络接口连接到容器组（pod）](pod-multiple-network-interfaces.md)   | 

# 了解如何将 IPv6 地址分配给集群、容器组（pod）和服务
<a name="cni-ipv6"></a>

 **适用对象**：使用 Amazon EC2 实例的容器组（pod）和 Fargate 容器组（pod）

默认情况下，Kubernetes 会将 `IPv4` 地址分配给容器组（pod）和服务。您可以将集群配置为向其分配 `IPv6` 地址，而不是将 `IPv4` 地址分配给容器组（pod）和服务。Amazon EKS 不支持双堆栈容器组（pod）或服务，即使 Kubernetes 支持也是如此。因此，您无法将 `IPv4` 和 `IPv6` 地址同时分配给容器组（pod）和服务。

创建集群时，您可以选择要用于集群的 IP 系列。集群在创建之后无法更改系列。

有关部署 Amazon EKS `IPv6` 集群的教程，请参阅[部署 Amazon EKS `IPv6` 集群和 Amazon Linux 托管节点](deploy-ipv6-cluster.md)。

以下是使用该功能的注意事项：

## `IPv6` 功能支持
<a name="_ipv6_feature_support"></a>
+  **不支持 Windows**：不支持 Windows 容器组（pod）和服务。
+  **需要基于 Nitro 的 EC2 节点**：您只能将 AWS 与 `IPv6` 基于 Nitro 的 Amazon EC2 节点或 Fargate 节点结合使用。
+  **支持 EC2 和 Fargate 节点**：您可以将 `IPv6` 与具有 Amazon EC2 节点和 Fargate 节点的 [将安全组分配给各个容器组（pod）](security-groups-for-pods.md) 结合使用。
+  **不支持 Outposts**：您不能将 `IPv6` 与 [使用 AWS Outposts 在本地部署 Amazon EKS](eks-outposts.md) 结合使用。
+  **不支持 FSx for Lustre**：不支持 [将高性能应用程序存储与适用于 Lustre 的 Amazon FSx 结合使用](fsx-csi.md)。
+  **不支持自定义联网**：如果您以前使用过[使用自定义网络在备用子网中部署容器组（pod）](cni-custom-network.md)帮助缓解 IP 地址耗尽，您可以改用 `IPv6`。您不能将自定义联网与 `IPv6` 结合使用。如果您使用自定义联网进行网络隔离，则可能需要为集群继续使用自定义联网和 `IPv4` 系列。

## IP 地址分配
<a name="_ip_address_assignments"></a>
+  **Kubernetes 服务**：仅为 Kubernetes 服务分配一个 `IPv6` 地址。系统不会为其分配 IPv4 地址。
+  **容器组（pod）**：将为容器组（pod）分配一个 IPv6 地址和一个主机本地 IPv4 地址。主机本地 IPv4 地址是使用与 VPC CNI 关联的主机本地 CNI 插件分配的，并且该地址不会报告给 Kubernetes 控制面板。仅在有容器组需要与其他 Amazon VPC 或互联网中的外部 IPv4 资源通信时才会使用该地址。主机本地 IPv4 地址将（由 VPC CNI）SNAT 转换为 Worker 节点的主 ENI 的主 IPv4 地址。
+  **容器组和服务**：容器组和服务只接收 `IPv6` 地址，不接收 `IPv4` 地址。当容器组需要与外部 `IPv4` 端点通信时，它们会在节点本身上使用 NAT。这种内置的 NAT 功能无需 [DNS64 和 NAT64](https://docs.aws.amazon.com/vpc/latest/userguide/vpc-nat-gateway.html#nat-gateway-nat64-dns64)。对于需要公共互联网访问的流量，容器组的流量将源网络地址转换为公有 IP 地址。
+  **路由地址**：当容器组与 VPC 外部通信时，其原始 `IPv6` 地址将被保留（不会转换为节点的 `IPv6` 地址）。此流量将直接通过互联网网关或仅出口互联网网关进行路由。
+  **节点**：所有节点均已分配 `IPv4` 和 `IPv6` 地址。
+  **Fargate 容器组（pod）**：每个 Fargate 容器组（pod）都会收到来自为其部署的子网指定的 CIDR 的 `IPv6` 地址。运行 Fargate 容器组（pod）的底层硬件单元从分配给部署硬件单元的子网的 CIDR 获取唯一的 `IPv4` 和 `IPv6` 地址。

## 如何将 `IPv6` 与 EKS 结合使用。
<a name="_how_to_use_ipv6_with_eks"></a>
+  **创建新集群**：您必须创建新集群并指定该集群要使用 `IPv6` 系列。您无法为从前一版本更新的集群启用 `IPv6` 系列。有关如何创建新集群的说明，请参阅“注意事项”。
+  **使用最新的 VPC CNI**：部署 Amazon VPC CNI 版本 `1.10.1` 或更高版本。默认情况下，会部署此版本或更高版本。部署附加组件后，您无法在不先删除集群所有节点组中的所有节点的情况下将 Amazon VPC CNI 附加组件版本降级到 `1.10.1` 版以下。
+  **为 `IPv6` 配置 VPC CNI**：如果您使用 Amazon EC2 节点，则必须使用 IP 前缀委派和 `IPv6` 配置 Amazon VPC CNI 附加组件。如果您在创建集群时选择 `IPv6` 系列，则 `1.10.1` 版的附加组件默认采用此配置。自行管理或 Amazon EKS 附加组件均为属于此种情况。有关 IP 前缀委派的更多信息，请参阅 [为带前缀的 Amazon EKS 节点分配更多 IP 地址](cni-increase-ip-addresses.md)。
+  **配置 `IPv4` 和 `IPv6` 地址**：创建集群时，您指定的 VPC 和子网必须具有分配给您指定的 VPC 和子网的 `IPv6` CIDR 块。您还必须为其分配一个 `IPv4` CIDR 块。这是因为，即使您只想使用 `IPv6`，VPC 仍然需要 `IPv4` CIDR 块才能正常工作。有关更多信息，请参阅 Amazon VPC 用户指南中的[关联 IPv6 CIDR 块与 VPC](https://docs.aws.amazon.com/vpc/latest/userguide/working-with-vpcs.html#vpc-associate-ipv6-cidr)。
+  **自动将 IPv6 地址分配非节点**：创建节点时，必须指定配置为自动分配 `IPv6` 地址的子网。否则，您无法部署节点。默认情况下，将禁用此配置。有关更多信息，请参阅 Amazon VPC 用户指南中的[修改子网的 IPv6 寻址属性](https://docs.aws.amazon.com/vpc/latest/userguide/vpc-ip-addressing.html#subnet-ipv6)。
+  **设置路由表以使用 `IPv6`**：分配给子网的路由表必须有 `IPv6` 地址的路由。有关更多信息，请参阅 Amazon VPC 用户指南中的[迁移到 IPv6](https://docs.aws.amazon.com/vpc/latest/userguide/vpc-migrate-ipv6.html)。
+  **为 `IPv6` 设置安全组**：您的安全组必须允许 `IPv6` 地址。有关更多信息，请参阅 Amazon VPC 用户指南中的[迁移到 IPv6](https://docs.aws.amazon.com/vpc/latest/userguide/vpc-migrate-ipv6.html)。
+  **设置负载均衡器**：使用 AWS 负载均衡器控制器版本 `2.3.1` 或更高版本，对 HTTP 应用程序（通过使用 [使用应用程序负载均衡器路由应用程序和 HTTP 流量](alb-ingress.md)）或流向 `IPv6` 容器组（pod）的网络流量（通过在 IP 模式下借助负载均衡器使用 [使用网络负载均衡器路由 TCP 和 UDP 流量](network-load-balancing.md)，不支持实例模式）进行负载均衡。有关更多信息，请参阅 [使用 AWS 负载均衡器控制器路由互联网流量](aws-load-balancer-controller.md)。
+  **添加 `IPv6` IAM 策略**：您必须将 `IPv6` IAM 策略附加到节点 IAM 或 CNI IAM 角色。在两者之间，我们建议您将其附加到 CNI IAM 角色。有关更多信息，请参阅[为使用 `IPv6` 系列的集群创建 IAM policy](cni-iam-role.md#cni-iam-role-create-ipv6-policy)和[步骤 1：创建适用于 Kubernetes 的 Amazon VPC CNI 插件 IAM 角色](cni-iam-role.md#cni-iam-role-create-role)。
+  **评估所有组件**：在部署 `IPv6` 集群之前对集成的应用程序、Amazon EKS 附加组件和 AWS 服务进行全面的评估。这是为了确保 `IPv6` 的所有功能按预期运行。

# 部署 Amazon EKS `IPv6` 集群和 Amazon Linux 托管节点
<a name="deploy-ipv6-cluster"></a>

在本教程中，您将部署 `IPv6` Amazon VPC、具有 `IPv6` 系列的 Amazon EKS 集群以及具有 Amazon EC2 Amazon Linux 节点的托管节点组。您无法在 `IPv6` 集群中部署 Amazon EC2 Windows 节点。您还可以将 Fargate 节点部署到集群，但为了简单起见，本主题中没有提供这些说明。

## 先决条件
<a name="_prerequisites"></a>

开始教程前，请完成以下任务：

安装并配置创建和管理 Amazon EKS 集群所需的以下工具和资源。
+ 我们建议您熟悉所有设置，并使用符合您要求的设置部署集群。有关更多信息，请参阅[创建一个 Amazon EKS 集群。](create-cluster.md)、[使用托管式节点组简化节点生命周期](managed-node-groups.md)和本主题中的[注意事项](cni-ipv6.md)。一些设置仅在创建集群时才能启用。
+ 您的设备或 AWS CloudShell 上安装了 `kubectl` 命令行工具。该版本可以与集群的 Kubernetes 版本相同，或者最多早于或晚于该版本一个次要版本。例如，如果您的集群版本为 `1.29`，则可以将 `kubectl` 的 `1.28`、`1.29` 或 `1.30` 版本与之配合使用。要安装或升级 `kubectl`，请参阅 [设置 `kubectl` 和 `eksctl`](install-kubectl.md)。
+ 您正在使用的 IAM 安全主体必须具有使用 Amazon EKS IAM 角色、服务相关角色、AWS CloudFormation、VPC 和相关资源的权限。有关更多信息，请参阅《IAM 用户指南》中的[操作](https://docs.aws.amazon.com/service-authorization/latest/reference/list_amazonelastickubernetesservice.html)和[编辑服务相关角色](https://docs.aws.amazon.com/IAM/latest/UserGuide/using-service-linked-roles.html)。
+ 如果您使用 eksctl，请在计算机上安装版本 `0.215.0` 或更高版本。要安装或更新该工具，请参阅 `eksctl` 文档中的[安装](https://eksctl.io/installation)。
+ 在您的设备或 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，则可能需要[安装版本 2.12.3 或更高版本或者 1.27.160 版或更高版本的 AWS CLI](https://docs.aws.amazon.com/cloudshell/latest/userguide/vm-specs.html#install-cli-software)，因为 AWS CloudShell 中安装的默认 AWS CLI 版本可能是较早的版本。

您可以使用 eksctl 或 CLI 来部署 `IPv6` 集群。

## 使用 eksctl 部署 IPv6 集群
<a name="_deploy_an_ipv6_cluster_with_eksctl"></a>

1. 创建 `ipv6-cluster.yaml` 文件。将以下命令复制到您的设备。根据需要对该命令进行以下修改，然后运行修改后的命令：
   + 将 *my-cluster* 替换为您的集群名称。名称只能包含字母数字字符（区分大小写）和连字符。该名称必须以字母数字字符开头，且不得超过 100 个字符。对于您在其中创建集群的 AWS 区域和 AWS 账户，该名称必须在其内具有唯一性。
   + 请将 *region-code* 替换为 Amazon EKS 支持的任何 AWS 区域。有关 AWS 区域列表，请参阅《AWS 一般参考》指南中的 [Amazon EKS 服务端点和配额](https://docs.aws.amazon.com/general/latest/gr/eks.html)。
   + `version` 的值与您的集群版本有关。有关更多信息，请参阅 [Amazon EKS 支持的版本](https://docs.aws.amazon.com/eks/latest/userguide/kubernetes-versions.html)。
   + 将 *my-nodegroup* 替换为您的节点组的名称。节点组名称的长度不能超过 63 个字符。它必须以字母或数字开头，但也可以包括其余字符的连字符和下划线。
   + 将 *t3.medium* 替换为任何 [AWS Nitro 系统实例类型](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instance-types.html#ec2-nitro-instances)。

     ```
     cat >ipv6-cluster.yaml <<EOF
     ---
     apiVersion: eksctl.io/v1alpha5
     kind: ClusterConfig
     
     metadata:
       name: my-cluster
       region: region-code
       version: "X.XX"
     
     kubernetesNetworkConfig:
       ipFamily: IPv6
     
     addons:
       - name: vpc-cni
         version: latest
       - name: coredns
         version: latest
       - name: kube-proxy
         version: latest
     
     iam:
       withOIDC: true
     
     managedNodeGroups:
       - name: my-nodegroup
         instanceType: t3.medium
     EOF
     ```

1. 创建您的集群。

   ```
   eksctl create cluster -f ipv6-cluster.yaml
   ```

   创建集群需要几分钟时间。在看到输出的最后一行（与以下输出类似）之前，不要继续操作。

   ```
   [...]
   [✓]  EKS cluster "my-cluster" in "region-code" region is ready
   ```

1. 确认默认容器组（pod）分配到了 `IPv6` 地址。

   ```
   kubectl get pods -n kube-system -o wide
   ```

   示例输出如下。

   ```
   NAME                       READY   STATUS    RESTARTS   AGE     IP                                       NODE                                            NOMINATED NODE   READINESS GATES
   aws-node-rslts             1/1     Running   1          5m36s   2600:1f13:b66:8200:11a5:ade0:c590:6ac8   ip-192-168-34-75.region-code.compute.internal   <none>           <none>
   aws-node-t74jh             1/1     Running   0          5m32s   2600:1f13:b66:8203:4516:2080:8ced:1ca9   ip-192-168-253-70.region-code.compute.internal  <none>           <none>
   coredns-85d5b4454c-cw7w2   1/1     Running   0          56m     2600:1f13:b66:8203:34e5::                ip-192-168-253-70.region-code.compute.internal  <none>           <none>
   coredns-85d5b4454c-tx6n8   1/1     Running   0          56m     2600:1f13:b66:8203:34e5::1               ip-192-168-253-70.region-code.compute.internal  <none>           <none>
   kube-proxy-btpbk           1/1     Running   0          5m36s   2600:1f13:b66:8200:11a5:ade0:c590:6ac8   ip-192-168-34-75.region-code.compute.internal   <none>           <none>
   kube-proxy-jjk2g           1/1     Running   0          5m33s   2600:1f13:b66:8203:4516:2080:8ced:1ca9   ip-192-168-253-70.region-code.compute.internal  <none>           <none>
   ```

1. 确认默认服务已分配 `IPv6` 地址。

   ```
   kubectl get services -n kube-system -o wide
   ```

   示例输出如下。

   ```
   NAME       TYPE        CLUSTER-IP          EXTERNAL-IP   PORT(S)         AGE   SELECTOR
   kube-dns   ClusterIP   fd30:3087:b6c2::a   <none>        53/UDP,53/TCP   57m   k8s-app=kube-dns
   ```

1. （可选）[部署示例应用程序](sample-deployment.md)或部署 [AWS 负载均衡器控制器](aws-load-balancer-controller.md)和示例应用程序，对 HTTP 应用程序（通过[使用应用程序负载均衡器路由应用程序和 HTTP 流量](alb-ingress.md)）或流向 `IPv6` 容器组（pod）的网络流量（通过[使用网络负载均衡器路由 TCP 和 UDP 流量](network-load-balancing.md)）进行负载均衡。

1. 在使用完成针对本教程而创建的集群和节点后，应使用以下命令清理创建的资源。

   ```
   eksctl delete cluster my-cluster
   ```

## 使用 AWS CLI 部署 IPv6 集群
<a name="deploy_an_ipv6_cluster_with_shared_aws_cli"></a>

**重要**  
您必须以同一用户身份完成此程序中的所有步骤。要查看当前用户，请运行以下命令：  

  ```
  aws sts get-caller-identity
  ```
您必须在同一 Shell 中完成此程序中的所有步骤。有几个步骤使用了之前步骤中设置的变量。如果在不同的 Shell 中设置变量值，则使用这些变量的步骤将无法正常运行。如果使用 [AWS CloudShell](https://docs.aws.amazon.com/cloudshell/latest/userguide/welcome.html) 完成以下程序，请记住，如果您在大约 20–30 分钟内没有使用键盘或指针与其交互，则 Shell 会话将结束。正在运行的进程不算作交互。
这些说明是针对 Bash Shell 编写的，在其他 Shell 中可能需要调整。

将此程序步骤中的所有示例值替换为您自己的值。

1. 运行以下命令以设置在后面的步骤中使用的一些变量。将 *region-code* 替换为您想要在其中部署资源的 AWS 区域。该值可以是 Amazon EKS 支持的任何 AWS 区域。有关 AWS 区域列表，请参阅《AWS 一般参考》指南中的 [Amazon EKS 服务端点和配额](https://docs.aws.amazon.com/general/latest/gr/eks.html)。将 *my-cluster* 替换为您的集群名称。名称只能包含字母数字字符（区分大小写）和连字符。该名称必须以字母数字字符开头，且不得超过 100 个字符。对于您在其中创建集群的 AWS 区域和 AWS 账户，该名称必须在其内具有唯一性。将 *my-nodegroup* 替换为您的节点组的名称。节点组名称的长度不能超过 63 个字符。它必须以字母或数字开头，但也可以包括其余字符的连字符和下划线。请将 *111122223333* 替换为您的账户 ID。

   ```
   export region_code=region-code
   export cluster_name=my-cluster
   export nodegroup_name=my-nodegroup
   export account_id=111122223333
   ```

1. 创建具有公有和私有子网且符合 Amazon EKS 和 `IPv6` 要求的 Amazon VPC。

   1. 运行以下命令设置 AWS CloudFormation 堆栈名称的变量。您可以将 *my-eks-ipv6-vpc* 替换为选择的任何名称。

      ```
      export vpc_stack_name=my-eks-ipv6-vpc
      ```

   1. 使用 AWS CloudFormation 模板创建 `IPv6` VPC。

      ```
      aws cloudformation create-stack --region $region_code --stack-name $vpc_stack_name \
        --template-url https://s3.us-west-2.amazonaws.com/amazon-eks/cloudformation/2020-10-29/amazon-eks-ipv6-vpc-public-private-subnets.yaml
      ```

      堆栈需要几分钟的时间来创建。运行如下命令。在命令的输出变成 `CREATE_COMPLETE` 之前，请勿继续执行下一步。

      ```
      aws cloudformation describe-stacks --region $region_code --stack-name $vpc_stack_name --query Stacks[].StackStatus --output text
      ```

   1. 检索创建的公有子网的 ID。

      ```
      aws cloudformation describe-stacks --region $region_code --stack-name $vpc_stack_name \
          --query='Stacks[].Outputs[?OutputKey==`SubnetsPublic`].OutputValue' --output text
      ```

      示例输出如下。

      ```
      subnet-0a1a56c486EXAMPLE,subnet-099e6ca77aEXAMPLE
      ```

   1. 为创建的公有子网启用自动分配 `IPv6` 地址选项。

      ```
      aws ec2 modify-subnet-attribute --region $region_code --subnet-id subnet-0a1a56c486EXAMPLE --assign-ipv6-address-on-creation
      aws ec2 modify-subnet-attribute --region $region_code --subnet-id subnet-099e6ca77aEXAMPLE --assign-ipv6-address-on-creation
      ```

   1. 从部署的 AWS CloudFormation 堆栈中检索模板创建的子网和安全组的名称，将其存储在变量中，以供后续步骤使用。

      ```
      security_groups=$(aws cloudformation describe-stacks --region $region_code --stack-name $vpc_stack_name \
          --query='Stacks[].Outputs[?OutputKey==`SecurityGroups`].OutputValue' --output text)
      
      public_subnets=$(aws cloudformation describe-stacks --region $region_code --stack-name $vpc_stack_name \
          --query='Stacks[].Outputs[?OutputKey==`SubnetsPublic`].OutputValue' --output text)
      
      private_subnets=$(aws cloudformation describe-stacks --region $region_code --stack-name $vpc_stack_name \
          --query='Stacks[].Outputs[?OutputKey==`SubnetsPrivate`].OutputValue' --output text)
      
      subnets=${public_subnets},${private_subnets}
      ```

1. 创建一个集群 IAM 角色，并将所需的 Amazon EKS IAM 托管式策略附加到该角色。Amazon EKS 托管的 Kubernetes 集群会代表您调用其他AWS服务，以管理您用于该服务的资源。

   1. 运行以下命令以创建 `eks-cluster-role-trust-policy.json` 文件。

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

   1. 运行以下命令设置角色名称的变量。您可以将 *myAmazonEKSClusterRole* 替换为选择的任何名称。

      ```
      export cluster_role_name=myAmazonEKSClusterRole
      ```

   1. 创建角色。

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

   1. 检索 IAM 角色的 ARN 并将其存储在变量中以供后续步骤使用。

      ```
      CLUSTER_IAM_ROLE=$(aws iam get-role --role-name $cluster_role_name --query="Role.Arn" --output text)
      ```

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

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

1. 创建您的集群。

   ```
   aws eks create-cluster --region $region_code --name $cluster_name --kubernetes-version 1.XX \
      --role-arn $CLUSTER_IAM_ROLE --resources-vpc-config subnetIds=$subnets,securityGroupIds=$security_groups \
      --kubernetes-network-config ipFamily=ipv6
   ```

   1. 注意：您可能会收到一个错误，指示请求中的可用区之一没有足够容量来创建 Amazon EKS 集群。如果发生这种情况，错误输出将包含可支持新集群的可用区。再次尝试使用至少两个位于您账户中支持的可用区的子网创建集群。有关更多信息，请参阅 [容量不足](troubleshooting.md#ice)。

      创建集群需要几分钟时间。运行如下命令。在命令的输出变成 `ACTIVE` 之前，请勿继续执行下一步。

      ```
      aws eks describe-cluster --region $region_code --name $cluster_name --query cluster.status
      ```

1. 为集群创建或更新 `kubeconfig` 文件，以便您可以与集群通信。

   ```
   aws eks update-kubeconfig --region $region_code --name $cluster_name
   ```

   默认情况下，`config` 文件创建在 `~/.kube` 中或者新集群的配置已添加到 `~/.kube` 的现有 `config` 文件中。

1. 创建节点 IAM 角色。

   1. 运行以下命令以创建 `vpc-cni-ipv6-policy.json` 文件。

      ```
      {
          "Version":"2012-10-17",		 	 	 
          "Statement": [
              {
                  "Effect": "Allow",
                  "Action": [
                      "ec2:AssignIpv6Addresses",
                      "ec2:DescribeInstances",
                      "ec2:DescribeTags",
                      "ec2:DescribeNetworkInterfaces",
                      "ec2:DescribeInstanceTypes"
                  ],
                  "Resource": "*"
              },
              {
                  "Effect": "Allow",
                  "Action": [
                      "ec2:CreateTags"
                  ],
                  "Resource": [
                      "arn:aws:ec2:*:*:network-interface/*"
                  ]
              }
          ]
      }
      ```

   1. 创建 IAM 策略。

      ```
      aws iam create-policy --policy-name AmazonEKS_CNI_IPv6_Policy --policy-document file://vpc-cni-ipv6-policy.json
      ```

   1. 运行以下命令以创建 `node-role-trust-relationship.json` 文件。

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

   1. 运行以下命令设置角色名称的变量。您可以将 *AmazonEKSNodeRole* 替换为选择的任何名称。

      ```
      export node_role_name=AmazonEKSNodeRole
      ```

   1. 创建 IAM 角色。

      ```
      aws iam create-role --role-name $node_role_name --assume-role-policy-document file://"node-role-trust-relationship.json"
      ```

   1. 将 IAM 策略附加到 IAM 角色。

      ```
      aws iam attach-role-policy --policy-arn arn:aws:iam::$account_id:policy/AmazonEKS_CNI_IPv6_Policy \
          --role-name $node_role_name
      ```
**重要**  
为简单起见，在本教程中，该策略附加到此 IAM 角色。但是，在生产集群中，我们建议将该策略附加到单独的 IAM 角色。有关更多信息，请参阅 [配置 Amazon VPC CNI 插件以使用 IRSA](cni-iam-role.md)。

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

      ```
      aws iam attach-role-policy --policy-arn arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy \
        --role-name $node_role_name
      aws iam attach-role-policy --policy-arn arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly \
        --role-name $node_role_name
      ```

   1. 检索 IAM 角色的 ARN 并将其存储在变量中以供后续步骤使用。

      ```
      node_iam_role=$(aws iam get-role --role-name $node_role_name --query="Role.Arn" --output text)
      ```

1. 创建托管节点组。

   1. 查看在上一步中创建的子网的 ID。

      ```
      echo $subnets
      ```

      示例输出如下。

      ```
      subnet-0a1a56c486EXAMPLE,subnet-099e6ca77aEXAMPLE,subnet-0377963d69EXAMPLE,subnet-0c05f819d5EXAMPLE
      ```

   1. 创建节点组。将 *0a1a56c486EXAMPLE*、*099e6ca77aEXAMPLE*、*0377963d69EXAMPLE* 和 *0c05f819d5EXAMPLE* 替换为上一步输出中返回的值。请务必在以下命令之前的输出中删除子网 ID 之间的逗号。您可以将 *t3.medium* 替换为任何 [AWS Nitro 系统实例类型](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instance-types.html#ec2-nitro-instances)。

      ```
      aws eks create-nodegroup --region $region_code --cluster-name $cluster_name --nodegroup-name $nodegroup_name \
          --subnets subnet-0a1a56c486EXAMPLE subnet-099e6ca77aEXAMPLE subnet-0377963d69EXAMPLE subnet-0c05f819d5EXAMPLE \
          --instance-types t3.medium --node-role $node_iam_role
      ```

      创建节点组需要几分钟的时间。运行如下命令。在返回的输出为 `ACTIVE` 之前，请勿继续执行下一步。

      ```
      aws eks describe-nodegroup --region $region_code --cluster-name $cluster_name --nodegroup-name $nodegroup_name \
          --query nodegroup.status --output text
      ```

1. 确认默认容器组（pod）分配到了 `IP` 列中的 `IPv6` 地址。

   ```
   kubectl get pods -n kube-system -o wide
   ```

   示例输出如下。

   ```
   NAME                       READY   STATUS    RESTARTS   AGE     IP                                       NODE                                            NOMINATED NODE   READINESS GATES
   aws-node-rslts             1/1     Running   1          5m36s   2600:1f13:b66:8200:11a5:ade0:c590:6ac8   ip-192-168-34-75.region-code.compute.internal   <none>           <none>
   aws-node-t74jh             1/1     Running   0          5m32s   2600:1f13:b66:8203:4516:2080:8ced:1ca9   ip-192-168-253-70.region-code.compute.internal  <none>           <none>
   coredns-85d5b4454c-cw7w2   1/1     Running   0          56m     2600:1f13:b66:8203:34e5::                ip-192-168-253-70.region-code.compute.internal  <none>           <none>
   coredns-85d5b4454c-tx6n8   1/1     Running   0          56m     2600:1f13:b66:8203:34e5::1               ip-192-168-253-70.region-code.compute.internal  <none>           <none>
   kube-proxy-btpbk           1/1     Running   0          5m36s   2600:1f13:b66:8200:11a5:ade0:c590:6ac8   ip-192-168-34-75.region-code.compute.internal   <none>           <none>
   kube-proxy-jjk2g           1/1     Running   0          5m33s   2600:1f13:b66:8203:4516:2080:8ced:1ca9   ip-192-168-253-70.region-code.compute.internal  <none>           <none>
   ```

1. 确认默认服务已分配 `IP` 列中的 `IPv6` 地址。

   ```
   kubectl get services -n kube-system -o wide
   ```

   示例输出如下。

   ```
   NAME       TYPE        CLUSTER-IP          EXTERNAL-IP   PORT(S)         AGE   SELECTOR
   kube-dns   ClusterIP   fd30:3087:b6c2::a   <none>        53/UDP,53/TCP   57m   k8s-app=kube-dns
   ```

1. （可选）[部署示例应用程序](sample-deployment.md)或部署 [AWS 负载均衡器控制器](aws-load-balancer-controller.md)和示例应用程序，对 HTTP 应用程序（通过[使用应用程序负载均衡器路由应用程序和 HTTP 流量](alb-ingress.md)）或流向 `IPv6` 容器组（pod）的网络流量（通过[使用网络负载均衡器路由 TCP 和 UDP 流量](network-load-balancing.md)）进行负载均衡。

1. 在使用完成针对本教程而创建的集群和节点后，应使用以下命令清理创建的资源。删除之前，确保您没有使用本教程之外的任何资源。

   1. 如果您在与之前步骤不同的 Shell 中完成此步骤，请设置之前步骤中使用的所有变量的值，然后将 example values 替换为完成之前步骤时指定的值。如果在完成之前步骤的同一 Shell 中完成此步骤，请跳至下一步。

      ```
      export region_code=region-code
      export vpc_stack_name=my-eks-ipv6-vpc
      export cluster_name=my-cluster
      export nodegroup_name=my-nodegroup
      export account_id=111122223333
      export node_role_name=AmazonEKSNodeRole
      export cluster_role_name=myAmazonEKSClusterRole
      ```

   1. 删除您的节点组。

      ```
      aws eks delete-nodegroup --region $region_code --cluster-name $cluster_name --nodegroup-name $nodegroup_name
      ```

      删除需要花费几分钟的时间。运行如下命令。如果返回任何输出，请勿继续执行下一步。

      ```
      aws eks list-nodegroups --region $region_code --cluster-name $cluster_name --query nodegroups --output text
      ```

   1. 请删除集群。

      ```
      aws eks delete-cluster --region $region_code --name $cluster_name
      ```

      删除集群需要几分钟时间。在继续之前，请确保使用以下命令删除集群。

      ```
      aws eks describe-cluster --region $region_code --name $cluster_name
      ```

      在输出与以下输出类似之前，请勿继续执行下一步。

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

   1. 删除您创建的 IAM 资源。如果您选择的名称与与之前步骤中使用的名称不同，则将 *AmazonEKS\$1CNI\$1IPv6\$1Policy* 替换为您选择的名称。

      ```
      aws iam detach-role-policy --role-name $cluster_role_name --policy-arn arn:aws:iam::aws:policy/AmazonEKSClusterPolicy
      aws iam detach-role-policy --role-name $node_role_name --policy-arn arn:aws:iam::aws:policy/AmazonEKSWorkerNodePolicy
      aws iam detach-role-policy --role-name $node_role_name --policy-arn arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryReadOnly
      aws iam detach-role-policy --role-name $node_role_name --policy-arn arn:aws:iam::$account_id:policy/AmazonEKS_CNI_IPv6_Policy
      aws iam delete-policy --policy-arn arn:aws:iam::$account_id:policy/AmazonEKS_CNI_IPv6_Policy
      aws iam delete-role --role-name $cluster_role_name
      aws iam delete-role --role-name $node_role_name
      ```

   1. 删除创建 VPC 的 AWS CloudFormation 堆栈。

      ```
      aws cloudformation delete-stack --region $region_code --stack-name $vpc_stack_name
      ```

# 为容器组（pod）启用出站互联网访问权限
<a name="external-snat"></a>

 **适用对象**：Linux `IPv4` Fargate 节点以及带有 Amazon EC2 实例的 Linux 节点

如果您使用 `IPv6` 系列部署集群，那么本主题中的信息不适用于您的集群，因为 `IPv6` 地址未进行网络转换。有关集群使用 `IPv6` 的详细信息，请参阅 [了解如何将 IPv6 地址分配给集群、容器组（pod）和服务](cni-ipv6.md)。

默认情况下，集群中的每个容器组（pod）都从无类别域间路由（CIDR）块中分配到一个[私有](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-instance-addressing.html#concepts-private-addresses) `IPv4` 地址，该块与容器组（pod）部署在其中的 VPC 关联。相同 VPC 中的容器组（pod）使用这些私有 IP 地址作为端点来相互通信。当容器组（pod）与不在与您 VPC 关联的 CIDR 块内的任何 `IPv4` 地址通信时，Amazon VPC CNI 插件（适用于 [Linux](https://github.com/aws/amazon-vpc-cni-k8s#amazon-vpc-cni-k8s) 或 [Windows](https://github.com/aws/amazon-vpc-cni-plugins/tree/master/plugins/vpc-bridge)）默认会将容器组（pod）的 `IPv4` 地址转换为容器组（pod）运行所在的节点的主[弹性网络接口](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-eni.html#eni-basics)的主私有 `IPv4` 地址[\$1](#snat-exception)。

**注意**  
对于 Windows 节点，还有其他详细信息需要考虑。默认情况下，[适用于 Windows 的 VPC CNI 插件](https://github.com/aws/amazon-vpc-cni-plugins/tree/master/plugins/vpc-bridge)使用网络配置进行定义，该配置下 SNAT 不包括同一 VPC 内向目标发送的流量。这意味着内部 VPC 通信已禁用 SNAT，分配给容器组（pod）的 IP 地址可在 VPC 内路由。但是向 VPC 以外目标发送的流量会将源容器组（pod）IP 经 SNAT 处理到实例 ENI 的主 IP 地址。适用于 Windows 的此默认配置可确保容器组（pod）能像主机实例一样访问您 VPC 之外的网络。

由于此行为：
+ 只有当运行互联网资源的节点分配了[公有](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-instance-addressing.html#concepts-public-addresses)或[弹性](https://docs.aws.amazon.com/vpc/latest/userguide/vpc-eips.html) IP 地址并且位于[公有子网](https://docs.aws.amazon.com/vpc/latest/userguide/configure-subnets.html#subnet-basics)中时，您的容器组（pod）才能与互联网资源通信。公有子网的关联[路由表](https://docs.aws.amazon.com/vpc/latest/userguide/VPC_Route_Tables.html)具有指向互联网网关的路由。我们建议尽可能将节点部署到私有子网。
+ 对于 `1.8.0` 之前的插件版本，如果网络或 VPC 中的资源使用 [VPC 对等](https://docs.aws.amazon.com/vpc/latest/peering/what-is-vpc-peering.html)、[中转 VPC](https://docs.aws.amazon.com/whitepapers/latest/aws-vpc-connectivity-options/transit-vpc-option.html) 或 [AWS Direct Connect](https://docs.aws.amazon.com/directconnect/latest/UserGuide/Welcome.html) 连接到您的集群 VPC，则无法在辅助弹性网络接口后启动与容器组（pod）的通信。但是，您的容器组（pod）可以启动与这些资源的通信并接收其响应。

如果以下任一陈述在您的环境中成立，则使用以下命令更改默认配置。
+ 网络或 VPC 中有资源使用 [VPC 对等](https://docs.aws.amazon.com/vpc/latest/peering/what-is-vpc-peering.html)、[中转 VPC](https://docs.aws.amazon.com/whitepapers/latest/aws-vpc-connectivity-options/transit-vpc-option.html) 或 [AWS Direct Connect](https://docs.aws.amazon.com/directconnect/latest/UserGuide/Welcome.html) 连接到您的集群 VPC，它们需要使用 `IPv4` 地址启动与容器组（pod）的通信，并且您的插件版本早于 `1.8.0`。
+ 您的容器组（pod）位于[私有子网](https://docs.aws.amazon.com/vpc/latest/userguide/configure-subnets.html#subnet-basics)中，需要向互联网进行出站通信。子网具有通往 [NAT 网关](https://docs.aws.amazon.com/vpc/latest/userguide/vpc-nat-gateway.html)的路由。

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

**注意**  
`AWS_VPC_K8S_CNI_EXTERNALSNAT` 和 `AWS_VPC_K8S_CNI_EXCLUDE_SNAT_CIDRS` CNI 配置变量不适用于 Windows 节点。Windows 不支持禁用 SNAT。至于从 SNAT 中排除 `IPv4` CIDR 列表，您可以通过在 Windows 引导脚本中指定 `ExcludedSnatCIDRs` 参数来定义。有关使用该参数的更多信息，请参阅 [引导脚本配置参数](eks-optimized-windows-ami.md#bootstrap-script-configuration-parameters)。

## 主机网络
<a name="snat-exception"></a>

\$1如果容器组（pod）规范包含 `hostNetwork=true`（默认值为 `false`），其 IP 地址就不会转换为其他地址。对于在集群上运行的 `kube-proxy` 和适用于 Kubernetes 的 Amazon VPC CNI 插件容器组（pod），默认情况便是如此。对于这些容器组（pod），IP 地址与节点的主 IP 地址相同，因此容器组（pod）IP 地址未转换。有关容器组（pod）`hostNetwork` 设置的更多信息，请参阅 Kubernetes API 参考中的 [PodSpec v1 core](https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.35/#podspec-v1-core)。

# 通过 Kubernetes 网络策略限制容器组（pod）流量
<a name="cni-network-policy"></a>

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

默认情况下，Kubernetes 对集群中任何容器组（pod）之间或容器组（pod）与任何其他网络中的资源之间的 IP 地址、端口或连接没有限制。可以使用 Kubernetes *网络策略*来限制进出容器组（pod）的网络流量。有关更多信息，请参阅 Kubernetes 文档中的[网络策略](https://kubernetes.io/docs/concepts/services-networking/network-policies/)。

## 标准网络策略
<a name="_standard_network_policy"></a>

您可以使用 `NetworkPolicy` 标准在集群中分段容器组（pod）间流量。这些网络策略在 OSI 网络模型的第 3 层和第 4 层上运行，让您能够控制 Amazon EKS 集群中 IP 地址或端口级别的流量。标准网络策略的范围限定为命名空间级别。

### 使用案例
<a name="_use_cases"></a>
+ 在工作负载之间对网络流量进行分段，确保只有相关的应用程序才能相互通信。
+ 使用策略在命名空间级别隔离租户，以强制执行网络分离。

### 示例
<a name="_example"></a>

在以下策略中，来自 *sun* 命名空间中的 *webappp*容器组（pod）的出口流量受到限制。

```
apiVersion: networking.k8s.io/v1
kind: NetworkPolicy
metadata:
  name: webapp-egress-policy
  namespace: sun
spec:
  podSelector:
    matchLabels:
      role: webapp
  policyTypes:
  - Egress
  egress:
  - to:
    - namespaceSelector:
        matchLabels:
          name: moon
      podSelector:
        matchLabels:
          role: frontend
    ports:
    - protocol: TCP
      port: 8080
  - to:
    - namespaceSelector:
        matchLabels:
          name: stars
      podSelector:
        matchLabels:
          role: frontend
    ports:
    - protocol: TCP
      port: 8080
```

该策略适用于 `sun` 命名空间中带有 `role: webapp` 标签的容器组（pod）。
+ 允许的流量：在 TCP 端口 `8080` 的 `moon` 命名空间中带有 `role: frontend` 标签的容器组（pod） 
+ 允许的流量：在 TCP 端口 `8080` 的 `stars` 命名空间中带有 role: frontend 标签的容器组（pod） 
+ 被阻止的流量：所有其他来自 `webapp` 容器组（pod）的出站流量都被隐式拒绝

## 管理员（或集群）网络策略
<a name="_admin_or_cluster_network_policy"></a>

![\[EKS 中的网络策略评估顺序示意图\]](http://docs.aws.amazon.com/zh_cn/eks/latest/userguide/images/evaluation-order.png)


您可以使用 `ClusterNetworkPolicy` 来强制执行适用于整个集群的网络安全标准。无需为每个命名空间重复定义和维护不同的策略，而是可以使用单个策略来集中管理集群中不同工作负载的网络访问权限控制，无论其命名空间如何。

### 使用案例
<a name="_use_cases_2"></a>
+ 集中管理 EKS 集群中所有（或部分）工作负载的网络访问权限控制。
+ 定义整个集群的默认网络安全状况。
+ 以更具运营效率的方式，将组织安全标准扩展到集群范围。

### 示例
<a name="_example_2"></a>

在以下策略中，您可以明确阻止来自其他命名空间的集群流量，以防止网络访问敏感的工作负载命名空间。

```
apiVersion: networking.k8s.aws/v1alpha1
kind: ClusterNetworkPolicy
metadata:
  name: protect-sensitive-workload
spec:
  tier: Admin
  priority: 10
  subject:
    namespaces:
      matchLabels:
        kubernetes.io/metadata.name: earth
  ingress:
    - action: Deny
      from:
      - namespaces:
          matchLabels: {} # Match all namespaces.
      name: select-all-deny-all
```

## 重要提示
<a name="_important_notes"></a>

以下配置支持适用于 Kubernetes 的 Amazon VPC CNI 插件中的网络策略。
+ 适用于标准和管理员网络策略的 Amazon VPC CNI 插件 1.21.0 版本（或更高版本）。
+ 为 `IPv4` 或 `IPv6` 地址配置的集群。
+ 您可以将网络策略与[容器组（pod）的安全组](security-groups-for-pods.md)结合使用。通过网络策略，您可以控制集群内的所有通信。借助容器组（pod）的安全组，您可以控制从容器组（pod）中的应用程序对 AWS 服务的访问。
+ 您可以将网络策略与*自定义网络*和*前缀委派*结合使用。

## 注意事项
<a name="cni-network-policy-considerations"></a>

 **架构** 
+ 当使用适用于 Kubernetes 的 Amazon VPC CNI 插件，将其网络策略应用于集群时，您只能将策略应用于 Amazon EC2 Linux 节点。无法将策略应用于 Fargate 或 Windows 节点。
+ 网络策略仅适用于其中一个 `IPv4` 或 `IPv6` 地址，但不适用于两者。在 `IPv4` 集群中，VPC CNI 为容器组（pod）分配 `IPv4` 地址并应用 `IPv4` 策略。在 `IPv6` 集群中，VPC CNI 为容器组（pod）分配 `IPv6` 地址并应用 `IPv6` 策略。系统将忽略应用于 `IPv6` 集群的任何 `IPv4` 网络策略规则。系统将忽略应用于 `IPv4` 集群的任何 `IPv6` 网络策略规则。

 **网络策略** 
+ 网络策略仅适用于属于部署构成部分的容器组（pod）。不能将网络策略应用于未设置 `metadata.ownerReferences` 的独立容器组（pod）。
+ 可以对同一容器组（pod）应用多个网络策略。当配置两个或多个选择同一容器组（pod）的策略时，所有策略都将应用于该容器组（pod）。
+ 在所有网络策略中，单个 IP 地址范围（CIDR）的最大端口和协议组合数量为 24 个。`namespaceSelector` 等选择器会解析为一个或多个 CIDR。如果多个选择器解析为单个 CIDR，或者您在相同或不同的网络策略中多次指定了相同的直接 CIDR，这些都会计入此限制。
+ 对于任何 Kubernetes 服务，服务端口必须与容器端口相同。如果您使用的是命名端口，也请在服务规范中使用相同的名称。

 **管理员网络策略** 

1.  **管理员层策略（先进行评估）**：首先对所有管理员层 ClusterNetworkPolicies 进行评估，然后再评估任何其他策略。在管理员层中，策略按优先级顺序处理（优先级序号最小者优先）。操作类型决定了接下来的操作。
   +  **Deny 操作（优先级最高）**：当具有 Deny 操作的管理员策略与流量匹配时，无论采用何种其他策略，该流量都会立即被阻止。不再处理其他 ClusterNetworkPolicy 或 NetworkPolicy 规则。这样可以确保组织范围的安全控制不会被命名空间级别的策略所覆盖。
   +  **Allow 操作**：评估 Deny 规则后，将按优先级顺序处理具有 Allow 操作的管理员策略（优先级序号最小者优先）。当 Allow 操作匹配时，流量将被接受，并且不再进行进一步的策略评估。这些策略可以根据标签选择器授予跨多个命名空间的访问权限，从而集中控制哪些工作负载可以访问特定资源。
   +  **Pass 操作**：管理员层策略中的 Pass 操作将决策委托给较低层级。当流量与 Pass 规则匹配时，评估将跳过该流量的所有剩余管理层规则，直接进入 NetworkPolicy 层。这允许管理员将某些流量模式的控制权明确委托给应用程序团队。例如，您可以使用 Pass 规则将命名空间内的流量管理委托给命名空间管理员，同时保持对外部访问权限的严格控制。

1.  **网络策略层**：如果没有与 Deny 或 Allow 匹配的管理员层策略，或者匹配了 Pass 操作，则接下来将评估命名空间范围的 NetworkPolicy 资源。这些策略在各个命名空间内提供精细的控制，并由应用程序团队管理。命名空间范围的策略只能比管理员策略更严格。它们无法覆盖管理员策略的 Deny 决策，但可以进一步限制管理员策略允许或通过的流量。

1.  **基准层管理员策略**：如果没有管理员或命名空间范围的策略与流量匹配，则会评估基准层 ClusterNetworkPolicies。它们提供了可以被命名空间范围的策略覆盖的默认安全状况，允许管理员设置组织范围的默认值，同时让团队可以灵活地根据需要进行自定义。基准策略按优先级顺序进行评估（优先级序号最小者优先）。

1.  **默认拒绝（如果没有匹配的策略）**：这种默认拒绝行为可确保仅允许明确允许的连接，从而保持稳固的安全状况。

 **迁移** 
+ 如果集群当前使用第三方解决方案来管理 Kubernetes 网络策略，则可将这些策略与适用于 Kubernetes 的 Amazon VPC CNI 插件结合使用。但是，您必须删除现有的解决方案，使其不再管理相同的策略。

**警告**  
建议您在删除网络策略解决方案后，替换所有应用过该网络策略解决方案的节点。这是因为如果解决方案的某个容器组（pod）突然退出，其流量规则可能会遗留下来。

 **安装**。
+ 网络策略功能创建并需要一个名为 `policyendpoints.networking.k8s.aws` 的 `PolicyEndpoint` 自定义资源定义（CRD）。自定义资源的 `PolicyEndpoint` 对象由 Amazon EKS 管理。您不应该修改或删除这些资源。
+ 如果您运行的容器组（pod）使用实例角色 IAM 凭证或连接到 EC2 IMDS，请注意检查是否存在会阻止访问 EC2 IMDS 的网络策略。您可能需要添加网络策略以允许访问 EC2 IMDS。有关更多信息，请参阅 Amazon EC2 用户指南中的[实例元数据和用户数据](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-instance-metadata.html)。

  *对服务账户使用 IAM 角色*或使用 *EKS 容器组身份*的容器组（pod）无法访问 EC2 IMDS。
+ 适用于 Kubernetes 的 Amazon VPC CNI 插件不会将网络策略应用于每个容器组（pod）的其他网络接口，只会应用于每个容器组（pod）的主接口 (`eth0`)。这会影响以下架构：
  +  `ENABLE_V4_EGRESS` 变量设置为 `true` 的 `IPv6` 容器组。此变量使 `IPv4` 出口功能能够将 IPv6 容器组连接到 `IPv4` 端点，例如集群外部的端点。`IPv4` 出口功能的工作原理是使用本地环回 IPv4 地址创建一个额外的网络接口。
  + 使用诸如 Multus 之类的链式网络插件时。由于这些插件为每个容器组（pod）添加了网络接口，因此网络策略不适用于链式网络插件。

# 使用 Kubernetes 网络策略限制容器组（pod）网络流量
<a name="cni-network-policy-configure"></a>

您可以使用 Kubernetes 网络策略来限制进出容器组（pod）的网络流量。有关更多信息，请参阅 Kubernetes 文档中的[网络策略](https://kubernetes.io/docs/concepts/services-networking/network-policies/)。

要使用此功能，您必须配置以下内容：

1. 在容器组（pod）启动时设置策略实施。您可以在 VPC CNI `DaemonSet` 的 `aws-node` 容器中执行此操作。

1. 为附加组件启用网络策略参数。

1. 将集群配置为使用 Kubernetes 网络策略

开始之前，请查看注意事项。有关更多信息，请参阅 [注意事项](cni-network-policy.md#cni-network-policy-considerations)。

## 先决条件
<a name="cni-network-policy-prereqs"></a>

以下是使用此功能的先决条件：

### 最低集群版本
<a name="cni-network-policy-minimum"></a>

现有 Amazon EKS 集群。要部署一个角色，请参阅[开始使用 Amazon EKS](getting-started.md)。该集群当前运行的必须是下表中列出的 Kubernetes 版本和平台版本之一。请注意，也支持所有比所列版本更高的 Kubernetes 和平台版本。您可以通过将以下命令中的 *my-cluster* 替换为集群名称，然后运行修改后的命令来检查当前的 Kubernetes 版本：

```
aws eks describe-cluster --name my-cluster --query cluster.version --output text
```


| Kubernetes 版本 | 平台版本 | 
| --- | --- | 
|   `1.27.4`   |   `eks.5`   | 
|   `1.26.7`   |   `eks.6`   | 

### 最低 Amazon CNI 版本
<a name="cni-network-policy-minimum-vpc"></a>

要同时创建标准 Kubernetes 网络策略和管理员网络策略，您需要运行 `1.21` 版的 VPC CNI 插件。您可以使用以下命令查看当前使用的版本。

```
kubectl describe daemonset aws-node --namespace kube-system | grep amazon-k8s-cni: | cut -d : -f 3
```

如果您的版本低于 `1.21`，请查看 [更新 Amazon VPC CNI（Amazon EKS 附加组件）](vpc-add-on-update.md) 将版本升级到 `1.21` 版本或更高版本。

### 最低 Amazon 内核版本
<a name="cni-network-policy-minimum-linux"></a>

您的节点必须具有 Linux 内核版本 `5.10` 或更高版本。您可以使用 `uname -r` 检查您的内核版本。如果您使用的是最新版本的 Amazon EKS 优化 Amazon Linux、Amazon EKS 优化版加速型 Amazon Linux AMI 和 Bottlerocket AMI，则已拥有所需的内核版本。

Amazon EKS 优化加速的 Amazon Linux AMI 版本 `v20231116`，或更高版本拥有内核版本 `5.10`。

## 第 1 步：在容器组（pod）启动时设置策略实施
<a name="cni-network-policy-configure-policy"></a>

适用于 Kubernetes 的 Amazon VPC CNI 插件为容器组（pod）配置网络策略，同时进行容器组（pod）预置。在为新的容器组（pod）配置所有策略之前，新的容器组（pod）中的容器将从*默认允许策略*开始。这称为*标准模式*。默认允许策略意味着允许所有进出新容器组（pod）的入口和出口流量。例如，在使用生效的策略更新新的容器组之前，容器组不会强制执行任何防火墙规则（允许所有流量）。

将 `NETWORK_POLICY_ENFORCING_MODE` 变量设置为 `strict` 后，使用 VPC CNI 的容器组（pod）从*默认拒绝策略*开始，然后将配置策略。这称为*严格模式*。在严格模式下，您必须为集群中容器组（pod）需要访问的每个端点制定网络策略。请注意，此要求适用于 CoreDNS 容器组（pod）。未为带有主机网络的容器组（pod）配置默认拒绝策略。

您可以通过在 VPC CNI `DaemonSet` 的 `aws-node` 容器中将环境变量 `NETWORK_POLICY_ENFORCING_MODE` 设置为 `strict` 来更改此默认网络策略。

```
env:
  - name: NETWORK_POLICY_ENFORCING_MODE
    value: "strict"
```

## 第 2 步：为附加组件启用网络策略参数
<a name="enable-network-policy-parameter"></a>

默认情况下，网络策略功能使用节点上的端口 `8162` 获取指标。此外，该功能还使用端口 `8163` 进行运行状况探测。如果您在需要使用这些端口的节点或 Pod 内运行其他应用程序，则该应用程序将无法运行。在 VPC CNI `v1.14.1` 版或更高版本中，您可以更改这些端口。

要为附加组件启用网络策略参数，请使用以下程序。

### AWS 管理控制台
<a name="cni-network-policy-console"></a>

1. 打开 [Amazon EKS 控制台](https://console.aws.amazon.com/eks/home#/clusters)。

1. 在左侧导航窗格中，选择**集群**，然后选择要为其配置 Amazon VPC CNI 附加组件的集群名称。

1. 选择**附加组件**选项卡。

1. 选择附加组件框右上角的框，然后选择 **Edit**（编辑）。

1. 在**配置 `Amazon VPC CNI`** 页面上：

   1. 在**版本**列表中选择 `v1.14.0-eksbuild.3` 或更高版本。

   1. 展开**可选配置设置**。

   1. 在**配置值**中输入 JSON 键 `"enableNetworkPolicy":` 和值 `"true"`。生成的文本必须是有效的 JSON 对象。如果此键和值是文本框中的唯一数据，请用大括号 `{ }` 将键和值括起来。

      以下示例启用了网络策略功能，并将指标和运行状况探测设置为默认端口号：

      ```
      {
          "enableNetworkPolicy": "true",
          "nodeAgent": {
              "healthProbeBindAddr": "8163",
              "metricsBindAddr": "8162"
          }
      }
      ```

### Helm
<a name="cni-network-helm"></a>

如果已通过 `helm` 安装适用于 Kubernetes 的 Amazon VPC CNI 插件，则可以更新配置以更改端口。

1. 运行以下命令以更改端口。分别在键 `nodeAgent.metricsBindAddr` 或键 `nodeAgent.healthProbeBindAddr` 的值中设置端口号。

   ```
   helm upgrade --set nodeAgent.metricsBindAddr=8162 --set nodeAgent.healthProbeBindAddr=8163 aws-vpc-cni --namespace kube-system eks/aws-vpc-cni
   ```

### kubectl
<a name="cni-network-policy-kubectl"></a>

1. 在编辑器中打开 `aws-node` `DaemonSet`。

   ```
   kubectl edit daemonset -n kube-system aws-node
   ```

1. 在 VPC CNI `aws-node` 守护程序集清单中 `aws-network-policy-agent` 容器的 `args:` 中，替换以下命令参数中的端口号。

   ```
       - args:
               - --metrics-bind-addr=:8162
               - --health-probe-bind-addr=:8163
   ```

## 步骤 3：将集群配置为使用 Kubernetes 网络策略
<a name="cni-network-policy-setup"></a>

您可以为 Amazon EKS 附加组件或自行管理的附加组件设置此项。

### Amazon EKS 附加组件
<a name="cni-network-policy-setup-procedure-add-on"></a>

使用 AWS CLI，您可以通过运行以下命令将集群配置为使用 Kubernetes 网络策略。将 `my-cluster` 替换为集群的名称，并将 IAM 角色 ARN 替换为您正在使用的角色。

```
aws eks update-addon --cluster-name my-cluster --addon-name vpc-cni --addon-version v1.14.0-eksbuild.3 \
    --service-account-role-arn arn:aws:iam::123456789012:role/AmazonEKSVPCCNIRole \
    --resolve-conflicts PRESERVE --configuration-values '{"enableNetworkPolicy": "true"}'
```

要使用 AWS 管理控制台配置此项，请按以下步骤操作：

1. 打开 [Amazon EKS 控制台](https://console.aws.amazon.com/eks/home#/clusters)。

1. 在左侧导航窗格中，选择**集群**，然后选择要为其配置 Amazon VPC CNI 附加组件的集群名称。

1. 选择**附加组件**选项卡。

1. 选择附加组件框右上角的框，然后选择 **Edit**（编辑）。

1. 在**配置 `Amazon VPC CNI`** 页面上：

   1. 在**版本**列表中选择 `v1.14.0-eksbuild.3` 或更高版本。

   1. 展开**可选配置设置**。

   1. 在**配置值**中输入 JSON 键 `"enableNetworkPolicy":` 和值 `"true"`。生成的文本必须是有效的 JSON 对象。如果此键和值是文本框中的唯一数据，请用大括号 `{ }` 将键和值括起来。以下示例显示网络策略已启用：

      ```
      { "enableNetworkPolicy": "true" }
      ```

      下面的屏幕截图为此场景的一个示例。  
![\[<shared id="consolelong"/> 在可选配置中显示带有网络策略的 VPC CNI 附加组件。\]](http://docs.aws.amazon.com/zh_cn/eks/latest/userguide/images/console-cni-config-network-policy.png)

### 自主管理的附加组件
<a name="cni-network-policy-setup-procedure-self-managed-add-on"></a>

如果已通过 `helm` 安装适用于 Kubernetes 的 Amazon VPC CNI 插件，则可以更新配置以启用网络策略。

1. 运行以下命令以启用网络策略。

   ```
   helm upgrade --set enableNetworkPolicy=true aws-vpc-cni --namespace kube-system eks/aws-vpc-cni
   ```

1. 在编辑器中打开 `amazon-vpc-cni` `ConfigMap`。

   ```
   kubectl edit configmap -n kube-system amazon-vpc-cni -o yaml
   ```

1. 将以下行添加到 `ConfigMap` 中的 `data`。

   ```
   enable-network-policy-controller: "true"
   ```

   添加该行后，您的 `ConfigMap` 应该看起来像下面的示例。

   ```
   apiVersion: v1
    kind: ConfigMap
    metadata:
     name: amazon-vpc-cni
     namespace: kube-system
    data:
     enable-network-policy-controller: "true"
   ```

1. 在编辑器中打开 `aws-node` `DaemonSet`。

   ```
   kubectl edit daemonset -n kube-system aws-node
   ```

   1. 在 VPC CNI `aws-node` 守护程序集清单中 `aws-network-policy-agent` 容器的 `args:` 中，将命令参数 `--enable-network-policy=false` 中的 `false` 替换为 `true`。

      ```
           - args:
              - --enable-network-policy=true
      ```

## 步骤 4：后续步骤
<a name="cni-network-policy-setup-procedure-confirm"></a>

完成配置后，确认 `aws-node` 容器组（pod）正在您的集群上运行。

```
kubectl get pods -n kube-system | grep 'aws-node\|amazon'
```

示例输出如下。

```
aws-node-gmqp7                                          2/2     Running   1 (24h ago)   24h
aws-node-prnsh                                          2/2     Running   1 (24h ago)   24h
```

版本 `1.14` 及更高版本的 `aws-node` 容器组中有 2 个容器。在以前的版本中，如果禁用网络策略，则 `aws-node` 容器组（pod）中只有 1 个容器。

您现在可以将 Kubernetes 网络策略部署到集群。

要实施 Kubernetes 网络策略，您可以创建 Kubernetes `NetworkPolicy` 或 `ClusterNetworkPolicy` 对象并将其部署到集群。`NetworkPolicy` 对象的范围限定为命名空间，而 `ClusterNetworkPolicy` 对象的范围可限定为整个集群或多个命名空间。您可以实施策略，根据标签选择器、命名空间和 IP 地址范围来允许或拒绝容器组（pod）之间的流量。有关创建 `NetworkPolicy` 对象的更多信息，请参阅 Kubernetes 文档中的[网络策略](https://kubernetes.io/docs/concepts/services-networking/network-policies/#networkpolicy-resource)。

Kubernetes `NetworkPolicy` 对象的执行是使用 Extended Berkeley Packet Filter（eBPF）实施的。与基于 `iptables` 的实施相比，它具有更低的延迟和性能，包括降低 CPU 利用率和避免顺序查找。此外，eBPF 探测器还可以访问上下文丰富的数据，帮助调试复杂的内核级问题并提高可观测性。Amazon EKS 支持基于 eBPF 的导出程序，该导出程序利用探测器记录每个节点上的策略结果，并将数据导出到外部日志收集器以帮助调试。有关更多信息，请参阅 [eBPF 文档](https://ebpf.io/what-is-ebpf/#what-is-ebpf)。

# 禁用 Amazon EKS 容器组（pod）网络流量的 Kubernetes 网络策略
<a name="network-policy-disable"></a>

禁用 Kubernetes 网络策略，停止限制 Amazon EKS 容器组（pod）网络流量

1. 列出所有 Kubernetes 网络策略。

   ```
   kubectl get netpol -A
   ```

1. 删除所有 Kubernetes 网络策略。必须首先删除所有网络策略，然后才能禁用网络策略。

   ```
   kubectl delete netpol <policy-name>
   ```

1. 在编辑器中打开 aws-node DaemonSet。

   ```
   kubectl edit daemonset -n kube-system aws-node
   ```

1. 在 VPC CNI `aws-node` 守护程序集清单中 `aws-network-policy-agent` 容器的 `args:` 中，将命令参数 `--enable-network-policy=true` 中的 `true` 替换为 `false`。

   ```
        - args:
           - --enable-network-policy=true
   ```

# 排查 Amazon EKS 的 Kubernetes 网络策略问题
<a name="network-policies-troubleshooting"></a>

这是 Amazon VPC CNI 网络策略功能的故障排除指南。

本指南涵盖以下内容：
+ 安装信息、CRD 和 RBAC 权限（[新的 `policyendpoints` CRD 和权限](#network-policies-troubleshooting-permissions)） 
+ 诊断网络策略问题时要检查的日志（[网络策略日志](#network-policies-troubleshooting-flowlogs)） 
+ 运行 eBPF SDK 工具集进行故障排除
+ 已知问题和解决方案 [已知问题和解决方案](#network-policies-troubleshooting-known-issues) 

**注意**  
请注意，网络策略仅适用于通过 Kubernetes *部署*创建的容器组。有关 VPC CNI 中网络策略的更多限制，请参阅[注意事项](cni-network-policy.md#cni-network-policy-considerations)。

您可以通过查看[网络策略日志](#network-policies-troubleshooting-flowlogs)和运行 [eBPF SDK](#network-policies-ebpf-sdk) 中的工具，对使用网络策略的网络连接进行问题排查和调查。

## 新的 `policyendpoints` CRD 和权限
<a name="network-policies-troubleshooting-permissions"></a>
+ CRD：`policyendpoints.networking.k8s.aws`
+ Kubernetes API：名为 `v1.networking.k8s.io` 的 `apiservice` 
+ Kubernetes 资源：`Kind: NetworkPolicy`
+ RBAC：名为 `aws-node` 的 `ClusterRole`（VPC CNI），名为 `eks:network-policy-controller` 的 `ClusterRole`（EKS 集群控制面板中的网络策略控制器）

对于网络策略，VPC CNI 会创建一个名为 `policyendpoints.networking.k8s.aws` 的新 `CustomResourceDefinition`（CRD）。VPC CNI 必须有相关权限，以创建 CRD 以及创建由 VPC CNI（`eniconfigs.crd.k8s.amazonaws.com`）安装的此 CRD 和另一个 CRD 的 CustomResources（CR）。这两个 CRD 都在 GitHub 上的 [`crds.yaml` 文件](https://github.com/aws/amazon-vpc-cni-k8s/blob/master/charts/aws-vpc-cni/crds/customresourcedefinition.yaml)中提供。具体而言，VPC CNI 必须具有对 `policyendpoints` 执行“获取”、“列出”和“监控”操作的权限。

Kubernetes *网络策略*是名为 `v1.networking.k8s.io` 的 `apiservice` 的一部分，这是您的策略 YAML 文件中的 `apiversion: networking.k8s.io/v1`。VPC CNI `DaemonSet` 必须有使用 Kubernetes API 这一部分的权限。

VPC CNI 权限位于名为 `aws-node` 的 `ClusterRole` 中。请注意，`ClusterRole` 对象未按命名空间分组。以下显示了集群的 `aws-node`：

```
kubectl get clusterrole aws-node -o yaml
```

```
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  labels:
    app.kubernetes.io/instance: aws-vpc-cni
    app.kubernetes.io/managed-by: Helm
    app.kubernetes.io/name: aws-node
    app.kubernetes.io/version: v1.19.4
    helm.sh/chart: aws-vpc-cni-1.19.4
    k8s-app: aws-node
  name: aws-node
rules:
- apiGroups:
  - crd.k8s.amazonaws.com
  resources:
  - eniconfigs
  verbs:
  - list
  - watch
  - get
- apiGroups:
  - ""
  resources:
  - namespaces
  verbs:
  - list
  - watch
  - get
- apiGroups:
  - ""
  resources:
  - pods
  verbs:
  - list
  - watch
  - get
- apiGroups:
  - ""
  resources:
  - nodes
  verbs:
  - list
  - watch
  - get
- apiGroups:
  - ""
  - events.k8s.io
  resources:
  - events
  verbs:
  - create
  - patch
  - list
- apiGroups:
  - networking.k8s.aws
  resources:
  - policyendpoints
  verbs:
  - get
  - list
  - watch
- apiGroups:
  - networking.k8s.aws
  resources:
  - policyendpoints/status
  verbs:
  - get
- apiGroups:
  - vpcresources.k8s.aws
  resources:
  - cninodes
  verbs:
  - get
  - list
  - watch
  - patch
```

此外，每个 EKS 集群的控制面板中都会运行一个新的控制器。控制器使用名为 `eks:network-policy-controller` 的 `ClusterRole` 的权限。以下显示了集群的 `eks:network-policy-controller`：

```
kubectl get clusterrole eks:network-policy-controller -o yaml
```

```
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
  labels:
    app.kubernetes.io/name: amazon-network-policy-controller-k8s
  name: eks:network-policy-controller
rules:
- apiGroups:
  - ""
  resources:
  - namespaces
  verbs:
  - get
  - list
  - watch
- apiGroups:
  - ""
  resources:
  - pods
  verbs:
  - get
  - list
  - watch
- apiGroups:
  - ""
  resources:
  - services
  verbs:
  - get
  - list
  - watch
- apiGroups:
  - networking.k8s.aws
  resources:
  - policyendpoints
  verbs:
  - create
  - delete
  - get
  - list
  - patch
  - update
  - watch
- apiGroups:
  - networking.k8s.aws
  resources:
  - policyendpoints/finalizers
  verbs:
  - update
- apiGroups:
  - networking.k8s.aws
  resources:
  - policyendpoints/status
  verbs:
  - get
  - patch
  - update
- apiGroups:
  - networking.k8s.io
  resources:
  - networkpolicies
  verbs:
  - get
  - list
  - patch
  - update
  - watch
```

## 网络策略日志
<a name="network-policies-troubleshooting-flowlogs"></a>

VPC CNI 根据网络策略允许还是拒绝连接的每个决定都将记录在*流日志*中。每个节点上的网络策略日志包括每个具有网络策略的容器组（pod）流日志。网络策略日志存储在 `/var/log/aws-routed-eni/network-policy-agent.log`。以下示例来自 `network-policy-agent.log` 文件：

```
{"level":"info","timestamp":"2023-05-30T16:05:32.573Z","logger":"ebpf-client","msg":"Flow Info: ","Src
IP":"192.168.87.155","Src Port":38971,"Dest IP":"64.6.160","Dest
Port":53,"Proto":"UDP","Verdict":"ACCEPT"}
```

默认情况下，网络策略日志被禁用。要启用网络策略日志，请按照下列步骤操作：

**注意**  
网络策略日志需要为 VPC CNI `aws-node` `DaemonSet` 清单中的 `aws-network-policy-agent` 容器额外提供 1 个 vCPU。

### Amazon EKS 附加组件
<a name="cni-network-policy-flowlogs-addon"></a>

 ** AWS 管理控制台 **   

1. 打开 [Amazon EKS 控制台](https://console.aws.amazon.com/eks/home#/clusters)。

1. 在左侧导航窗格中，选择**集群**，然后选择要为其配置 Amazon VPC CNI 附加组件的集群名称。

1. 选择**附加组件**选项卡。

1. 选择附加组件框右上角的框，然后选择 **Edit**（编辑）。

1. 在**配置 *Amazon VPC CNI*** 页面上：

   1. 在**版本**下拉列表中选择 `v1.14.0-eksbuild.3` 或更高版本。

   1. 展开**可选配置设置**。

   1. 输入顶级 JSON 键 `"nodeAgent":`，值是一个在**配置值**中键为 `"enablePolicyEventLogs":` 且值为 `"true"` 的对象。生成的文本必须是有效的 JSON 对象。以下示例显示网络策略和网络策略日志已启用，并将网络策略日志发送到 CloudWatch Logs：

      ```
      {
          "enableNetworkPolicy": "true",
          "nodeAgent": {
              "enablePolicyEventLogs": "true"
          }
      }
      ```

下面的屏幕截图为此场景的一个示例。

![\[<shared id="consolelong"/>在可选配置中显示带有网络策略和 CloudWatch Logs 的 VPC CNI 附加组件。\]](http://docs.aws.amazon.com/zh_cn/eks/latest/userguide/images/console-cni-config-network-policy-logs.png)


 AWS CLI  

1. 运行以下 AWS CLI 命令。将 `my-cluster` 替换为集群的名称，并将 IAM 角色 ARN 替换为您正在使用的角色。

   ```
   aws eks update-addon --cluster-name my-cluster --addon-name vpc-cni --addon-version v1.14.0-eksbuild.3 \
       --service-account-role-arn arn:aws:iam::123456789012:role/AmazonEKSVPCCNIRole \
       --resolve-conflicts PRESERVE --configuration-values '{"nodeAgent": {"enablePolicyEventLogs": "true"}}'
   ```

### 自主管理的附加组件
<a name="cni-network-policy-flowlogs-selfmanaged"></a>

Helm  
如果已通过 `helm` 安装适用于 Kubernetes 的 Amazon VPC CNI 插件，则可以更新配置来编写网络策略日志。  

1. 运行以下命令以启用网络策略。

   ```
   helm upgrade --set nodeAgent.enablePolicyEventLogs=true aws-vpc-cni --namespace kube-system eks/aws-vpc-cni
   ```

kubectl  
如果已通过 `kubectl` 安装适用于 Kubernetes 的 Amazon VPC CNI 插件，则可以更新配置来编写网络策略日志。  

1. 在编辑器中打开 `aws-node` `DaemonSet`。

   ```
   kubectl edit daemonset -n kube-system aws-node
   ```

1. 在 VPC CNI `aws-node` `DaemonSet` 清单中 `aws-network-policy-agent` 容器的 `args:` 中，将命令参数 `--enable-policy-event-logs=false` 中的 `false` 替换为 `true`。

   ```
        - args:
           - --enable-policy-event-logs=true
   ```

### 将网络策略日志发送到 Amazon CloudWatch Logs
<a name="network-policies-cloudwatchlogs"></a>

您可以使用 Amazon CloudWatch Logs 等服务监控网络策略日志。您可以使用以下方法将网络策略日志发送到 CloudWatch Logs。

对于 EKS 集群，策略日志将放在 `/aws/eks/cluster-name/cluster/` 下；对于自主管理型 K8S 集群，日志将放在 `/aws/k8s-cluster/cluster/` 下。

#### 使用适用于 Kubernetes 的 Amazon VPC CNI 插件发送网络策略日志
<a name="network-policies-cwl-agent"></a>

如果启用网络策略，则会将第二个容器添加到*节点代理*的 `aws-node` 容器组（pod）。此节点代理可将网络策略日志发送到 CloudWatch Logs。

**注意**  
节点代理仅发送网络策略日志。不包括 VPC CNI 生成的其它日志。

##### 先决条件
<a name="cni-network-policy-cwl-agent-prereqs"></a>
+ 将以下权限作为节或单独的策略添加到您用于 VPC CNI 的 IAM 角色中。

  ```
  {
      "Version":"2012-10-17",		 	 	 
      "Statement": [
          {
              "Sid": "VisualEditor0",
              "Effect": "Allow",
              "Action": [
                  "logs:DescribeLogGroups",
                  "logs:CreateLogGroup",
                  "logs:CreateLogStream",
                  "logs:PutLogEvents"
              ],
              "Resource": "*"
          }
      ]
  }
  ```

##### Amazon EKS 附加组件
<a name="cni-network-policy-cwl-agent-addon"></a>

 ** AWS 管理控制台 **   

1. 打开 [Amazon EKS 控制台](https://console.aws.amazon.com/eks/home#/clusters)。

1. 在左侧导航窗格中，选择**集群**，然后选择要为其配置 Amazon VPC CNI 附加组件的集群名称。

1. 选择**附加组件**选项卡。

1. 选择附加组件框右上角的框，然后选择 **Edit**（编辑）。

1. 在**配置 *Amazon VPC CNI*** 页面上：

   1. 在**版本**下拉列表中选择 `v1.14.0-eksbuild.3` 或更高版本。

   1. 展开**可选配置设置**。

   1. 输入顶级 JSON 键 `"nodeAgent":`，值是一个在**配置值**中键为 `"enableCloudWatchLogs":` 且值为 `"true"` 的对象。生成的文本必须是有效的 JSON 对象。以下示例显示网络策略和网络策略日志已启用，并将日志发送到 CloudWatch Logs：

      ```
      {
          "enableNetworkPolicy": "true",
          "nodeAgent": {
              "enablePolicyEventLogs": "true",
              "enableCloudWatchLogs": "true",
          }
      }
      ```
下面的屏幕截图为此场景的一个示例。

![\[<shared id="consolelong"/>在可选配置中显示带有网络策略和 CloudWatch Logs 的 VPC CNI 附加组件。\]](http://docs.aws.amazon.com/zh_cn/eks/latest/userguide/images/console-cni-config-network-policy-logs-cwl.png)


 ** AWSCLI**   

1. 运行以下 AWS CLI 命令。将 `my-cluster` 替换为集群的名称，并将 IAM 角色 ARN 替换为您正在使用的角色。

   ```
   aws eks update-addon --cluster-name my-cluster --addon-name vpc-cni --addon-version v1.14.0-eksbuild.3 \
       --service-account-role-arn arn:aws:iam::123456789012:role/AmazonEKSVPCCNIRole \
       --resolve-conflicts PRESERVE --configuration-values '{"nodeAgent": {"enablePolicyEventLogs": "true", "enableCloudWatchLogs": "true"}}'
   ```

##### 自主管理的附加组件
<a name="cni-network-policy-cwl-agent-selfmanaged"></a>

 **Helm**   
如果已通过 `helm` 安装适用于 Kubernetes 的 Amazon VPC CNI 插件，则可以更新配置，将网络策略日志发送至 CloudWatch 日志。  

1. 运行以下命令以启用网络策略日志并将它们发送到 CloudWatch Logs。

   ```
   helm upgrade --set nodeAgent.enablePolicyEventLogs=true --set nodeAgent.enableCloudWatchLogs=true aws-vpc-cni --namespace kube-system eks/aws-vpc-cni
   ```

 **kubectl**   

1. 在编辑器中打开 `aws-node` `DaemonSet`。

   ```
   kubectl edit daemonset -n kube-system aws-node
   ```

1. 在 VPC CNI `aws-node` `DaemonSet` 清单中 `aws-network-policy-agent` 容器的 `args:` 中，将两个命令参数 `--enable-policy-event-logs=false` 和 `--enable-cloudwatch-logs=false` 中的 `false` 替换为 `true`。

   ```
        - args:
           - --enable-policy-event-logs=true
           - --enable-cloudwatch-logs=true
   ```

#### 使用 Fluent Bit `DaemonSet` 发送网络策略日志
<a name="network-policies-cwl-fluentbit"></a>

如果在 `DaemonSet` 中使用 Fluent Bit 从节点发送日志，则可以添加配置，纳入来自网络策略的网络策略日志。您可以使用以下示例配置：

```
    [INPUT]
        Name              tail
        Tag               eksnp.*
        Path              /var/log/aws-routed-eni/network-policy-agent*.log
        Parser            json
        DB                /var/log/aws-routed-eni/flb_npagent.db
        Mem_Buf_Limit     5MB
        Skip_Long_Lines   On
        Refresh_Interval  10
```

## 包含的 eBPF SDK
<a name="network-policies-ebpf-sdk"></a>

适用于 Kubernetes 的 Amazon VPC CNI 插件在节点上安装 eBPF SDK 工具集。您可以使用 eBPF SDK 工具来识别网络策略问题。例如，以下命令列出了节点上正在运行的程序。

```
sudo /opt/cni/bin/aws-eks-na-cli ebpf progs
```

要运行此命令，您可以使用任何方法连接到节点。

## 已知问题和解决方案
<a name="network-policies-troubleshooting-known-issues"></a>

以下各节介绍了 Amazon VPC CNI 网络策略功能的已知问题及其解决方案。

### 尽管 enable-policy-event-logs 设置为 false，但仍会生成网络策略日志
<a name="network-policies-troubleshooting-policy-event-logs"></a>

 **问题**：即使将 `enable-policy-event-logs` 设置为 `false`，EKS VPC CNI 仍会生成网络策略日志。

 **解决方案**：`enable-policy-event-logs` 设置仅禁用策略“决策”日志，但不会禁用所有网络策略代理日志记录。此行为已在 GitHub 上的 [aws-network-policy-agent README](https://github.com/aws/aws-network-policy-agent/) 中记录。要完全禁用日志记录，您可能需要调整其他日志记录配置。

### 网络策略映射清理问题
<a name="network-policies-troubleshooting-map-cleanup"></a>

 **问题**：删除容器组后，网络 `policyendpoint` 仍存在且未被清理。

 **解决方案**：此问题是由于 VPC CNI 附加组件版本 1.19.3-eksbuild.1 的问题引起的。更新为较新版本的 VPC CNI 附加组件即可解决此问题。

### 网络策略未应用
<a name="network-policies-troubleshooting-policyendpoint"></a>

 **问题**：网络策略功能在 Amazon VPC CNI 附加组件中已启用，但未正确应用网络策略。

如果您制定了网络策略 `kind: NetworkPolicy`，但其对容器组没有影响，则请检查 policyendpoint 对象是否是在与容器组相同的命名空间中创建的。如果命名空间中没有 `policyendpoint` 对象，则网络策略控制器（EKS 集群的一部分）无法为网络策略代理（VPC CNI 的一部分）创建要应用的网络策略规则。

 **解决方案**：解决方案是修复 VPC CNI（`ClusterRole` : `aws-node`）和网络策略控制器（`ClusterRole` : `eks:network-policy-controller`）的权限，并允许在任何策略执行工具（例如 Kyverno）中执行这些操作。确保 Kyverno 策略不会阻止创建 `policyendpoint` 对象。有关[新的 `policyendpoints` CRD 和权限](#network-policies-troubleshooting-permissions)中所需的权限，请参阅上一节。

### 在严格模式下删除策略后，容器组不会恢复为默认拒绝状态
<a name="network-policies-troubleshooting-strict-mode-fallback"></a>

 **问题**：在严格模式下启用网络策略时，容器组以默认拒绝策略开头。应用策略后，允许流量到达指定的端点。但是，删除策略后，容器组不会恢复为默认拒绝状态，而是进入默认允许状态。

 **解决方案**：此问题在 VPC CNI 版本 1.19.3（包含网络策略代理 1.2.0 版本）中已修复。修复后，启用严格模式时，移除策略后，容器组将按预期恢复为默认拒绝状态。

### 容器组的安全组启动延迟
<a name="network-policies-troubleshooting-sgfp-latency"></a>

 **问题**：在 EKS 中使用容器组的安全组功能时，容器组启动延迟会增加。

 **解决方案**：延迟是由于资源控制器对 `CreateNetworkInterface` API 的速率限制（API 节流）造成的，VPC 资源控制器使用其为容器组创建分支 ENI。请查看您的账户针对此操作的 API 限制，并在需要时考虑申请提高限制。

### 由于 vpc.amazonaws.com/pod-eni 不足导致 FailedScheduling
<a name="network-policies-troubleshooting-insufficient-pod-eni"></a>

 **问题**：容器组无法调度，错误信息：`FailedScheduling 2m53s (x28 over 137m) default-scheduler 0/5 nodes are available: 5 Insufficient vpc.amazonaws.com/pod-eni. preemption: 0/5 nodes are available: 5 No preemption victims found for incoming pod.`

 **解决方案**：与上一个问题类似，为容器组分配安全组会增加容器组调度延迟，并且添加每个 ENI 的时间可能会超出 CNI 阈值，从而导致容器组启动失败。这是使用容器组的安全组时的预期行为。在设计工作负载架构时，请考虑调度的影响。

### IPAM 连接问题和分段故障
<a name="network-policies-troubleshooting-systemd-udev"></a>

 **问题**：发生多个错误，包括 IPAM 连接问题、限制请求和分段故障：
+  `Checking for IPAM connectivity …​` 
+  `Throttling request took 1.047064274s` 
+  `Retrying waiting for IPAM-D` 
+  `panic: runtime error: invalid memory address or nil pointer dereference` 

 **解决方案**：如果您在 AL2023 上安装 `systemd-udev`，则会出现此问题，因为文件使用违反策略重写。更新为包含更新软件包的其他 `releasever` 或手动更新软件包本身时，可能会发生这种情况。避免在 AL2023 节点上安装或更新 `systemd-udev`。

### 无法按名称查找设备错误
<a name="network-policies-troubleshooting-device-not-found"></a>

 **问题**：错误消息：`{"level":"error","ts":"2025-02-05T20:27:18.669Z","caller":"ebpf/bpf_client.go:578","msg":"failed to find device by name eni9ea69618bf0: %!w(netlink.LinkNotFoundError={0xc000115310})"}`

 **解决方案**：此问题已发现并在最新版本的 Amazon VPC CNI 网络策略代理（v1.2.0）中修复。更新到最新版本的 VPC CNI 即可解决此问题。

### Multus CNI 映像中的 CVE 漏洞
<a name="network-policies-troubleshooting-cve-multus"></a>

 **问题**：增强版 EKS ImageScan CVE 报告发现 Multus CNI 映像版本 v4.1.4-eksbuild.2\$1thick 中存在漏洞。

 **解决方案**：更新为无漏洞的新版本 Multus CNI 映像和新的网络策略控制器映像。可以更新扫描器以修复先前版本中发现的漏洞。

### 日志中的 Flow Info DENY 裁决
<a name="network-policies-troubleshooting-flow-info-deny"></a>

 **问题**：网络策略日志显示 DENY 裁决：`{"level":"info","ts":"2024-11-25T13:34:24.808Z","logger":"ebpf-client","caller":"events/events.go:193","msg":"Flow Info: ","Src IP":"","Src Port":9096,"Dest IP":"","Dest Port":56830,"Proto":"TCP","Verdict":"DENY"}`

 **解决方案**：此问题已在新版本的网络策略控制器中得到解决。更新为最新的 EKS 平台版本即可解决日志记录问题。

### 从 Calico 迁移后容器组到容器组的通信问题
<a name="network-policies-troubleshooting-calico-migration"></a>

 **问题**：将 EKS 集群升级到版本 1.30 并将网络策略从 Calico 切换到 Amazon VPC CNI 后，应用网络策略后容器组到容器组的通信失败。删除网络策略后，通信即恢复。

 **解决方案**：VPC CNI 中的网络策略代理不能像 Calico 那样指定那么多的端口。相反，在网络策略中使用端口范围。网络策略中每个 `ingress:` 或 `egress:` 选择器中每个协议的唯一端口组合数最多为 24 个。使用端口范围可减少唯一端口的数量和避免此限制。

### 网络策略代理不支持独立容器组
<a name="network-policies-troubleshooting-standalone-pods"></a>

 **问题**：应用于独立容器组的网络策略可能存在不一致的行为。

 **解决方案**：网络策略代理目前仅支持作为部署/副本集一部分部署的容器组。如果将网络策略应用至独立容器组，则行为可能存在一些不一致。这将记录在本页顶部、[注意事项](cni-network-policy.md#cni-network-policy-considerations) 中和 GitHub 上的 [aws-network-policy-agent GitHub issue \$1327](https://github.com/aws/aws-network-policy-agent/issues/327) 中。将容器组作为部署或副本集的一部分进行部署，以实现一致的网络策略行为。

# Amazon EKS 的网络策略的 Stars 演示
<a name="network-policy-stars-demo"></a>

该演示在您的 Amazon EKS 集群上创建前端、后端和客户端服务。该演示还创建管理图形用户界面，用于显示各服务之间可用的传入和传出路径。我们建议您在不运行生产工作负载的集群上完成演示。

在您创建任何网络策略之前，所有服务可以双向通信。在应用网络策略后，您可以看到客户端只能与前端服务进行通信，而后端只能接受来自前端的流量。

1. 应用前端、后端、客户端和管理用户界面服务：

   ```
   kubectl apply -f https://raw.githubusercontent.com/aws-samples/eks-workshop/2f9d29ed3f82ed6b083649e975a0e574fb8a4058/content/beginner/120_network-policies/calico/stars_policy_demo/create_resources.files/namespace.yaml
   kubectl apply -f https://raw.githubusercontent.com/aws-samples/eks-workshop/2f9d29ed3f82ed6b083649e975a0e574fb8a4058/content/beginner/120_network-policies/calico/stars_policy_demo/create_resources.files/management-ui.yaml
   kubectl apply -f https://raw.githubusercontent.com/aws-samples/eks-workshop/2f9d29ed3f82ed6b083649e975a0e574fb8a4058/content/beginner/120_network-policies/calico/stars_policy_demo/create_resources.files/backend.yaml
   kubectl apply -f https://raw.githubusercontent.com/aws-samples/eks-workshop/2f9d29ed3f82ed6b083649e975a0e574fb8a4058/content/beginner/120_network-policies/calico/stars_policy_demo/create_resources.files/frontend.yaml
   kubectl apply -f https://raw.githubusercontent.com/aws-samples/eks-workshop/2f9d29ed3f82ed6b083649e975a0e574fb8a4058/content/beginner/120_network-policies/calico/stars_policy_demo/create_resources.files/client.yaml
   ```

1. 查看集群上的所有容器组（pod）。

   ```
   kubectl get pods -A
   ```

   示例输出如下。

   在输出中，您应该会在以下输出中显示的命名空间中看到容器。容器组（pod）的 *NAMES* 和 `READY` 列中的容器组（pod）数量与以下输出中的不同。在看到具有相似名称的容器并且它们在 `STATUS` 列中都具有 `Running` 之前，请不要继续。

   ```
   NAMESPACE         NAME                                       READY   STATUS    RESTARTS   AGE
   [...]
   client            client-xlffc                               1/1     Running   0          5m19s
   [...]
   management-ui     management-ui-qrb2g                        1/1     Running   0          5m24s
   stars             backend-sz87q                              1/1     Running   0          5m23s
   stars             frontend-cscnf                             1/1     Running   0          5m21s
   [...]
   ```

1. 要连接到管理用户界面，请连接到集群上运行的 `EXTERNAL-IP` 服务：

   ```
   kubectl get service/management-ui -n management-ui
   ```

1. 打开浏览器，进入上一步中的位置。您应该会看到管理用户界面。**C** 节点是客户端服务，**F** 节点是前端服务，**B** 节点是后端服务。每个节点都有到所有其他节点的完整通信访问权限（如粗体、彩色行所示）。  
![\[打开网络策略\]](http://docs.aws.amazon.com/zh_cn/eks/latest/userguide/images/stars-default.png)

1. 在 `stars` 和 `client` 命名空间中应用以下网络策略，以将服务彼此隔离：

   ```
   kind: NetworkPolicy
   apiVersion: networking.k8s.io/v1
   metadata:
     name: default-deny
   spec:
     podSelector:
       matchLabels: {}
   ```

   您可以使用以下命令将策略应用于两个命名空间：

   ```
   kubectl apply -n stars -f https://raw.githubusercontent.com/aws-samples/eks-workshop/2f9d29ed3f82ed6b083649e975a0e574fb8a4058/content/beginner/120_network-policies/calico/stars_policy_demo/apply_network_policies.files/default-deny.yaml
   kubectl apply -n client -f https://raw.githubusercontent.com/aws-samples/eks-workshop/2f9d29ed3f82ed6b083649e975a0e574fb8a4058/content/beginner/120_network-policies/calico/stars_policy_demo/apply_network_policies.files/default-deny.yaml
   ```

1. 刷新您的浏览器。您可以看到管理用户界面不再能访问任何节点，因此它们不会显示在用户界面中。

1. 应用以下不同的网络策略以允许管理用户界面访问这些服务。应用此策略以允许 UI：

   ```
   kind: NetworkPolicy
   apiVersion: networking.k8s.io/v1
   metadata:
     namespace: stars
     name: allow-ui
   spec:
     podSelector:
       matchLabels: {}
     ingress:
       - from:
           - namespaceSelector:
               matchLabels:
                 role: management-ui
   ```

   应用此策略以允许客户端：

   ```
   kind: NetworkPolicy
   apiVersion: networking.k8s.io/v1
   metadata:
     namespace: client
     name: allow-ui
   spec:
     podSelector:
       matchLabels: {}
     ingress:
       - from:
           - namespaceSelector:
               matchLabels:
                 role: management-ui
   ```

   您可以使用以下命令应用这两个策略：

   ```
   kubectl apply -f https://raw.githubusercontent.com/aws-samples/eks-workshop/2f9d29ed3f82ed6b083649e975a0e574fb8a4058/content/beginner/120_network-policies/calico/stars_policy_demo/apply_network_policies.files/allow-ui.yaml
   kubectl apply -f https://raw.githubusercontent.com/aws-samples/eks-workshop/2f9d29ed3f82ed6b083649e975a0e574fb8a4058/content/beginner/120_network-policies/calico/stars_policy_demo/apply_network_policies.files/allow-ui-client.yaml
   ```

1. 刷新您的浏览器。您可以看到管理用户界面可以再次访问节点，但各节点无法相互通信。  
![\[UI 访问网络策略\]](http://docs.aws.amazon.com/zh_cn/eks/latest/userguide/images/stars-no-traffic.png)

1. 应用以下网络策略以允许流量从前端服务传到后端服务：

   ```
   kind: NetworkPolicy
   apiVersion: networking.k8s.io/v1
   metadata:
     namespace: stars
     name: backend-policy
   spec:
     podSelector:
       matchLabels:
         role: backend
     ingress:
       - from:
           - podSelector:
               matchLabels:
                 role: frontend
         ports:
           - protocol: TCP
             port: 6379
   ```

1. 刷新您的浏览器。您将看到前端可以与后端进行通信。  
![\[前端到后端策略\]](http://docs.aws.amazon.com/zh_cn/eks/latest/userguide/images/stars-front-end-back-end.png)

1. 应用以下网络策略以允许流量从客户端传到前端服务：

   ```
   kind: NetworkPolicy
   apiVersion: networking.k8s.io/v1
   metadata:
     namespace: stars
     name: frontend-policy
   spec:
     podSelector:
       matchLabels:
         role: frontend
     ingress:
       - from:
           - namespaceSelector:
               matchLabels:
                 role: client
         ports:
           - protocol: TCP
             port: 80
   ```

1. 刷新您的浏览器。您将看到客户端可以与前端服务进行通信。前端服务仍可以与后端服务进行通信。  
![\[最终网络策略\]](http://docs.aws.amazon.com/zh_cn/eks/latest/userguide/images/stars-final.png)

1. （可选）完成该演示后，您可以删除其资源。

   ```
   kubectl delete -f https://raw.githubusercontent.com/aws-samples/eks-workshop/2f9d29ed3f82ed6b083649e975a0e574fb8a4058/content/beginner/120_network-policies/calico/stars_policy_demo/create_resources.files/client.yaml
   kubectl delete -f https://raw.githubusercontent.com/aws-samples/eks-workshop/2f9d29ed3f82ed6b083649e975a0e574fb8a4058/content/beginner/120_network-policies/calico/stars_policy_demo/create_resources.files/frontend.yaml
   kubectl delete -f https://raw.githubusercontent.com/aws-samples/eks-workshop/2f9d29ed3f82ed6b083649e975a0e574fb8a4058/content/beginner/120_network-policies/calico/stars_policy_demo/create_resources.files/backend.yaml
   kubectl delete -f https://raw.githubusercontent.com/aws-samples/eks-workshop/2f9d29ed3f82ed6b083649e975a0e574fb8a4058/content/beginner/120_network-policies/calico/stars_policy_demo/create_resources.files/management-ui.yaml
   kubectl delete -f https://raw.githubusercontent.com/aws-samples/eks-workshop/2f9d29ed3f82ed6b083649e975a0e574fb8a4058/content/beginner/120_network-policies/calico/stars_policy_demo/create_resources.files/namespace.yaml
   ```

   甚至在删除资源后，节点上仍可能存在网络策略端点，这些端点可能会以意想不到的方式干扰集群中的网络。删除这些规则的唯一可靠方法是重新启动节点或终止所有节点并将它们回收。要终止所有节点，请将自动扩缩组所需计数设置为 0，然后创建所需数量的备份，或者仅终止节点。

# 使用自定义网络在备用子网中部署容器组（pod）
<a name="cni-custom-network"></a>

 **适用对象**：Linux `IPv4` Fargate 节点以及带有 Amazon EC2 实例的 Linux 节点

![\[具有多个网络接口的节点示意图\]](http://docs.aws.amazon.com/zh_cn/eks/latest/userguide/images/cn-image.png)


默认情况下，当适用于 Kubernetes 的 Amazon VPC CNI 插件为 Amazon EC2 节点创建辅助[弹性网络接口](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-eni.html)（网络接口）时，会在与该节点的主网络接口相同的子网中创建它们。它还将相同的安全组关联到与主网络接口关联的辅助网络接口。出于以下一个或多个原因，您可能希望该插件在不同子网中创建辅助网络接口，或者希望将不同的安全组与辅助网络接口关联，或者希望同时实现此两者：
+ 主网络接口所在子网中可用的 `IPv4` 地址数量有限。这可能会限制您可以在子网中创建的容器组（pod）数量。通过对辅助网络接口使用不同的子网，您可以增加可用于容器组（pod）的 `IPv4` 地址的数量。
+ 出于安全原因，容器组（pod）可能需要使用与节点的主网络接口不同的子网或安全组。
+ 在公有子网中配置节点，在私有子网中放置容器组（pod）。与公有子网关联的路由表包含指向互联网网关的路由。与私有子网关联的路由表不包含指向互联网网关的路由。

**提示**  
您也可以直接向 Amazon EKS 集群添加新子网或现有子网，而不使用自定义联网。有关更多信息，请参阅 [通过管理控制台将现有 VPC 子网添加到 Amazon EKS 集群](eks-networking.md#add-existing-subnet)。

## 注意事项
<a name="cni-custom-network-considerations"></a>

以下是使用该功能的注意事项。
+ 启用自定义联网后，不会将分配给主网络接口的 IP 地址分配给容器组（pod）。仅会将辅助网络接口的 IP 地址分配给容器组（pod）。
+ 如果您的集群使用 `IPv6` 系列，您无法使用自定义联网。
+ 如果您计划仅为帮助缓解 `IPv4` 地址耗尽而使用自定义联网，您可以改为使用 `IPv6` 系列创建集群。有关更多信息，请参阅 [了解如何将 IPv6 地址分配给集群、容器组（pod）和服务](cni-ipv6.md)。
+ 尽管部署到为辅助网络接口指定的子网的容器组（pod）可以使用与节点的主网络接口不同的子网和安全组，子网和安全组也必须与节点位于同一 VPC 中。
+ 对于 Fargate，子网通过 Fargate 配置文件控制。有关更多信息，请参阅 [定义启动时将使用 AWS Fargate 的容器组（pod）](fargate-profile.md)。

# 自定义 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
   ```

# 为带前缀的 Amazon EKS 节点分配更多 IP 地址
<a name="cni-increase-ip-addresses"></a>

 **适用于**：带有 Amazon EC2 实例的 Linux 和 Windows 节点

 **适用于**：公有子网和私有子网

每个 Amazon EC2 实例支持最大数量的弹性网络接口以及可分配给每个网络接口的最大数量的 IP 地址。每个节点的每个网络接口都需要一个 IP 地址。可以将所有其他可用 IP 地址分配给 `Pods`。每个都 `Pod` 需要自己的 IP 地址。因此，您的节点可能有可用的计算和内存资源，但无法容纳其它 `Pods`，因为该节点已用完分配给 `Pods` 的 IP 地址。

您可以通过分配 IP 前缀而不是为节点分配单个辅助 IP 地址来显著增加节点可以分配给 `Pods` 的 IP 地址数量。每个前缀都包含多个 IP 地址。如果没有为集群配置 IP 前缀分配，则集群必须进行更多 Amazon EC2 应用程序编程接口（API）调用才能配置容器组（pod）连接所需的网络接口和 IP 地址。随着集群规模的扩大，这些 API 调用的频率可能会导致容器组（pod）和实例启动时间延长。这会导致扩展延迟以满足大型和尖峰工作负载的需求，并增加成本和管理开销，因为您需要配置额外的集群和 VPC 来满足扩展需求。有关更多信息，请参阅 GitHub 上的[Kubernetes 可扩展性阈值](https://github.com/kubernetes/community/blob/master/sig-scalability/configs-and-limits/thresholds.md)。

## 与适用于 Kubernetes 的 Amazon VPC CNI 插件功能的兼容性
<a name="cni-increase-ip-addresses-compatability"></a>

可以将 IP 前缀用于以下功能：
+ IPv4 源网络地址转换 - 有关更多信息，请参阅 [为容器组（pod）启用出站互联网访问权限](external-snat.md)。
+ 集群、容器组（pod）和服务的 IPv6 地址 - 有关更多信息，请参阅 [了解如何将 IPv6 地址分配给集群、容器组（pod）和服务](cni-ipv6.md)。
+ 使用 Kubernetes 网络策略限制流量 – 有关更多信息，请参阅[通过 Kubernetes 网络策略限制容器组（pod）流量](cni-network-policy.md)。

以下列表提供了适用的 Amazon VPC CNI 插件设置的相关信息。有关各项设置的更多信息，请参阅 GitHub 上的 [amazon-vpc-cni-k8s](https://github.com/aws/amazon-vpc-cni-k8s/blob/master/README.md)。
+  `WARM_IP_TARGET` 
+  `MINIMUM_IP_TARGET` 
+  `WARM_PREFIX_TARGET` 

## 注意事项
<a name="cni-increase-ip-addresses-considerations"></a>

在使用此功能时，请考虑以下几点：
+ 每种 Amazon EC2 实例类型支持最大数量的容器组（pod）。如果托管节点组由多种实例类型组成，则集群中某个实例的最大容器组（pod）数量的最小值将应用于集群中的所有节点。
+ 默认情况下，可以在节点上运行的最大 `Pods` 数量为 110，但您可以更改该数字。如果您更改该数量并且有现有的托管节点组，则节点组的下一次 AMI 或启动模板更新会导致新节点出现时使用更改后的值。
+ 从分配 IP 地址过渡到分配 IP 前缀时，建议您创建新的节点组以增加可用 IP 地址的数量，而不是滚动替换现有节点。在同时分配 IP 地址和前缀的节点上运行容器组（pod）可能会导致通告的 IP 地址容量不一致，从而影响节点上未来的工作负载。有关执行过渡的建议方法，请参阅《Amazon EKS Best Practices Guide》**中的 [Prefix Delegation mode for Linux](https://docs.aws.amazon.com/eks/latest/best-practices/prefix-mode-linux.html)。
+ 安全组范围在节点级别 - 有关更多信息，请参阅[安全组](https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html)。
+ 分配给网络接口的 IP 前缀支持在每个节点上运行更高密度的容器组（pod），并且实现最短的启动时间。
+ IP 前缀和 IP 地址与标准 Amazon EC2 弹性网络接口相关联。需要特定安全组的容器组被分配给分支网络接口的主 IP 地址。您可以将获取 IP 地址或从 IP 前缀获取 IP 地址的容器组（pod）与在同一节点上获取分支网络接口的容器组（pod）混合使用。
+ 仅适用于具有 Linux 节点的集群。
  + 将附加组件配置为向网络接口分配前缀后，将无法在不删除集群所有节点组中的所有节点的情况下将适用于 Kubernetes 附加组件的 Amazon VPC CNI 插件降级到 `1.9.0`（或 `1.10.1`）以下版本。
  + 如果容器组（pod）在与 VPC 外部的端点通信的同时使用了容器组（pod）的安全组（`POD_SECURITY_GROUP_ENFORCING_MODE`=`standard` 和 `AWS_VPC_K8S_CNI_EXTERNALSNAT`=`false`），则使用节点的安全组，而不是分配给容器组（pod）的任何安全组。

    如果您的 `Pods` 在与 VPC 外部的端点通信的同时使用了[容器组（pod）的安全组](security-groups-for-pods.md)（`POD_SECURITY_GROUP_ENFORCING_MODE`=`strict`），则使用 `Pod’s` 安全组。

# 增加 Amazon EKS 节点的可用 IP 地址
<a name="cni-increase-ip-addresses-procedure"></a>

您可以通过分配 IP 前缀而不是为节点分配单个辅助 IP 地址，来增加节点可以分配给容器组（pod）的 IP 地址数量。

## 先决条件
<a name="_prerequisites"></a>
+ 您需要现有集群。要部署一个角色，请参阅[创建一个 Amazon EKS 集群。](create-cluster.md)。
+ 您的 Amazon EKS 节点所在的子网必须有足够的连续 `/28`（适用于 `IPv4` 集群）或 `/80`（适用于 `IPv6` 集群）无类别域间路由 (CIDR) 块。`IPv6` 集群中只能有 Linux 节点。如果 IP 地址分散在整个子网 CIDR 中，则使用 IP 前缀可能会失败。我们建议执行下列操作：
  + 使用子网 CIDR 预留，这样即使保留范围内的任何 IP 地址仍在使用，在其释放后，这些 IP 地址也不会重新分配。这样可以确保前缀在不分段的情况下进行分配。
  + 使用专门用于运行分配 IP 前缀的工作负载的新子网。分配 IP 前缀时，Windows 和 Linux工作负载可以在同一个子网中运行。
+ 要为节点分配 IP 前缀，您的节点必须基于 AWS Nitro。不基于 Nitro 的实例会继续分配单个辅助 IP 地址，但分配给容器组（pod）的 IP 地址数量比基于 Nitro 的实例少得多。
+  **仅适用于具有 Linux 节点的集群** – 如果集群针对 `IPv4` 系列配置，则必须安装适用于 Kubernetes 附加组件的 Amazon VPC CNI 插件的版本 `1.9.0` 或更高版本。您可以使用以下命令检查当前版本。

  ```
  kubectl describe daemonset aws-node --namespace kube-system | grep Image | cut -d "/" -f 2
  ```

  如果您的集群是针对 `IPv6` 系列配置的，则必须安装附加组件的 `1.10.1` 版。如果您的插件版本低于所需版本，则必须进行更新。要了解更多信息，请参阅[向具有 Amazon VPC CNI 的容器组（pod）分配 IP](managing-vpc-cni.md) 的更新部分。
+  **仅适用于具有 Windows 节点的集群** 
  + 必须为集群启用 Windows 支持。有关更多信息，请参阅 [在 EKS 集群上部署 Windows 节点](windows-support.md)。

## 将 IP 地址前缀分配给节点
<a name="cni-increase-ip-procedure"></a>

配置集群以将 IP 地址前缀分配给节点。完成与节点的操作系统相匹配的步骤。

### Linux
<a name="_linux"></a>

1. 启用参数，以便为 Amazon VPC CNI DaemonSet 的网络接口分配前缀。部署集群时，版本 `1.10.1` 或更高版本的适用于 Kubernetes 附加组件的 Amazon VPC CNI 插件随之部署。如果您使用 `IPv6` 系列创建集群，这个设置将被默认设置为 `true`。如果您使用 `IPv4` 系列创建集群，这个设置将被默认设置为 `false`。

   ```
   kubectl set env daemonset aws-node -n kube-system ENABLE_PREFIX_DELEGATION=true
   ```
**重要**  
即使子网有可用的 IP 地址，如果子网没有任何连续 `/28` 数据块可用，您还是会在适用于 Kubernetes 的 Amazon VPC CNI 插件日志中看到以下错误。  

   ```
   InsufficientCidrBlocks: The specified subnet does not have enough free cidr blocks to satisfy the request
   ```
发生这种情况的原因可能是分散在子网中的现有辅助 IP 地址的碎片。要解决此错误，请创建一个新子网并在其中启动容器组（pod），或者使用 Amazon EC2 子网 CIDR 预留，在子网中预留空间以便与前缀分配结合使用。有关更多信息，请参阅《Amazon VPC 用户指南》中的[子网 CIDR 预留](https://docs.aws.amazon.com/vpc/latest/userguide/subnet-cidr-reservation.html)。

1. 如果计划在没有启动模板的情况下部署托管节点组，或者采用尚未在其中指定 AMI ID 的启动模板，并且使用的是在先决条件中列出的适用于 Kubernetes 的 Amazon VPC CNI 插件版本或更高版本，则跳至下一步。托管节点组会自动为您计算最大容器组（pod）数量。

   如果正在部署自主管理型节点组或带有启动模板的托管节点组，且其启动模板已指定 AMI ID，则必须确定 Amazon EKS 为节点推荐的最大容器组（pod）数量。按照 中的说明进行操作，将 `--cni-prefix-delegation-enabled` 添加到步骤 3。请记下输出的内容，以便在下一个步骤中使用。
**重要**  
托管节点组强制执行 `maxPods` 的值的最大数量。对于 vCPUs 少于 30 个的实例，最大数量为 110，对于所有其他实例，最大数量为 250。无论是否启用前缀委派，均应用此最大数量。

1. 如果使用为 `IPv6` 配置的集群，则跳至下一步。

   在以下选项中指定参数。要确定哪个选项适合您以及为其提供哪些值，请参阅 GitHub 上的 [WARM\$1PREFIX\$1TARGET, WARM\$1IP\$1TARGET, and MINIMUM\$1IP\$1TARGET](https://github.com/aws/amazon-vpc-cni-k8s/blob/master/docs/prefix-and-ip-target.md)。

   您可以将示例值替换为大于零的值。
   +  `WARM_PREFIX_TARGET` 

     ```
     kubectl set env ds aws-node -n kube-system WARM_PREFIX_TARGET=1
     ```
   +  `WARM_IP_TARGET` 或 `MINIMUM_IP_TARGET`：如果设置了两种值之一，则其会覆盖所设置的 `WARM_PREFIX_TARGET` 的值。

     ```
     kubectl set env ds aws-node -n kube-system WARM_IP_TARGET=5
     ```

     ```
     kubectl set env ds aws-node -n kube-system MINIMUM_IP_TARGET=2
     ```

1. 使用至少一种 Amazon EC2 Nitro Amazon Linux 2023 实例类型创建以下类型之一的节点组。有关 Nitro 实例类型的列表，请参阅《Amazon EC2 用户指南》中的[基于 Nitro 系统构建的实例](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instance-types.html#ec2-nitro-instances)。Windows 中不支持此功能。对于包含 *110* 的选项，将其替换为第 3 步中的值（建议）或您自己的值。
   +  **自行管理** – 按照[创建自行管理的 Amazon Linux 节点](launch-workers.md)中的说明部署节点组。在创建 CloudFormation 堆栈之前，请打开模板文件并将 `NodeLaunchTemplate` 中的 `UserData` 调整为如下所示

     ```
     ...
                 apiVersion: node.eks.aws/v1alpha1
                 kind: NodeConfig
                 spec:
                   cluster:
                     name: ${ClusterName}
                     apiServerEndpoint: ${ApiServerEndpoint}
                     certificateAuthority: ${CertificateAuthorityData}
                     cidr: ${ServiceCidr}
                   kubelet:
                     config:
                       maxPods: 110
     ...
     ```

     如果使用 `eksctl` 创建节点组，可以使用下面的命令。

     ```
     eksctl create nodegroup --cluster my-cluster --managed=false --max-pods-per-node 110
     ```
   +  **托管**：使用以下选项之一部署您的节点组：
     +  **没有启动模板或者没有指定 AMI ID 的启动模板**：完成[为集群创建托管式节点组](create-managed-node-group.md)中的过程。托管节点组会自动为您计算 Amazon EKS 建议的 `max-pods` 值。
     +  **使用具有指定 AMI ID 的启动模板**：在启动模板中，指定 Amazon EKS 优化的 AMI ID，或者指定基于 Amazon EKS 优化 AMI 构建的自定义 AMI，然后[使用启动模板部署节点组](launch-templates.md)并在启动模板中提供以下用户数据。此用户数据传递一个 `NodeConfig` 对象，供 `nodeadm` 工具在节点上读取。有关 `nodeadm` 的详细信息，请参阅 [nodeadm 文档](https://awslabs.github.io/amazon-eks-ami/nodeadm)。

       ```
       MIME-Version: 1.0
       Content-Type: multipart/mixed; boundary="//"
       
       --//
       Content-Type: application/node.eks.aws
       
       ---
       apiVersion: node.eks.aws/v1alpha1
       kind: NodeConfig
       spec:
        cluster:
          apiServerEndpoint: [.replaceable]`my-cluster`
          certificateAuthority: [.replaceable]`LS0t...`
          cidr: [.replaceable]`10.100.0.0/16`
          name: [.replaceable]`my-cluster
        kubelet:
          config:
            maxPods: [.replaceable]`110`
       --//--
       ```

       如果使用 `eksctl` 创建节点组，可以使用下面的命令。

       ```
       eksctl create nodegroup --cluster my-cluster --max-pods-per-node 110
       ```

       如果您创建的自定义 AMI 不是基于 Amazon EKS 优化版 AMI 构建的，则需要自行自定义创建配置。
**注意**  
如果还想将 IP 地址分配给不同于实例子网的容器组（pod），则需要在此步骤中启用该功能。有关更多信息，请参阅 [使用自定义网络在备用子网中部署容器组（pod）](cni-custom-network.md)。

### Windows
<a name="_windows"></a>

1. 启用 IP 前缀的分配。

   1. 打开 `amazon-vpc-cni` `ConfigMap` 进行编辑。

      ```
      kubectl edit configmap -n kube-system amazon-vpc-cni -o yaml
      ```

   1. 将以下行添加到 `data` 部分。

      ```
        enable-windows-prefix-delegation: "true"
      ```

   1. 保存文件，然后关闭编辑器。

   1. 确认该行已添加到 `ConfigMap`。

      ```
      kubectl get configmap -n kube-system amazon-vpc-cni -o "jsonpath={.data.enable-windows-prefix-delegation}"
      ```

      如果返回的输出并非 `true`，则可能存在错误。尝试再次完成该步骤。
**重要**  
即使子网有可用的 IP 地址，如果子网没有任何连续 `/28` 数据块可用，您还是会在适用于 Kubernetes 的 Amazon VPC CNI 插件日志中看到以下错误。  

      ```
      InsufficientCidrBlocks: The specified subnet does not have enough free cidr blocks to satisfy the request
      ```
发生这种情况的原因可能是分散在子网中的现有辅助 IP 地址的碎片。要解决此错误，请创建一个新子网并在其中启动容器组（pod），或者使用 Amazon EC2 子网 CIDR 预留，在子网中预留空间以便与前缀分配结合使用。有关更多信息，请参阅《Amazon VPC 用户指南》中的[子网 CIDR 预留](https://docs.aws.amazon.com/vpc/latest/userguide/subnet-cidr-reservation.html)。

1. （可选）指定其他配置以控制集群的预扩展和动态扩展行为。有关更多信息，请参阅 GitHub 上的[在 Windows 上使用前缀委派模式的配置选项](https://github.com/aws/amazon-vpc-resource-controller-k8s/blob/master/docs/windows/prefix_delegation_config_options.md)。

   1. 打开 `amazon-vpc-cni` `ConfigMap` 进行编辑。

      ```
      kubectl edit configmap -n kube-system amazon-vpc-cni -o yaml
      ```

   1. 用大于零的值替换示例值，然后将所需的条目添加到 `ConfigMap` 的 `data` 部分。如果您为 `warm-ip-target` 或 `minimum-ip-target` 设置了值，则该值将覆盖为 `warm-prefix-target` 设置的任何值。

      ```
        warm-prefix-target: "1"
        warm-ip-target: "5"
        minimum-ip-target: "2"
      ```

   1. 保存文件，然后关闭编辑器。

1. 创建至少包含一种 Amazon EC2 Nitro 实例类型的 Windows 节点组。有关 Nitro 实例类型的列表，请参阅《Amazon EC2 用户指南》中的[基于 Nitro 系统构建的实例](https://docs.aws.amazon.com/AWSEC2/latest/WindowsGuide/instance-types.html#ec2-nitro-instances)。默认情况下，可以部署到节点的最大容器组（pod）数量为 110。如果要增加或减少该数量，则请在引导配置的用户数据中指定以下内容。将 *max-pods-quantity* 替换为最大容器组（pod）值。

   ```
   -KubeletExtraArgs '--max-pods=max-pods-quantity'
   ```

   如果您要部署托管节点组，则需要在启动模板中添加此配置。有关更多信息，请参阅 [使用启动模板自定义托管式节点](launch-templates.md)。有关 Windows 引导脚本配置参数的更多信息，请参阅[引导脚本配置参数](eks-optimized-windows-ami.md#bootstrap-script-configuration-parameters)。

## 确定最大容器组（pod）数量和可用的 IP 地址
<a name="cni-increase-ip-verify"></a>

1. 节点部署完成后，请查看集群中的节点。

   ```
   kubectl get nodes
   ```

   示例输出如下。

   ```
   NAME                                             STATUS     ROLES    AGE   VERSION
   ip-192-168-22-103.region-code.compute.internal   Ready      <none>   19m   v1.XX.X-eks-6b7464
   ip-192-168-97-94.region-code.compute.internal    Ready      <none>   19m   v1.XX.X-eks-6b7464
   ```

1. 描述其中一个节点以确定该节点的 `max-pods` 值和可用 IP 地址数量。将 *192.168.30.193* 替换为之前输出中返回的其中一个节点名称中的 `IPv4` 地址。

   ```
   kubectl describe node ip-192-168-30-193.region-code.compute.internal | grep 'pods\|PrivateIPv4Address'
   ```

   示例输出如下。

   ```
   pods:                                  110
   vpc.amazonaws.com/PrivateIPv4Address:  144
   ```

   在之前的输出中，尽管有 *144* 个 IP 地址可用，但 `110` 是 Kubernetes 将部署到节点的最大容器组（pod）数量。

# 将安全组分配给各个容器组（pod）
<a name="security-groups-for-pods"></a>

 **适用于**：带有 Amazon EC2 实例的 Linux 节点

 **适用于**：私有子网

容器组（pod）的安全组将 Amazon EC2 安全组与 Kubernetes Pod 集成在一起。您可以使用 Amazon EC2 安全组定义允许流向和来自于容器组（pod）的入站和出站网络流量的规则，而这些容器组（pod）将部署到在许多 Amazon EC2 实例类型和 Fargate 上运行的节点。有关此功能的详细说明，请参阅[容器组（pod）的安全组介绍](https://aws.amazon.com/blogs/containers/introducing-security-groups-for-pods)博客文章。

## 与适用于 Kubernetes 的 Amazon VPC CNI 插件功能的兼容性
<a name="security-groups-for-pods-compatability"></a>

您可以将容器组（pod）的安全组与以下功能结合使用：
+ IPv4 源网络地址转换 - 有关更多信息，请参阅 [为容器组（pod）启用出站互联网访问权限](external-snat.md)。
+ 集群、容器组（pod）和服务的 IPv6 地址 - 有关更多信息，请参阅 [了解如何将 IPv6 地址分配给集群、容器组（pod）和服务](cni-ipv6.md)。
+ 使用 Kubernetes 网络策略限制流量 – 有关更多信息，请参阅[通过 Kubernetes 网络策略限制容器组（pod）流量](cni-network-policy.md)。

## 注意事项
<a name="sg-pods-considerations"></a>

在部署容器组（pod）的安全组之前，请考虑以下限制和条件：
+ 容器组（pod）的安全组不能与 Windows 节点或 EKS 自动模式一起使用。
+ 通过使用版本 1.16.0 或更高版本的 Amazon VPC CNI 插件，容器组（pod）的安全组可以与为包含 Amazon EC2 节点的 `IPv6` 系列配置的集群一起使用。通过使用版本 1.7.7 或更高版本的 Amazon VPC CNI 插件，容器组（pod）的安全组可以与为仅包含 Fargate 节点的 `IPv6` 系列配置的集群一起使用。有关更多信息，请参阅 [了解如何将 IPv6 地址分配给集群、容器组（pod）和服务](cni-ipv6.md)。
+ 大多数[基于 Nitro](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/instance-types.html#ec2-nitro-instances) 的 Amazon EC2 实例系列都支持容器组（pod）的安全组，但并非所有实例代的系列都支持安全组。例如，支持 `m5`、`c5`、`r5`、`m6g`、`c6g` 与 `r6g` 实例系列和实例代。但不支持 `t` 系列中的实例类型。有关支持的实例类型的完整列表，请参阅 GitHub 上的 [limits.go](https://github.com/aws/amazon-vpc-resource-controller-k8s/blob/v1.5.0/pkg/aws/vpc/limits.go) 文件。您的节点必须是在该文件中拥有 `IsTrunkingCompatible: true` 的所列出的实例类型之一。
+ 如果要将自定义联网和容器组（pod）的安全组一起使用，则请使用容器组（pod）的安全组所指定的安全组，不要使用 `ENIConfig` 中指定的安全组。
+ 如果您使用的是版本 `1.10.2` 或更低版本的 Amazon VPC CNI 插件，并且将 `terminationGracePeriodSeconds` 设置包括在您的容器组（pod）规范中，该设置的值不能为零。
+ 如果您使用的是版本 `1.10` 或更低版本的 Amazon VPC CNI 插件或 `POD_SECURITY_GROUP_ENFORCING_MODE`=`strict` 的版本 `1.11`（默认设置），则您向其分配安全组的容器组（pod）将不支持使用实例目标（`externalTrafficPolicy` 设置为 `Local`）的 `NodePort` 和 `LoadBalancer` 型 Kubernetes 服务。有关将负载均衡器与实例目标一起使用的更多信息，请参阅 [使用网络负载均衡器路由 TCP 和 UDP 流量](network-load-balancing.md)。
+ 如果您使用的是版本 `1.10` 或更低版本的 Amazon VPC CNI 插件或 `POD_SECURITY_GROUP_ENFORCING_MODE`=`strict` 的版本 `1.11`（默认设置），对于来自分配有安全组的容器组（pod）的出站流量，禁用源 NAT，以便应用出站安全组规则。要访问 Internet，必须在配置了 NAT 网关或实例的私有子网中部署的节点上启动具有已分配安全组的容器组（pod）。部署到公有子网的已分配安全组的 Pod 无法访问 Internet。

  如果您使用的是 `POD_SECURITY_GROUP_ENFORCING_MODE`=`standard` 的版本 `1.11` 或者更高版本的插件，则发往 VPC 之外的容器组（pod）流量将转换为实例主网络接口的 IP 地址。对于此流量，将使用主网络接口的安全组中的规则，而不是容器组（pod）安全组中的规则。
+ 要将 Calico 网络策略用于具有关联安全组的容器组（pod），您必须使用版本 `POD_SECURITY_GROUP_ENFORCING_MODE` 或更高版本的 Amazon VPC CNI 插件并设置 `1.11.0`=`standard`。否则，流向和来自具有关联安全组的容器组（pod）的流量不受 Calico 网络策略执行的限制，并且仅受限于 Amazon EC2 安全组执行。要更新 Amazon VPC CNI 版本，请参阅 [使用 Amazon VPC CNI 将 IP 分配给容器组（pod）](managing-vpc-cni.md) 
+ 在使用集群中的安全组的 Amazon EC2 节点上运行且使用 [NodeLocal DNSCache](https://kubernetes.io/docs/tasks/administer-cluster/nodelocaldns/) 的容器组（pod）仅支持版本 `1.11.0` 或更高版本的 Amazon VPC CNI 插件和 `POD_SECURITY_GROUP_ENFORCING_MODE`=`standard`。要更新 Amazon VPC CNI 插件版本，请参阅 [使用 Amazon VPC CNI 将 IP 分配给容器组（pod）](managing-vpc-cni.md) 
+ 对于具有高流失率的容器组（pod）而言，容器组（pod）的安全组可能会导致更高的容器组（pod）启动延迟。这是由于资源控制器中的速率限制造成的。
+ EC2 安全组范围处于容器组（pod）级别。有关更多信息，请参阅[安全组](https://docs.aws.amazon.com/vpc/latest/userguide/VPC_SecurityGroups.html)。

  如果您设置了 `POD_SECURITY_GROUP_ENFORCING_MODE=standard` 和 `AWS_VPC_K8S_CNI_EXTERNALSNAT=false`，则发往 VPC 外部端点的流量使用节点的安全组，而不是容器组（pod）的安全组。

# 为 Amazon EKS 容器组（pod）的安全组配置适用于 Kubernetes 的 Amazon VPC CNI 插件
<a name="security-groups-pods-deployment"></a>

如果将容器组（pod）用于 Amazon EC2 实例，则需要为安全组配置适用于 Kubernetes 的 Amazon VPC CNI 插件

如果仅使用 Fargate 容器组（pod），但集群中没有任何 Amazon EC2 节点，则请参阅[对 Amazon EKS 容器组（pod）使用安全组策略](sg-pods-example-deployment.md)。

1. 使用以下命令查看当前适用于 Kubernetes 的 Amazon VPC CNI 插件版本：

   ```
   kubectl describe daemonset aws-node --namespace kube-system | grep amazon-k8s-cni: | cut -d : -f 3
   ```

   示例输出如下。

   ```
   v1.7.6
   ```

   如果适用于 Kubernetes 的 Amazon VPC CNI 插件版本低于 `1.7.7`，请将该插件更新到版本 `1.7.7` 或更高版本。有关更多信息，请参阅 [使用 Amazon VPC CNI 将 IP 分配给容器组（pod）](managing-vpc-cni.md)。

1. 将 [AmazonEKSVPCResourceController](https://console.aws.amazon.com/iam/home#/policies/arn:aws:iam::aws:policy/AmazonEKSVPCResourceController) 托管 IAM 策略添加到与您的 Amazon EKS 集群关联的[集群角色](cluster-iam-role.md#create-service-role)。策略允许角色管理网络接口、网络接口的私有 IP 地址以及与网络实例之间的连接和分离。

   1. 检索您的集群 IAM 角色的名称，然后将其存储在一个变量中。将 *my-cluster* 替换为您的集群的名称。

      ```
      cluster_role=$(aws eks describe-cluster --name my-cluster --query cluster.roleArn --output text | cut -d / -f 2)
      ```

   1. 将 策略附加到该角色。

      ```
      aws iam attach-role-policy --policy-arn arn:aws:iam::aws:policy/AmazonEKSVPCResourceController --role-name $cluster_role
      ```

1. 通过在 `aws-node` DaemonSet 中将 `ENABLE_POD_ENI` 变量设置为 `true`，启用 Amazon VPC CNI 附加组件来管理容器组（pod）的网络接口。此设置一旦设置为 `true` 后，插件会为集群中的每个节点创建一个 `cninode` 自定义资源。VPC 资源控制器会创建并附加一个带有 `aws-k8s-trunk-eni` 描述且名为*中继网络接口*的特殊网络接口。

   ```
   kubectl set env daemonset aws-node -n kube-system ENABLE_POD_ENI=true
   ```
**注意**  
中继网络接口包含在实例类型支持的最大网络接口数中。有关每种实例类型支持的最大网络接口数的列表，请参阅 *Amazon EC2 用户指南*中的[每种实例类型的每个网络接口的 IP 地址数](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-eni.html#AvailableIpPerENI)。如果您的节点已经附加了最大数量的标准网络接口，则 VPC 资源控制器将预订一个空间。您必须缩减正在运行的容器组（pod），以便控制器足以分离和删除标准网络接口、创建中继网络接口并将其附加到实例。

1. 您可以使用以下命令查看哪些节点具有 `CNINode` 自定义资源。如果返回 `No resources found`，则等几秒钟后重试。上一步需要重新启动适用于 Kubernetes 容器组（pod）的 Amazon VPC CNI 插件，这需要几秒钟的时间。

   ```
   kubectl get cninode -A
        NAME FEATURES
        ip-192-168-64-141.us-west-2.compute.internal [{"name":"SecurityGroupsForPods"}]
        ip-192-168-7-203.us-west-2.compute.internal [{"name":"SecurityGroupsForPods"}]
   ```

   如果您使用的是早于 `1.15` 的 VPC CNI 版本，则使用节点标签代替 `CNINode` 自定义资源。您可以使用以下命令查看哪些节点的节点标签 `aws-k8s-trunk-eni` 设置为 `true`。如果返回 `No resources found`，则等几秒钟后重试。上一步需要重新启动适用于 Kubernetes 容器组（pod）的 Amazon VPC CNI 插件，这需要几秒钟的时间。

   ```
   kubectl get nodes -o wide -l vpc.amazonaws.com/has-trunk-attached=true
   ```

   创建中继网络接口后，可以从中继或标准网络接口为容器组（pod）分配辅助 IP 地址。如果节点被删除，中继接口将自动删除。

   当您在后面的步骤中部署容器组（pod）的安全组时，VPC 资源控制器会创建一个具有 `aws-k8s-branch-eni` 描述的名为*分支网络接口*的特殊网络接口，并将安全组与其关联。除了附加到节点的标准网络接口和中继网络接口之外，还会创建分支网络接口。

   如果您使用的是存活探测器或就绪探测器，则您还需要禁用 *TCP 早期解复用器*，以便 `kubelet` 可以使用 TCP 连接到分支网络接口上的容器组（pod）。要禁用 *TCP 早期解复用器*，请运行以下命令：

   ```
   kubectl patch daemonset aws-node -n kube-system \
     -p '{"spec": {"template": {"spec": {"initContainers": [{"env":[{"name":"DISABLE_TCP_EARLY_DEMUX","value":"true"}],"name":"aws-vpc-cni-init"}]}}}}'
   ```
**注意**  
如果您使用的是 `1.11.0` 或更高版本的适用于 Kubernetes 附加组件的 Amazon VPC CNI 插件并设置 `POD_SECURITY_GROUP_ENFORCING_MODE`=`standard`，如下一步所述，则您就不需要运行上一个命令。

1. 如果您的集群使用 `NodeLocal DNSCache`，或者您想将 Calico 网络策略与拥有自己的安全组的容器组（pod）结合使用，或者您有 `NodePort` 和 `LoadBalancer` 类型的 Kubernetes 服务，这些服务将实例目标（`externalTrafficPolicy` 设置为 `Local`）用于您向其分配安全组的容器组（pod），则您必须使用版本 `1.11.0` 或更高版本的适用于 Kubernetes 附加组件的 Amazon VPC CNI 插件，并且必须启用以下设置：

   ```
   kubectl set env daemonset aws-node -n kube-system POD_SECURITY_GROUP_ENFORCING_MODE=standard
   ```

   重要提示：**容器组（pod）安全组规则不适用于位于相同节点上的容器组（pod）之间或介于容器组（pod）和服务之间的流量，例如 `kubelet` 或 `nodeLocalDNS`。在同一节点上使用不同安全组的容器组（pod）无法通信，因为它们配置在不同的子网中，且这些子网之间的路由被禁用。**从容器组（pod）到 VPC 以外的地址的出站流量是转换为实例的主网络接口的 IP 地址的网络地址（除非您还设置了 `AWS_VPC_K8S_CNI_EXTERNALSNAT=true`）。对于此流量，将使用主网络接口的安全组中的规则，而不是容器组（pod）安全组中的规则。\$1\$1要将此设置应用于现有容器组（pod），必须重新启动容器组（pod）或其上运行着容器组（pod）的节点。

1. 要了解如何为容器组（pod）使用安全组策略，请参阅[对 Amazon EKS 容器组（pod）使用安全组策略](sg-pods-example-deployment.md)。

# 对 Amazon EKS 容器组（pod）使用安全组策略
<a name="sg-pods-example-deployment"></a>

要使用容器组（pod）的安全组，您必须拥有现有的安全组。以下步骤展示了如何将安全组策略用于容器组（pod）。除非另有说明，请从同一个终端完成所有步骤，因为以下步骤中使用的变量不会在终端之间持续存在。

如果您具有带 Amazon EC2 实例的容器组（pod），则必须在使用此过程之前配置插件。有关更多信息，请参阅 [为 Amazon EKS 容器组（pod）的安全组配置适用于 Kubernetes 的 Amazon VPC CNI 插件](security-groups-pods-deployment.md)。

1. 创建要将资源部署到的 Kubernetes 命名空间。您可以将 *my-namespace* 替换为您要使用的命名空间名称。

   ```
   kubectl create namespace my-namespace
   ```

1.  将 Amazon EKS `SecurityGroupPolicy` 部署到您的集群。

   1. 将以下内容复制到您的设备。如果您宁愿根据服务账户标签选择容器组（pod），则可以将 *podSelector* 替换为 `serviceAccountSelector`。您必须指定一个或其他选择器。空的 `podSelector`（示例：`podSelector: {}`）会选择命名空间中的所有容器组（pod）。您可以将 *my-role* 更改为您的角色名称。空的 `serviceAccountSelector` 会选择命名空间中的所有服务账户。您可以将 *my-security-group-policy* 替换为 `SecurityGroupPolicy` 的名称，并将 *my-namespace* 替换为要在其中创建 `SecurityGroupPolicy` 的命名空间。

      您必须将 *my\$1pod\$1security\$1group\$1id* 替换为现有安全组的 ID。如果您没有现有安全组，则必须创建一个安全组。有关更多信息，请参阅《Amazon EC2 用户指南》[https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/)中的[适用于 Linux 实例的 Amazon EC2 安全组](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/ec2-security-groups.html)。您可以指定 1-5 个安全组 ID。如果指定了多个 ID，则所有安全组中的所有规则的组合都会对选定的容器组（pod）生效。

      ```
      cat >my-security-group-policy.yaml <<EOF
      apiVersion: vpcresources.k8s.aws/v1beta1
      kind: SecurityGroupPolicy
      metadata:
        name: my-security-group-policy
        namespace: my-namespace
      spec:
        podSelector:
          matchLabels:
            role: my-role
        securityGroups:
          groupIds:
            - my_pod_security_group_id
      EOF
      ```
**重要**  
您为容器组（pod）指定的一个或多个安全组必须符合以下标准：  
它们必须存在。如果它们不存在，当您部署与选择器匹配的容器组（pod）时，该容器组（pod）会在创建过程中处于卡住状态。如果您描述容器组（pod），则会看到类似于以下内容的错误消息：`An error occurred (InvalidSecurityGroupID.NotFound) when calling the CreateNetworkInterface operation: The securityGroup ID 'sg-05b1d815d1EXAMPLE' does not exist`。
这些安全组必须允许通过您为其配置探测器的任何端口，从应用于您节点的安全组（对于 `kubelet`）进行入站通信。
这些安全组必须允许通过 `TCP` 和 `UDP` 端口 53 与分配到运行 CoreDNS 的容器组（pod）（或其上会运行容器组的节点）的安全组进行出站通信。适用于您的 CoreDNS 容器组（pod）的安全组必须允许来自您指定的安全组的入站 `TCP` 和 `UDP` 端口 53 流量。
它们必须具备必要的入站和出站规则，才能与它们需要与其通信的其他容器组（pod）进行通信。
如果您将安全组与 Fargate 一起使用，它们必须具有允许容器组（pod）与 Kubernetes 控制面板通信的规则。执行此操作的最简单方法是将集群安全组指定为安全组之一。
安全组策略仅适用于新调度的容器组（pod），不会影响正在运行的容器组（pod）。

   1. 部署策略。

      ```
      kubectl apply -f my-security-group-policy.yaml
      ```

1. 部署其标签与上一步中指定的 *podSelector* 的 *my-role* 值相匹配的示例应用程序。

   1. 将以下内容复制到您的设备。将示例值替换为您自己的值，然后运行修改后的命令。如果您替换 *my-role*，请确保它与上一步中为选择器指定的值相同。

      ```
      cat >sample-application.yaml <<EOF
      apiVersion: apps/v1
      kind: Deployment
      metadata:
        name: my-deployment
        namespace: my-namespace
        labels:
          app: my-app
      spec:
        replicas: 4
        selector:
          matchLabels:
            app: my-app
        template:
          metadata:
            labels:
              app: my-app
              role: my-role
          spec:
            terminationGracePeriodSeconds: 120
            containers:
            - name: nginx
              image: public.ecr.aws/nginx/nginx:1.23
              ports:
              - containerPort: 80
      ---
      apiVersion: v1
      kind: Service
      metadata:
        name: my-app
        namespace: my-namespace
        labels:
          app: my-app
      spec:
        selector:
          app: my-app
        ports:
          - protocol: TCP
            port: 80
            targetPort: 80
      EOF
      ```

   1. 使用以下命令部署应用程序。当您部署应用程序时，适用于 Kubernetes 的 Amazon VPC CNI 插件将匹配 `role` 标签，并且您在上一步中指定的安全组将应用到容器组（pod）。

      ```
      kubectl apply -f sample-application.yaml
      ```

1. 查看使用示例应用程序部署的容器组（pod）。对于本主题的其余部分，此终端称为 `TerminalA`。

   ```
   kubectl get pods -n my-namespace -o wide
   ```

   示例输出如下。

   ```
   NAME                             READY   STATUS    RESTARTS   AGE     IP               NODE                                            NOMINATED NODE   READINESS GATES
   my-deployment-5df6f7687b-4fbjm   1/1     Running   0          7m51s   192.168.53.48    ip-192-168-33-28.region-code.compute.internal   <none>           <none>
   my-deployment-5df6f7687b-j9fl4   1/1     Running   0          7m51s   192.168.70.145   ip-192-168-92-33.region-code.compute.internal   <none>           <none>
   my-deployment-5df6f7687b-rjxcz   1/1     Running   0          7m51s   192.168.73.207   ip-192-168-92-33.region-code.compute.internal   <none>           <none>
   my-deployment-5df6f7687b-zmb42   1/1     Running   0          7m51s   192.168.63.27    ip-192-168-33-28.region-code.compute.internal   <none>           <none>
   ```
**注意**  
如果容器组（pod）被卡住，请遵循以下提示。  
如果任何容器组（pod）卡在 `Waiting` 状态，则运行 `kubectl describe pod my-deployment-xxxxxxxxxx-xxxxx -n my-namespace `。如果您看到了 `Insufficient permissions: Unable to create Elastic Network Interface.`，请确认您已在上一步中将 IAM 策略添加到 IAM 集群角色。
如果任何容器组（pod）卡在 `Pending` 状态，请确认您的节点实例类型已在 [limits.go](https://github.com/aws/amazon-vpc-resource-controller-k8s/blob/master/pkg/aws/vpc/limits.go) 中列出，并且尚未达到实例类型支持的最大分支网络接口数与您的节点组中节点数的乘积。例如，`m5.large` 实例支持 9 个分支网络接口。如果节点组有 5 个节点，则最多可以为节点组创建 45 个分支网络接口。在删除另一个具有关联安全组的容器组（pod）前，您尝试部署的第 46 个容器组（pod）将会处于 `Pending` 状态。

   如果您运行 `kubectl describe pod my-deployment-xxxxxxxxxx-xxxxx -n my-namespace ` 并看到类似于以下消息内容的消息，则可以安全地忽略该消息。当适用于 Kubernetes 的 Amazon VPC CNI 插件尝试在创建网络接口时设置主机联网并失败时，可能会出现此消息。该插件会记录此事件，直到创建了网络接口为止。

   ```
   Failed to create Pod sandbox: rpc error: code = Unknown desc = failed to set up sandbox container "e24268322e55c8185721f52df6493684f6c2c3bf4fd59c9c121fd4cdc894579f" network for Pod "my-deployment-5df6f7687b-4fbjm": networkPlugin
   cni failed to set up Pod "my-deployment-5df6f7687b-4fbjm-c89wx_my-namespace" network: add cmd: failed to assign an IP address to container
   ```

   不能超过可在实例类型上运行的容器组（pod）的最大数量。有关可在每种实例类型上运行的容器组（pod）的最大数量的列表，请参阅 GitHub 上的 [eni-max-pods.txt](https://github.com/aws/amazon-vpc-cni-k8s/blob/master/misc/eni-max-pods.txt)。当您删除具有关联安全组的容器组（pod）或删除运行该容器组的节点时，VPC 资源控制器会删除分支网络接口。如果您使用适用于安全组的容器组（pod）删除带有容器组的集群，则该控制器不会删除分支网络接口，因此您需要自行删除这些接口。有关如何删除网络接口的信息，请参阅《Amazon EC2 用户指南》中的[删除网络接口](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-eni.html#delete_eni)。

1. 在单独的终端中，Shell 进入其中一个容器组（pod）。对于本主题的其余部分，此终端称为 `TerminalB`。请将 *5df6f7687b-4fbjm* 替换为您在上一步输出中返回的其中一个容器组（pod）的 ID。

   ```
   kubectl exec -it -n my-namespace my-deployment-5df6f7687b-4fbjm -- /bin/bash
   ```

1. 从 `TerminalB` 的 Shell 中，确认示例应用程序是否有效。

   ```
   curl my-app
   ```

   示例输出如下。

   ```
   <!DOCTYPE html>
   <html>
   <head>
   <title>Welcome to nginx!</title>
   [...]
   ```

   您收到了输出，因为运行该应用程序的所有容器组（pod）与您创建的安全组关联。该组包含一条规则，允许安全组所关联的所有容器组（pod）之间的所有流量。允许 DNS 流量从该安全组出站到与您的节点关联的集群安全组。节点正在运行 CoreDNS 容器组（pod），您的容器组对其进行了名称查找。

1. 从 `TerminalA` 中，删除允许从安全组与集群安全组进行 DNS 通信的安全组规则。如果您在上一步中没有将 DNS 规则添加到集群安全组中，请将 *\$1my\$1cluster\$1security\$1group\$1id* 替换为您在其中创建规则的安全组的 ID。

   ```
   aws ec2 revoke-security-group-ingress --group-id $my_cluster_security_group_id --security-group-rule-ids $my_tcp_rule_id
   aws ec2 revoke-security-group-ingress --group-id $my_cluster_security_group_id --security-group-rule-ids $my_udp_rule_id
   ```

1. 从 `TerminalB` 中，尝试再次访问该应用程序。

   ```
   curl my-app
   ```

   示例输出如下。

   ```
   curl: (6) Could not resolve host: my-app
   ```

   由于容器组（pod）不再能够访问具有与其关联的集群安全组的 CoreDNS 容器组，尝试失败。集群安全组不再具有安全组规则，该规则允许从与您的容器组（pod）关联的安全组进行 DNS 通信。

   如果您尝试使用上一步中的其中一个容器组（pod）返回的 IP 地址访问应用程序，您仍然会收到响应，因为在与安全组相关联的容器组之间允许所有端口，并且不需要名称查找。

1. 完成实验后，您可以移除您创建的示例安全组策略、应用程序和安全组。从 `TerminalA` 运行以下命令。

   ```
   kubectl delete namespace my-namespace
   aws ec2 revoke-security-group-ingress --group-id $my_pod_security_group_id --security-group-rule-ids $my_inbound_self_rule_id
   wait
   sleep 45s
   aws ec2 delete-security-group --group-id $my_pod_security_group_id
   ```

# 将多个网络接口连接到容器组（pod）
<a name="pod-multiple-network-interfaces"></a>

默认情况下，Amazon VPC CNI 插件为每个容器组（pod）分配一个 IP 地址。此 IP 地址连接到一个*弹性网络接口*，该接口负责处理容器组（pod）的所有传入和传出流量。要提高带宽和每秒数据包速率性能，您可以使用 VPC CNI 的*多 NIC 功能*配置多宿主容器组（pod）。多宿主容器组（pod）是使用多个网络接口（和多个 IP 地址）的单个 Kubernetes 容器组（pod）。通过运行多宿主容器组（pod），您可以使用并发连接将其应用程序流量分散到多个网络接口。这对于人工智能（AI）、机器学习（ML）和高性能计算（HPC）使用案例特别有用。

下图显示一个在使用多个网络接口卡（NIC）的 Worker 节点上运行的多宿主容器组（pod）。

![\[带有两个网络接口的多宿主容器组（pod），一个网络接口连接 ENA，一个网络接口连接 ENA 和 EFA\]](http://docs.aws.amazon.com/zh_cn/eks/latest/userguide/images/multi-homed-pod.png)


## 背景
<a name="pod-multi-nic-background"></a>

在 Amazon EC2 上，*弹性网络接口*是 VPC 中的逻辑联网组件，表示虚拟网卡。对于许多 EC2 实例类型，网络接口在硬件中共享一个网络接口卡（NIC）。此单个 NIC 具有最大带宽和每秒数据包速率。

如果启用了多 NIC 功能，则 VPC CNI 不会像默认那样批量分配 IP 地址。相反，新容器组（pod）启动后，VPC CNI 会按需为每个网卡上的网络接口分配一个 IP 地址。这种行为可降低因使用多宿主容器组（pod）而增加的 IP 地址耗尽率。由于 VPC CNI 按需分配 IP 地址，因此在启用多 NIC 功能的实例上，容器组（pod）可能需要更长的时间才能启动。

## 注意事项
<a name="pod-multi-nic-considerations"></a>
+ 确保您的 Kubernetes 集群运行的是 VPC CNI 版本 `1.20.0` 及更高版本。多 NIC 功能仅在 VPC CNI `1.20.0` 或更高版本中可用。
+ 在 VPC CNI 插件中启用 `ENABLE_MULTI_NIC` 环境变量。您可以运行以下命令来设置该变量并开始部署 DaemonSet。
  +  `kubectl set env daemonset aws-node -n kube-system ENABLE_MULTI_NIC=true` 
+ 确保创建具有多个网络接口卡（NIC）的 Worker 节点。有关具有多个网络接口卡的 EC2 实例列表，请参阅《Amazon EC2 用户指南》****中的[网卡](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-eni.html#network-cards)。
+ 如果启用了多 NIC 功能，则 VPC CNI 不会像默认那样批量分配 IP 地址。由于 VPC CNI 按需分配 IP 地址，因此在启用多 NIC 功能的实例上，容器组（pod）可能需要更长的时间才能启动。有关更多信息，请参阅之前的 [背景](#pod-multi-nic-background) 部分。
+ 启用多 NIC 功能后，容器组（pod）默认没有多个网络接口。必须将每个工作负载配置为使用多 NIC。为应具有多个网络接口的工作负载添加 `k8s.amazonaws.com/nicConfig: multi-nic-attachment` 注解。

### `IPv6` 注意事项
<a name="pod-multi-nic-considerations-ipv6"></a>
+  **自定义 IAM 策略**：对于 `IPv6` 集群，请为 VPC CNI 创建并使用以下自定义 IAM 策略。此策略专用于多 NIC。有关将 VPC CNI 与 `IPv6` 集群结合使用的更多一般信息，请参阅 [了解如何将 IPv6 地址分配给集群、容器组（pod）和服务](cni-ipv6.md)。

  ```
  {
      "Version":"2012-10-17",		 	 	 
      "Statement": [
          {
              "Sid": "AmazonEKSCNIPolicyIPv6MultiNIC",
              "Effect": "Allow",
              "Action": [
                  "ec2:CreateNetworkInterface",
                  "ec2:DescribeInstances",
                  "ec2:AssignIpv6Addresses",
                  "ec2:DetachNetworkInterface",
                  "ec2:DescribeNetworkInterfaces",
                  "ec2:DescribeTags",
                  "ec2:ModifyNetworkInterfaceAttribute",
                  "ec2:DeleteNetworkInterface",
                  "ec2:DescribeInstanceTypes",
                  "ec2:UnassignIpv6Addresses",
                  "ec2:AttachNetworkInterface",
                  "ec2:DescribeSubnets"
              ],
              "Resource": "*"
          },
          {
              "Sid": "AmazonEKSCNIPolicyENITagIPv6MultiNIC",
              "Effect": "Allow",
              "Action": "ec2:CreateTags",
              "Resource": "arn:aws:ec2:*:*:network-interface/*"
          }
      ]
  }
  ```
+  `IPv6` **转换机制不可用**：如果您使用多 NIC 功能，则 VPC CNI 不会为 `IPv6` 集群上的容器组（pod）分配 `IPv4` 地址。否则，VPC CNI 会为每个容器组（pod）分配一个主机本地 `IPv4` 地址，这样容器组（pod）便可与其他 Amazon VPC 或互联网中的外部 `IPv4` 资源进行通信。

## 用法
<a name="pod-multi-NIC-usage"></a>

在 VPC CNI 中启用多 NIC 功能并且 `aws-node` 容器组（pod）重新启动后，您可以将每个工作负载配置为多宿主。以下是带有所需注解的 YAML 配置示例：

```
apiVersion: apps/v1
kind: Deployment
metadata:
  name: orders-deployment
  namespace: ecommerce
  labels:
    app: orders
spec:
  replicas: 3
  selector:
    matchLabels:
      app: orders
  template:
    metadata:
      annotations:
         k8s.amazonaws.com/nicConfig: multi-nic-attachment
      labels:
        app: orders
    spec:
...
```

## 常见问题
<a name="pod-muti-nic-faqs"></a>

### **1。什么是网络接口卡（NIC）？**
<a name="pod-muti-nic-faqs-nic"></a>

网络接口卡（NIC），也简称网卡，是一种支持底层云计算硬件网络连接的物理设备。在现代 EC2 服务器中，这指的是 Nitro 网卡。弹性网络接口（ENI）是该底层网卡的虚拟表示。

某些 EC2 实例类型有多个 NIC，以提升带宽和数据包速率性能。对于此类实例，您可以将辅助 ENI 分配给其他网卡。例如，ENI \$11 可以作为连接到网卡索引 0 的 NIC 的接口，而 ENI \$12 可以作为连接到单独网卡索引的 NIC 的接口。

### **2. 什么是多宿主容器组（pod）？**
<a name="pod-muti-nic-faqs-pod"></a>

多宿主容器组（pod）是具有多个网络接口（也意味着多个 IP 地址）的单个 Kubernetes 容器组（pod）。每个容器组（pod）网络接口都关联一个[弹性网络接口（ENI）](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-eni.html)，而这些 ENI 是底层 Worker 节点上独立 NIC 的逻辑表示。通过多个网络接口，多宿主容器组（pod）具有额外的数据传输容量，从而也提升了其数据传输速率。

**重要**  
VPC CNI 只能在具有多个 NIC 的实例类型上配置多宿主容器组（pod）。

### **3. 为什么应该使用此功能？**
<a name="pod-muti-nic-faqs-why"></a>

如果您需要在基于 Kubernetes 的工作负载中扩展网络性能，可以使用多 NIC 功能运行多宿主容器组（pod），这些容器组（pod）与连接 ENA 设备的所有底层 NIC 相连。通过将应用程序流量分布到多个并发连接，利用额外的网卡可以提高应用程序的带宽容量和数据包速率性能。这对于人工智能（AI）、机器学习（ML）和高性能计算（HPC）使用案例特别有用。

### **4. 如何使用此功能？**
<a name="pod-muti-nic-faqs-how-to-enable"></a>

1. 首先，必须确保您的 Kubernetes 集群使用的是 VPC CNI 版本 1.20 或更高版本。有关将 VPC CNI 更新为 EKS 附加组件的步骤，请参阅[更新 Amazon VPC CNI（Amazon EKS 附加组件）](vpc-add-on-update.md)。

1. 然后，您必须使用 `ENABLE_MULTI_NIC` 环境变量在 VPC CNI 中启用多 NIC 支持。

1. 接着，您必须确保创建并加入具有多个网卡的节点。有关具有多个网卡的 EC2 实例类型列表，请参阅《Amazon EC2 用户指南》**中的[网卡](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/using-eni.html#network-cards)。

1. 最后，您可以将每个工作负载配置为使用多个网络接口（多宿主容器组（pod））或使用单个网络接口。

### **5. 如何将我的工作负载配置为在支持的 Worker 节点上使用多个 NIC？**
<a name="pod-muti-nic-faqs-how-to-workloads"></a>

要使用多宿主容器组（pod），您需要添加以下注解：`k8s.amazonaws.com/nicConfig: multi-nic-attachment`。这会将底层实例中每个 NIC 的 ENI 连接到容器组（pod）（容器组（pod）与 NIC 之间是一对多映射）。

如果缺少此注解，VPC CNI 会假设您的容器组（pod）只需要 1 个网络接口，并从任何可用 NIC 上的 ENI 为其分配一个 IP。

### **6. 此功能支持哪些网络接口适配器？**
<a name="pod-muti-nic-faqs-adapters"></a>

如果至少有一个 ENA 连接到底层网卡用于传输 IP 流量，则可以使用任何网络接口适配器。有关 ENA 的更多信息，请参阅《Amazon EC2 用户指南》**中的[弹性网络适配器（ENA）](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/enhanced-networking-ena.html)。

支持的网络设备配置：
+  **ENA** 接口提供支持 VPC 的 IP 联网所需的所有传统 IP 联网和路由功能。有关更多信息，请参阅[在 EC2 实例上使用 ENA 启用增强联网功能](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/enhanced-networking-ena.html)。
+  **EFA****（带 ENA 的** **EFA）**接口既提供用于 IP 联网的 ENA 设备，又提供用于低延迟、高吞吐量通信的 EFA 设备。

**重要**  
如果网卡仅连接了**仅限 EFA** 适配器，则在为多宿主容器组（pod）预置网络连接时，VPC CNI 将跳过。但是，如果您在网卡上将**仅限 EFA** 适配器与 **ENA** 适配器结合使用，则 VPC CNI 也将管理此设备上的 ENI。要将仅限 EFA 接口与 EKS 集群结合使用，请参阅[使用 Elastic Fabric Adapter 在 Amazon EKS 上运行机器学习训练](node-efa.md)。

### **7. 我可以查看集群中的某个节点是否支持 ENA 吗？**
<a name="pod-muti-nic-faqs-node-ena"></a>

是的，您可以使用 AWS CLI 或 EC2 API 来检索有关集群中 EC2 实例的网络信息。这将提供有关该实例是否支持 ENA 的详细信息。在以下示例中，将 `<your-instance-id>` 替换为节点的 EC2 实例 ID。

 AWS CLI 示例：

```
aws ec2 describe-instances --instance-ids <your-instance-id> --query "Reservations[].Instances[].EnaSupport"
```

输出示例：

```
[ true ]
```

### **8. 我可以查看与容器组（pod）关联的不同 IP 地址吗？**
<a name="pod-muti-nic-faqs-list-ips"></a>

这不太容易。但您可以从节点使用 `nsenter` 运行常用网络工具（例如 `ip route show`）并查看其他 IP 地址和接口。

### **9. 我可以控制控制容器组（pod）的网络接口数量吗？**
<a name="pod-muti-nic-faqs-number-of-enis"></a>

不可以。当您的工作负载配置为在支持的实例上使用多个 NIC 时，单个容器组（pod）会自动从该实例上的每个网卡获得一个 IP 地址。或者，单宿主容器组（pod）将有一个网络接口连接到实例上的一个 NIC。

**重要**  
VPC CNI 会跳过*仅*连接**仅限 EFA** 设备的网卡。

### **10. 我可以将容器组（pod）配置为使用特定的 NIC 吗？**
<a name="pod-muti-nic-faqs-specify-nic"></a>

不可以，不支持此功能。如果某个容器组（pod）有相关注解，则 VPC CNI 会自动将其配置为使用 Worker 节点上带有 ENA 适配器的每个 NIC。

### **11. 此功能可以与其他 VPC CNI 联网功能结合使用吗？**
<a name="pod-muti-nic-faqs-modes"></a>

可以，VPC CNI 中的多 NIC 功能可以与*自定义联网*和*增强型子网发现*功能结合使用。但是，多宿主容器组（pod）不会使用自定义子网或安全组。相反，VPC CNI 会将 IP 地址和网络接口分配给与节点具有相同子网和安全组配置的多宿主容器组（pod）。有关自定义联网功能的更多信息，请参阅 [使用自定义网络在备用子网中部署容器组（pod）](cni-custom-network.md)。

VPC CNI 中的多 NIC 功能不适用且无法与*容器组（pod）的安全组*结合使用。

### **12. 我可以将网络策略与此功能结合使用吗？**
<a name="pod-muti-nic-faqs-netpol"></a>

可以，您可以将 Kubernetes 网络策略与多 NIC 结合使用。Kubernetes 网络策略可限制进出容器组（pod）的网络流量。有关使用 VPC CNI 应用网络策略的更多信息，请参阅[通过 Kubernetes 网络策略限制容器组（pod）流量](cni-network-policy.md)。

### **13. EKS 自动模式下是否启用了多 NIC 支持？**
<a name="pod-muti-nic-faqs-auto-mode"></a>

EKS 自动模式集群不支持多 NIC。