

 **帮助改进此页面** 

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

# Amazon EKS 混合节点功能概述
<a name="hybrid-nodes-overview"></a>

借助 *Amazon EKS 混合节点功能*，您可以将本地和边缘基础设施用作 Amazon EKS 集群中的节点。AWS 负责管理由 AWS 托管的 Amazon EKS 集群的 Kubernetes 控制面板，而您负责管理在本地或边缘环境中运行的混合节点。这样就实现了跨环境的统一 Kubernetes 管理，将本地和边缘应用程序的 Kubernetes 控制面板管理工作转移到 AWS。

Amazon EKS 混合节点功能可支持任何本地硬件或虚拟机，从而在任何需要运行应用程序的位置享受到 Amazon EKS 的效率、可扩展性和可用性。您可以将各种 Amazon EKS 功能与 Amazon EKS 混合节点功能结合使用，包括 Amazon EKS 附加组件、Amazon EKS 容器组身份、集群访问条目、集群及见解和 Kubernetes 版本延期支持。Amazon EKS 混合节点功能原生集成了多项 AWS 服务，包括 AWS Systems Manager、AWS IAM Roles Anywhere、Amazon Managed Service for Prometheus 和 Amazon CloudWatch，用于集中监控、日志记录和身份管理。

使用 Amazon EKS 混合节点功能时，无预付承诺或最低费用要求，并且在将混合节点挂载到 Amazon EKS 集群时，您只需按小时为混合节点的 vCPU 资源付费。有关详细定价信息，请参阅 [Amazon EKS 定价](https://aws.amazon.com/eks/pricing/)。

[![AWS Videos](http://img.youtube.com/vi/https://www.youtube.com/embed/tFn9IdlddBw?rel=0/0.jpg)](http://www.youtube.com/watch?v=https://www.youtube.com/embed/tFn9IdlddBw?rel=0)


## 特征
<a name="hybrid-nodes-features"></a>

EKS 混合节点具有以下高级功能：
+  **托管式 Kubernetes 控制面板**：AWS 负责管理 EKS 集群中由 AWS 托管的 Kubernetes 控制面板，您负责管理在本地或边缘环境中运行的混合节点。这样就实现了跨环境的统一 Kubernetes 管理，将本地和边缘应用程序的 Kubernetes 控制面板管理工作转移到 AWS。通过将 Kubernetes 控制面板转移到 AWS，您可以将本地容量留给应用程序，并且 Kubernetes 控制平面会根据工作负载的需要而扩展。
+  **一致的 EKS 体验**：EKS 混合节点功能支持大多数 EKS 功能，可在本地和云环境中提供一致的 EKS 体验，包括 EKS 附加组件、EKS 容器组身份、集群访问条目、集群见解、扩展 Kubernetes 版本支持等。有关 EKS 混合节点功能支持的 EKS 附加组件的更多信息，请参阅[为混合节点配置附加组件](hybrid-nodes-add-ons.md)。
+  **集中式可观测性和身份管理**：EKS 混合节点功能可与多项 AWS 服务原生集成，包括 AWS Systems Manager、AWS IAM Roles Anywhere、Amazon Managed Service for Prometheus 和Amazon CloudWatch 等，从而满足集中监控、日志记录和身份管理等需求。
+  **通过云端满足突发需求或增加本地容量**：单个 EKS 集群可用于运行混合节点以及位于 AWS 区域、AWS Local Zones 或 AWS Outposts 中的节点，从而通过云端满足突发需求，也可为 EKS 集群添加本地容量。有关更多信息，请参阅[混合模式集群注意事项](hybrid-nodes-webhooks.md#hybrid-nodes-considerations-mixed-mode)。
+  **灵活基础设施**：EKS 混合节点功能遵循*自带基础设施*的方法，并且与您用于混合节点的基础设施无关。您可以在物理计算机或虚拟机上运行混合节点，可以使用 x86 和 ARM 架构，从而跨不同的基础设施类型迁移在混合节点上运行的本地工作负载。
+  **灵活联网**：使用 EKS 混合节点功能时，EKS 控制面板与混合节点之间的通信通过您在集群创建期间传递的 VPC 和子网进行路由，此方法基于 EKS 中控制面板用于节点联网的[现有机制](https://docs.aws.amazon.com/eks/latest/best-practices/subnets.html)。您可以灵活选择将本地网络连接到 AWS 中的 VPC 的首选方法。有多个[有文档记录的选项](https://docs.aws.amazon.com/whitepapers/latest/aws-vpc-connectivity-options/network-to-amazon-vpc-connectivity-options.html)可供选择，包括 AWS Site-to-Site VPN、AWS Direct Connect 或您自己的 VPN 解决方案，您可以根据自己的应用场景选择最适合的方法。

## 限制
<a name="hybrid-node-limits"></a>
+ 每个集群最多支持将 15 个 CIDR 用于远程节点网络，以及将 15 个 CIDR 用于远程容器组网络。

## 注意事项
<a name="hybrid-nodes-general"></a>
+ EKS 混合节点功能可与新的或现有的 EKS 集群结合使用。
+ 除 AWS GovCloud（美国）区域和 AWS 中国区域外，EKS 混合节点功能已在所有 AWS 区域开放。
+ 要使用 EKS 混合节点功能，必须在您的本地环境和 AWS 之间建立可靠的连接。EKS 混合节点功能不适合连接断开、中断、间歇性或受限（DDIL）的环境。如果在 DDIL 环境中运行，可以考虑使用 [Amazon EKS Anywhere](https://aws.amazon.com/eks/eks-anywhere/)。有关混合节点在网络断开连接情况下行为的信息，请参阅 [Best Practices for EKS Hybrid Nodes](https://docs.aws.amazon.com/eks/latest/best-practices/hybrid-nodes-network-disconnections.html)。
+ 不支持在云基础设施（包括 AWS 区域、AWS Local Zones、AWS Outposts 或其他云）中运行 EKS 混合节点功能。如果您在 Amazon EC2 实例上运行混合节点，则需要支付混合节点功能使用费。
+ 混合节点功能使用费从节点加入 EKS 集群时起开始计费，并在从集群中移除节点时停止计费。如果您不使用混合节点功能，请务必将其从 EKS 集群中移除。

## 其他资源
<a name="hybrid-nodes-resources"></a>
+  [https://www.eksworkshop.com/docs/networking/eks-hybrid-nodes/](https://www.eksworkshop.com/docs/networking/eks-hybrid-nodes/)：在演示环境中部署 EKS 混合节点的分步说明。
+  [https://www.youtube.com/watch?v=ZxC7SkemxvU](https://www.youtube.com/watch?v=ZxC7SkemxvU)：AWS re:Invent 会议介绍了 EKS 混合节点发布会，一位客户展示了其如何在自己的环境中使用 EKS 混合节点。
+  [https://repost.aws/articles/ARL44xuau6TG2t-JoJ3mJ5Mw/unpacking-the-cluster-networking-for-amazon-eks-hybrid-nodes](https://repost.aws/articles/ARL44xuau6TG2t-JoJ3mJ5Mw/unpacking-the-cluster-networking-for-amazon-eks-hybrid-nodes)：文章说明了为 EKS 混合节点设置网络的各种方法。
+  [https://aws.amazon.com/blogs/containers/run-genai-inference-across-environments-with-amazon-eks-hybrid-nodes/](https://aws.amazon.com/blogs/containers/run-genai-inference-across-environments-with-amazon-eks-hybrid-nodes/)：博客文章展示了如何使用 EKS 混合节点跨环境运行 GenAI 推理。

# 混合节点的先决条件设置
<a name="hybrid-nodes-prereqs"></a>

要使用 Amazon EKS 混合节点功能，您必须拥有在本地环境与 AWS、具有支持操作系统的裸机服务器或虚拟机之间往来传输的私有连接，并且配置了 AWS IAM Roles Anywhere 或 AWS Systems Manager（SSM）混合激活。您负责在整个混合节点生命周期中管理这些先决条件。
+ 在本地环境与 AWS 之间往来传输的混合网络连接 
+ 物理计算机或虚拟机形式的基础设施
+ 与混合节点功能兼容的操作系统
+ 已配置好本地 IAM 凭证提供者

![\[混合节点网络连接。\]](http://docs.aws.amazon.com/zh_cn/eks/latest/userguide/images/hybrid-prereq-diagram.png)


## 混合网络连接
<a name="hybrid-nodes-prereqs-connect"></a>

Amazon EKS 控制面板和混合节点之间的通信通过您在集群创建期间传递的 VPC 和子网进行路由，此方法以 Amazon EKS 中控制面板到节点联网的[现有机制](https://aws.github.io/aws-eks-best-practices/networking/subnets/)为基础。有多个[有文档记录的选项](https://docs.aws.amazon.com/whitepapers/latest/aws-vpc-connectivity-options/network-to-amazon-vpc-connectivity-options.html)可供选择，以在本地环境与 VPC 之间建立连接，包括 AWS Site-to-Site VPN 和 AWS Direct Connect。有关如何使用这些解决方案实现混合网络连接的更多信息，请参阅 [AWS Site-to-Site VPN](https://docs.aws.amazon.com/vpn/latest/s2svpn/VPC_VPN.html) 和 [AWS Direct Connect](https://docs.aws.amazon.com/directconnect/latest/UserGuide/Welcome.html) 用户指南。

为确保最佳体验，我们建议您从混合节点到 AWS 区域的可靠网络连接至少达到 100 Mbps，并且往返延迟最大 200 毫秒。这是适用于大多数使用案例的一般指导，但并非严格要求。带宽和延迟要求可能因混合节点的数量和工作负载特征而异，例如应用程序映像大小，应用程序弹性、监控和日志记录配置，以及需要访问其他 AWS 服务中所存储数据的应用程序依赖项。我们建议在部署到生产环境之前使用自己的应用程序和环境进行测试，从而验证您的网络设置是否满足工作负载的要求。

## 本地网络配置
<a name="hybrid-nodes-prereqs-onprem"></a>

您必须启用从 Amazon EKS 控制面板到本地环境的入站网络访问权限，以允许 Amazon EKS 控制面板与在混合节点上运行的 `kubelet` 进行通信，此外也可以选择与在混合节点上运行的 Webhook 进行通信。此外，您必须为混合节点以及在其上运行的组件启用出站网络访问权限，确保其能与 Amazon EKS 控制面板进行通信。您可以将此通信配置为完全限定于您的 AWS Direct Connect、AWS Site-to-Site VPN 或您自己的 VPN 连接。

您用于本地节点和容器组（pod）网络的无类别域间路由范围必须使用 IPv4 RFC-1918 或 CGNAT 地址范围。本地路由器必须配置指向本地节点以及（可选）容器组的路由。请参阅[本地联网配置](hybrid-nodes-networking.md#hybrid-nodes-networking-on-prem)以了解有关本地网络要求的更多信息，包括防火墙和本地环境中必须启用的所需端口和协议的完整列表。

## EKS 集群配置
<a name="hybrid-nodes-prereqs-cluster"></a>

为尽可能减少延迟，我们建议您在距离本地或边缘环境最近的 AWS 区域创建 Amazon EKS 集群。您需要在创建 Amazon EKS 集群期间通过以下两个 API 字段来传递本地节点和容器组 CIDR：`RemoteNodeNetwork` 和 `RemotePodNetwork`。您可能需要与本地网络团队讨论，以确定本地节点和容器组 CIDR。节点 CIDR 是从本地网络分配的，如果您为 CNI 使用叠加网络，则容器组 CIDR 是从您使用的容器网络接口（CNI）分配的。默认情况下，Cilium 和 Calico 使用叠加网络。

您通过 `RemoteNodeNetwork` 和 `RemotePodNetwork` 字段配置的本地节点和容器组 CIDR 可用于配置 Amazon EKS 控制面板，以通过您的 VPC 将流量路由到 `kubelet` 以及在混合节点上运行的容器组。您的本地节点和容器组 CIDR 不能相互重叠，不能与您在创建集群时传递的 VPC CIDR 重叠，也不能与 Amazon EKS 集群的服务 IPv4 配置重叠。此外，每个 EKS 集群的容器组（pod）CIDR 必须是唯一的，这样本地路由器才能路由流量。

我们建议为 Amazon EKS Kubernetes API 服务器端点使用公有或私有端点访问权限。如果您选择“公有和私有”，Amazon EKS Kubernetes API 服务器端点将始终解析为在您的 VPC 之外运行的混合节点公有 IP，这可能会阻止您的混合节点加入集群。使用公有端点访问权限时，Kubernetes API 服务器端点将解析为公有 IP，并且从混合节点到 Amazon EKS 控制面板的通信将通过互联网路由。当您选择私有端点访问权限时，Kubernetes API 服务器端点将解析为私有 IP，并且从混合节点到 Amazon EKS 控制面板的通信将通过您的私有连接链路（大部分情况下为 AWS Direct Connect 或 AWS Site-to-Site VPN）进行路由。

## VPC 配置
<a name="hybrid-nodes-prereqs-vpc"></a>

您必须在创建 Amazon EKS 集群期间配置 VPC，并在其路由表中包含本地节点的路由，您还可以配置容器组网络，将您的虚拟专用网关（VGW）或中转网关（TGW）作为目标。下面显示了一个示例。将 `REMOTE_NODE_CIDR` 和 `REMOTE_POD_CIDR` 替换为本地网络的相应值。


| 目标位置 | Target | 说明 | 
| --- | --- | --- | 
|  10.226.0.0/16  |  本地  |  到 VPC 的流量将在 VPC 内部路由  | 
|  REMOTE\$1NODE\$1CIDR  |  tgw-abcdef123456  |  本地节点 CIDR，将流量路由到 TGW  | 
|  REMODE\$1POD\$1CIDR  |  tgw-abcdef123456  |  本地容器组 CIDR，将流量路由到 TGW  | 

## 安全组配置
<a name="hybrid-nodes-prereqs-sg"></a>

在创建集群时，Amazon EKS 将创建一个名为 `eks-cluster-sg-<cluster-name>-<uniqueID>` 的安全组。您无法更改此集群安全组的入站规则，但可以限制出站规则。您必须向集群添加一个额外的安全组，以确保在混合节点上运行的 kubelet 和（可选）Webhook 能够与 Amazon EKS 控制面板通信。对于此额外的安全组，必需的入站规则如下所示。将 `REMOTE_NODE_CIDR` 和 `REMOTE_POD_CIDR` 替换为本地网络的相应值。


| 名称 | 安全组规则 ID | IP 版本 | Type | 协议 | 端口范围 | 来源 | 
| --- | --- | --- | --- | --- | --- | --- | 
|  本地节点入站  |  sgr-abcdef123456  |  IPv4  |  HTTPS  |  TCP  |  443  |  REMOTE\$1NODE\$1CIDR  | 
|  本地容器组入站  |  sgr-abcdef654321  |  IPv4  |  HTTPS  |  TCP  |  443  |  REMOTE\$1POD\$1CIDR  | 

## Infrastructure
<a name="hybrid-nodes-prereqs-infra"></a>

您必须有可用作混合节点的裸机服务器或虚拟机可用。混合节点与底层基础设施无关，x86 和 ARM 架构均受支持。Amazon EKS 混合节点功能采用“自带基础设施”的方法，即您需要自行预置和管理用作混合节点的裸机服务器或虚拟机。虽然没有严格的最低资源要求，但对于混合节点，我们建议您使用至少具有 1 个 vCPU 和 1GiB RAM 的主机。

## 操作系统
<a name="hybrid-nodes-prereqs-os"></a>

Bottlerocket、Amazon Linux 2023（AL2023）、Ubuntu 和 RHEL 均已经过持续验证，可用作混合节点的节点操作系统。AWS 仅在 VMware vSphere 环境中支持 Bottlerocket。在 Amazon EC2 之外运行时，AL2023 不属于 AWS Support 计划的范围。AL2023 只能在本地虚拟化环境中使用；有关更多信息，请参阅《Amazon Linux 2023 User Guide》[https://docs.aws.amazon.com/linux/al2023/ug/outside-ec2.html](https://docs.aws.amazon.com/linux/al2023/ug/outside-ec2.html)。AWS 支持混合节点与 Ubuntu 和 RHEL 操作系统的集成，但不提供对操作系统本身的支持。

操作系统的预置和管理由您负责。首次测试混合节点时，最简单的方法是在一台已预置好的主机上运行 Amazon EKS 混合节点功能 CLI (`nodeadm`)。对于生产部署，建议在黄金操作系统映像中包含 `nodeadm` 并将其配置为作为 systemd 服务运行，从而在主机启动时自动将主机加入 Amazon EKS 集群。

## 本地 IAM 凭证提供者
<a name="hybrid-nodes-prereqs-iam"></a>

Amazon EKS 混合节点功能使用由 AWS SSM 混合激活或 AWS IAM Roles Anywhere 预置的临时 IAM 凭证，来进行 Amazon EKS 集群身份验证。您必须使用 AWS SSM 混合激活，或将 AWS IAM Roles Anywhere 与 Amazon EKS 混合节点功能 CLI (`nodeadm`) 配合使用。如果您没有具有证书颁发机构（CA）的现有公钥基础设施（PKI）和本地环境的证书，我们建议您使用 AWS SSM 混合激活。如果您在确实具有现有的 PKI 和本地证书，请使用 AWS IAM Roles Anywhere。

与适用于在 Amazon EC2 上运行的节点的 [Amazon EKS 节点 IAM 角色](create-node-role.md) 类似，您将创建一个混合节点 IAM 角色，具有将混合节点加入到 Amazon EKS 集群所需的权限。如果您使用 AWS IAM Roles Anywhere，请配置一个信任策略来允许 AWS IAM Roles Anywhere 代入该混合节点 IAM 角色，此外还需要配置您的 AWS IAM Roles Anywhere 配置文件，将该混合节点 IAM 角色作为假设角色。如果您使用 AWS SSM，请配置一个信任策略来允许 AWS SSM 代入混合节点 IAM 角色并使用混合节点 IAM 角色创建混合激活。有关如何创建具有必需权限的混合节点 IAM 角色的信息，请参阅[准备用于混合节点的凭证](hybrid-nodes-creds.md)。

# 准备混合节点的联网
<a name="hybrid-nodes-networking"></a>

本主题概述创建 Amazon EKS 集群和挂载混合节点之前必须配置的联网设置。本指南假设您已满足使用 [AWS Site-to-Site VPN](https://docs.aws.amazon.com/vpn/latest/s2svpn/SetUpVPNConnections.html)、[AWS Direct Connect](https://docs.aws.amazon.com/directconnect/latest/UserGuide/Welcome.html) 或您自己的 VPN 解决方案进行混合网络连接的先决条件。

![\[混合节点网络连接。\]](http://docs.aws.amazon.com/zh_cn/eks/latest/userguide/images/hybrid-prereq-diagram.png)


## 本地联网配置
<a name="hybrid-nodes-networking-on-prem"></a>

### 最低网络要求
<a name="hybrid-nodes-networking-min-reqs"></a>

为确保最佳体验，我们建议您从混合节点到 AWS 区域的可靠网络连接至少达到 100 Mbps，并且往返延迟最大 200 毫秒。这是适用于大多数使用案例的一般指导，但并非严格要求。带宽和延迟要求可能因混合节点的数量和工作负载特征而异，例如应用程序映像大小，应用程序弹性、监控和日志记录配置，以及需要访问其他 AWS 服务中所存储数据的应用程序依赖项。我们建议在部署到生产环境之前使用自己的应用程序和环境进行测试，从而验证您的网络设置是否满足工作负载的要求。

### 本地节点和容器组 CIDR
<a name="hybrid-nodes-networking-on-prem-cidrs"></a>

确定您将用于混合节点以及在其上运行的工作负载的节点和容器组 CIDR。节点 CIDR 是从本地网络分配的，如果您为 CNI 使用叠加网络，则容器组 CIDR 是从您的容器网络接口（CNI）分配的。创建 EKS 集群时，您可以使用 `RemoteNodeNetwork` 和 `RemotePodNetwork` 字段将本地节点 CIDR 和容器组 CIDR 作为输入传递。本地节点 CIDR 必须可在本地网络上路由。有关本地容器组 CIDR 可路由性的信息，请参阅以下一节。

本地节点和容器组 CIDR 块必须满足以下要求：

1. 位于以下 `IPv4` RFC-1918 范围之一：`10.0.0.0/8`、`172.16.0.0/12` 或 `192.168.0.0/16`，或位于 RFC 6598 定义的 CGNAT 范围：`100.64.0.0/10`。

1. 不相互重叠，也不与 EKS 集群的 VPC CIDR 或 Kubernetes 服务 `IPv4` CIDR 重叠。

### 本地容器组网络路由
<a name="hybrid-nodes-networking-on-prem-pod-routing"></a>

使用 EKS 混合节点时，我们通常建议您将本地容器组 CIDR 设置为在本地网络上可路由，以便在云和本地环境之间实现完整的集群通信和功能。

 **可路由的容器组网络** 

如果您能够将容器组网络设置为在本地网络上可路由，则请按照以下指导操作。

1. 使用本地容器 CIDR 配置 EKS 集群的 `RemotePodNetwork` 字段，使用本地容器 CIDR 配置您的 VPC 路由表，以及使用本地容器 CIDR 配置您的 EKS 集群安全组。

1. 您可以通过多种方法来使本地容器组 CIDR 可在本地网络上路由，包括边界网关协议（BGP）、静态路由或其他自定义路由解决方案。我们推荐使用 BGP 解决方案，因为与需要自定义或手动路由配置的备选解决方案相比，此方案具有更好的可扩展性并且更易于管理。AWS 支持使用 Cilium 和 Calico 的 BGP 功能来公开容器组 CIDR，有关更多信息，请参阅[为混合节点配置 CNI](hybrid-nodes-cni.md)和[可路由的远程容器组（pod）CIDR](hybrid-nodes-concepts-kubernetes.md#hybrid-nodes-concepts-k8s-pod-cidrs)。

1. Webhook 可以在混合节点上运行，因为 EKS 控制面板能够与分配给 Webhook 的容器组 IP 地址进行通信。

1. 在云节点上运行的工作负载能够直接与同一 EKS 集群中混合节点上运行的工作负载进行通信。

1. 其他 AWS 服务（例如 AWS 应用程序负载均衡器和 Amazon Managed Service for Prometheus）能够与在混合节点上运行的工作负载进行通信，以平衡网络流量并抓取容器组指标。

 **不可路由的容器组网络** 

如果您*无法*将容器组网络设置为在本地网络上可路由，则请按照以下指导操作。

1. Webhook 无法在混合节点上运行，因为 Webhook 需要从 EKS 控制面板连接到分配给 Webhook 的容器组 IP 地址。在这种情况下，我们建议您在与混合节点位于同一 EKS 集群中的云节点上运行 Webhook；有关更多信息，请参阅[为混合节点配置 Webhook](hybrid-nodes-webhooks.md)。

1. 对云节点使用 VPC CNI 并对混合节点使用 Cilium 或 Calico 时，在云节点上运行的工作负载无法直接与在混合节点上运行的工作负载进行通信。

1. 使用服务流量分布将流量保持在其源区域的本地。有关服务流量分布的更多信息，请参阅[配置服务流量分布](hybrid-nodes-webhooks.md#hybrid-nodes-mixed-service-traffic-distribution)。

1. 将 CNI 配置为在离开本地主机时对容器组流量使用出口伪装或网络地址转换（NAT）。此项在 Cilium 中默认为启用状态。Calico 需要将 `natOutgoing` 设置为 `true`。

1. 其他 AWS 服务（例如 AWS 应用程序负载均衡器和 Amazon Managed Service for Prometheus）能够与在混合节点上运行的工作负载进行通信。

### 混合节点安装和升级期间必需的访问权限
<a name="hybrid-nodes-networking-access-reqs"></a>

在安装过程中，您必须具有以下域的访问权限，以便在主机上安装混合节点依赖项。此过程可以在生成操作系统映像时一次执行，也可以在运行时中在每台主机上完成。这包括初始安装以及升级混合节点的 Kubernetes 版本时。

某些软件包使用操作系统的默认软件包管理器进行安装。对于 AL2023 和 RHEL，使用 `yum` 命令安装 `containerd`、`ca-certificates`、`iptables` 和 `amazon-ssm-agent`。对于 Ubuntu，使用 `apt` 安装 `containerd`、`ca-certificates` 和 `iptables`，并使用 `snap` 安装 `amazon-ssm-agent`。


| 组件 | URL | 协议 | 端口： | 
| --- | --- | --- | --- | 
|  EKS 节点构件（S3）  |  https://hybrid-assets.eks.amazonaws.com  |  HTTPS  |  443  | 
|   [EKS 服务端点](https://docs.aws.amazon.com/general/latest/gr/eks.html)   |  https://eks.*region*.amazonaws.com  |  HTTPS  |  443  | 
|   [ECR 服务端点](https://docs.aws.amazon.com/general/latest/gr/ecr.html)   |  https://api.ecr.*region*.amazonaws.com  |  HTTPS  |  443  | 
|  EKS ECR 端点  |  区域性端点请参阅[查看 Amazon EKS 附加组件的 Amazon 容器映像注册表](add-ons-images.md)。  |  HTTPS  |  443  | 
|  SSM 二进制端点 1   |  https://amazon-ssm-*region*.s3.*region*.amazonaws.com  |  HTTPS  |  443  | 
|   [SSM 服务端点](https://docs.aws.amazon.com/general/latest/gr/ssm.html) 1   |  https://ssm.*region*.amazonaws.com  |  HTTPS  |  443  | 
|  IAM Anywhere 二进制端点 2   |  https://rolesanywhere.amazonaws.com  |  HTTPS  |  443  | 
|   [IAM Anywhere 服务端点](https://docs.aws.amazon.com/general/latest/gr/rolesanywhere.html) 2   |  https://rolesanywhere.*region*.amazonaws.com  |  HTTPS  |  443  | 
|  操作系统软件包管理器端点  |  软件包存储库端点是特定于操作系统的端点，并且可能因地理区域而异。  |  HTTPS  |  443  | 

**注意**  
 1 仅在将 AWS SSM 混合激活用作本地 IAM 凭证提供者时，才需要 AWS SSM 端点访问权限。  
 2 仅在将 AWS IAM Roles Anywhere 用作本地 IAM 凭证提供者时，才需要 AWS IAM 端点访问权限。

### 正在进行的集群操作需要的访问权限
<a name="hybrid-nodes-networking-access-reqs-ongoing"></a>

正在进行的集群操作需要拥有本地防火墙的以下网络访问权限。

**重要**  
根据您选择的 CNI，您需要为 CNI 端口配置其他网络访问规则。有关详细信息，请参阅 [Cilium 文档](https://docs.cilium.io/en/stable/operations/system_requirements/#firewall-rules)和 [Calico 文档](https://docs.tigera.io/calico/latest/getting-started/kubernetes/requirements#network-requirements)。


| Type | 协议 | Direction | 端口： | 来源 | 目标 | 用法 | 
| --- | --- | --- | --- | --- | --- | --- | 
|  HTTPS  |  TCP  |  出站  |  443  |  远程节点 CIDR  |  EKS 集群 IP 1   |  Kubelet 到 Kubernetes API 服务器  | 
|  HTTPS  |  TCP  |  出站  |  443  |  远程容器组 CIDR  |  EKS 集群 IP 1   |  容器组（pod）到 Kubernetes API 服务器  | 
|  HTTPS  |  TCP  |  出站  |  443  |  远程节点 CIDR  |   [SSM 服务端点](https://docs.aws.amazon.com/general/latest/gr/ssm.html)   |  SSM 混合激活凭证刷新和 SSM 心跳信号发送每隔 5 分钟进行一次  | 
|  HTTPS  |  TCP  |  出站  |  443  |  远程节点 CIDR  |   [IAM Anywhere 服务端点](https://docs.aws.amazon.com/general/latest/gr/rolesanywhere.html)   |  IAM Roles Anywhere 凭证刷新  | 
|  HTTPS  |  TCP  |  出站  |  443  |  远程容器组 CIDR  |   [STS 区域性端点](https://docs.aws.amazon.com/general/latest/gr/sts.html)   |  容器组（pod）到 STS 端点，仅对 IRSA 为必需  | 
|  HTTPS  |  TCP  |  出站  |  443  |  远程节点 CIDR  |   [Amazon EKS 身份验证服务端点](https://docs.aws.amazon.com/general/latest/gr/eks.html)   |  节点到 Amazon EKS 身份验证端点，仅对 Amazon EKS 容器组身份为必需  | 
|  HTTPS  |  TCP  |  入站  |  10250  |  EKS 集群 IP 1   |  远程节点 CIDR  |  Kubernetes API 服务器到 kubelet  | 
|  HTTPS  |  TCP  |  入站  |  Webhook 端口  |  EKS 集群 IP 1   |  远程容器组 CIDR  |  Kubernetes API 服务器到 Webhook  | 
|  HTTPS  |  TCP、UDP  |  入站、出站  |  53  |  远程容器组 CIDR  |  远程容器组 CIDR  |  容器组（pod）到 CoreDNS。如果您在云端运行至少 1 个 CoreDNS 副本，则必须允许指向运行 CoreDNS 的 VPC 的 DNS 流量。  | 
|  用户定义  |  用户定义  |  入站、出站  |  应用程序端口  |  远程容器组 CIDR  |  远程容器组 CIDR  |  容器组（pod）到容器组（pod）  | 

**注意**  
 1 EKS 集群的 IP。请参阅以下有关 Amazon EKS 弹性网络接口的章节。

### Amazon EKS 网络接口
<a name="hybrid-nodes-networking-eks-network-interfaces"></a>

Amazon EKS 将网络接口附加到您在集群创建期间传递的 VPC 中的子网，从而实现 EKS 控制面板与您的 VPC 之间的通信。Amazon EKS 创建的网络接口可以在集群创建后通过 Amazon EC2 控制台查看，也可以通过 AWS CLI 查看。对 EKS 集群应用更改（例如 Kubernetes 版本升级）时，系统会删除原始网络接口并创建新的网络接口。您可以在集群创建期间传递子网时使用受限子网大小来限制 Amazon EKS 网络接口的 IP 范围，从而更轻松地配置本地防火墙，允许与已知受限 IP 集的入站/出站连接。要控制要在其中创建网络接口的子网，您可以在创建集群时限制指定的子网数，或者在创建集群后更新子网。

由 Amazon EKS 预置的网络接口的描述格式为 `Amazon EKS your-cluster-name `。有关可用于查找 Amazon EKS 所预置网络接口的 IP 地址的 AWS CLI 命令，请参阅以下示例。请将 `VPC_ID` 替换为您在创建集群时传递的 VPC 的 ID。

```
aws ec2 describe-network-interfaces \
--query 'NetworkInterfaces[?(VpcId == VPC_ID && contains(Description,Amazon EKS))].PrivateIpAddress'
```

## AWS VPC 和子网设置
<a name="hybrid-nodes-networking-vpc"></a>

Amazon EKS 的现有 [VPC 和子网要求](network-reqs.md)适用于使用混合节点的集群。此外，VPC CIDR 不能与本地节点和容器组 CIDR 重叠。必须在 VPC 路由表中为本地节点以及（可选）容器组 CIDR 配置路由。这些路由必须设置为将流量路由到用于混合网络连接的网关，这通常是虚拟专用网关（VGW）或中转网关（TGW）。如果您使用 TGW 或 VGW 来连接 VPC 和本地环境，则必须为您的 VPC 创建 TGW 或 VGW 连接。VPC 必须具有 DNS 主机名和 DNS 解析支持。

以下步骤会用到 AWS CLI。您还可以在 AWS 管理控制台中或使用其他接口（例如 AWS CloudFormation、AWS CDK 或 Terraform）创建这些资源。

### 第 1 步：创建 VPC
<a name="_step_1_create_vpc"></a>

1. 运行以下命令以创建一个 VPC。将 VPC\$1CIDR 替换为符合 RFC 1918（私有）、CGNAT（RFC 6598）或非 RFC 1918/非 CGNAT（公有）的 IPv4 CIDR 范围（例如 10.0.0.0/16）。注意：VPC 会默认启用 DNS 解析，这是 EKS 的一项要求。

   ```
   aws ec2 create-vpc --cidr-block VPC_CIDR
   ```

1. 为 VPC 启用 DNS 主机名。VPC 会默认启用 DNS 解析。请将 `VPC_ID` 替换为在上一步中创建的 VPC 的 ID。

   ```
   aws ec2 modify-vpc-attribute --vpc-id VPC_ID --enable-dns-hostnames
   ```

### 第 2 步：创建子网
<a name="_step_2_create_subnets"></a>

至少创建 2 个子网。Amazon EKS 会将这些子网作为集群网络接口。有关更多信息，请参阅[子网要求和注意事项](network-reqs.md#network-requirements-subnets)。

1. 您可以使用以下命令找到 AWS 区域的可用区。请将 `us-west-2` 替换为您的区域。

   ```
   aws ec2 describe-availability-zones \
        --query 'AvailabilityZones[?(RegionName == us-west-2)].ZoneName'
   ```

1. 创建子网。请将 `VPC_ID` 替换为 VPC 的 ID。请将 `SUBNET_CIDR` 替换为子网的 CIDR 块（例如 10.0.1.0/24）。请将 `AZ` 替换为将在其中创建子网的可用区（例如 us-west-2a）。您创建的子网必须至少位于 2 个不同的可用区。

   ```
   aws ec2 create-subnet \
       --vpc-id VPC_ID \
       --cidr-block SUBNET_CIDR \
       --availability-zone AZ
   ```

### （可选）第 3 步：使用 Amazon VPC Transit Gateway（TGW）或 AWS Direct Connect 虚拟专用网关（VGW）附加 VPC
<a name="optional_step_3_attach_vpc_with_amazon_vpc_transit_gateway_tgw_or_shared_aws_direct_connect_virtual_private_gateway_vgw"></a>

如果使用 TGW 或 VGW，请将您的 VPC 连接到该 TGW 或 VGW。有关更多信息，请参阅 [Amazon VPC attachments in Amazon VPC Transit Gateways](https://docs.aws.amazon.com/vpc/latest/tgw/tgw-vpc-attachments.html) 或 [AWS Direct Connect virtual private gateway associations](https://docs.aws.amazon.com/vpn/latest/s2svpn/how_it_works.html#VPNGateway)。

 **Transit Gateway** 

运行以下命令连接某个中转网关。请将 `VPC_ID` 替换为 VPC 的 ID。请将 `SUBNET_ID1` 和 `SUBNET_ID2` 替换为在上一步中创建的子网的 ID。请将 `TGW_ID` 替换为 TGW 的 ID。

```
aws ec2 create-transit-gateway-vpc-attachment \
    --vpc-id VPC_ID \
    --subnet-ids SUBNET_ID1 SUBNET_ID2 \
    --transit-gateway-id TGW_ID
```

 **虚拟专用网关** 

运行以下命令连接某个中转网关。请将 `VPN_ID` 替换为 VGW 的 ID。请将 `VPC_ID` 替换为 VPC 的 ID。

```
aws ec2 attach-vpn-gateway \
    --vpn-gateway-id VPN_ID \
    --vpc-id VPC_ID
```

### （可选）第 4 步：创建路由表
<a name="_optional_step_4_create_route_table"></a>

您可以修改 VPC 的主路由表，也可以创建自定义路由表。以下步骤将创建一个自定义路由表，其中包含本地节点和容器组 CIDR 的路由。有关更多信息，请参阅[子网路由表](https://docs.aws.amazon.com/vpc/latest/userguide/subnet-route-tables.html)。请将 `VPC_ID` 替换为 VPC 的 ID。

```
aws ec2 create-route-table --vpc-id VPC_ID
```

### 第 5 步：创建本地节点和容器组的路由
<a name="_step_5_create_routes_for_on_premises_nodes_and_pods"></a>

在路由表中创建每个本地远程节点的路由。您可以修改 VPC 的主路由表，也可以使用您在上一步中创建的自定义路由表。

以下示例展示了如何创建本地节点和容器组 CIDR 的路由。这些示例使用中转网关（TGW）将 VPC 连接到本地环境。如果您有多个本地节点和容器组 CIDR，请对每个 CIDR 重复这些步骤。
+ 如果您使用互联网网关或虚拟专用网关（VGW），请将 `--transit-gateway-id` 替换为 `--gateway-id`。
+ 请将 `RT_ID` 替换为在上一步中创建的路由表的 ID。
+ 请将 `REMOTE_NODE_CIDR` 替换为将用于混合节点的 CIDR 范围。
+ 请将 `REMOTE_POD_CIDR` 替换为将在混合节点上运行的容器组的 CIDR 范围。容器组 CIDR 范围对应于容器网络接口（CNI）配置，后者最常使用的是叠加本地网络。有关更多信息，请参阅 [为混合节点配置 CNI](hybrid-nodes-cni.md)。
+ 请将 `TGW_ID` 替换为 TGW 的 ID。

 **远程节点网络** 

```
aws ec2 create-route \
    --route-table-id RT_ID \
    --destination-cidr-block REMOTE_NODE_CIDR \
    --transit-gateway-id TGW_ID
```

 **远程容器组（pod）网络** 

```
aws ec2 create-route \
    --route-table-id RT_ID \
    --destination-cidr-block REMOTE_POD_CIDR \
    --transit-gateway-id TGW_ID
```

### （可选）第 6 步：将子网关联到路由表
<a name="_optional_step_6_associate_subnets_with_route_table"></a>

如果在上一步中创建了自定义路由表，请将您在上一步中创建的每个子网关联到您的自定义路由表。如果您选择修改 VPC 主路由表，则子网会自动关联到 VPC 的主路由表，因此可以跳过此步骤。

为您在之前步骤中创建的每个子网运行以下命令。请将 `RT_ID` 替换为在上一步中创建的路由表。请将 `SUBNET_ID` 替换为子网的 ID。

```
aws ec2 associate-route-table --route-table-id RT_ID --subnet-id SUBNET_ID
```

## 集群安全组配置
<a name="hybrid-nodes-networking-cluster-sg"></a>

EKS 集群安全组需要具有以下访问权限才能进行持续集群操作。当您创建或更新配置了远程节点和容器组（pod）网络的集群时，Amazon EKS 会自动为混合节点创建所需的**入站**安全组规则。默认情况下，安全组允许所有**出站**流量，因此 Amazon EKS 不会自动为混合节点修改集群安全组的**出站**规则。如果要自定义集群安全组，可将流量限制在下表中的规则范围内。


| Type | 协议 | Direction | 端口： | 来源 | 目标 | 用法 | 
| --- | --- | --- | --- | --- | --- | --- | 
|  HTTPS  |  TCP  |  入站  |  443  |  远程节点 CIDR  |  不适用  |  Kubelet 到 Kubernetes API 服务器  | 
|  HTTPS  |  TCP  |  入站  |  443  |  远程容器组 CIDR  |  不适用  |  当 CNI 未使用 NAT 来处理容器组流量时，容器组需要访问 K8s API 服务器的权限。  | 
|  HTTPS  |  TCP  |  出站  |  10250  |  不适用  |  远程节点 CIDR  |  Kubernetes API 服务器到 Kubelet  | 
|  HTTPS  |  TCP  |  出站  |  Webhook 端口  |  不适用  |  远程容器组 CIDR  |  Kubernetes API 服务器到 Webhook（如果在混合节点上运行 Webhook）  | 

**重要**  
 **安全组规则限制**：Amazon EC2 安全组默认最多有 60 条入站规则。如果集群安全组接近此限制，则安全组入站规则可能无法生效。在这种情况下，可能需要手动添加缺少的入站规则。  
 **CIDR 清理责任**：如果您从 EKS 集群中移除远程节点或容器组（pod）网络，EKS 不会自动移除相应的安全组规则。您负责从安全组规则中手动移除未使用的远程节点或容器组（pod）网络。

有关 Amazon EKS 创建的集群安全组的更多信息，请参阅 [查看集群的 Amazon EKS 安全组要求](sec-group-reqs.md)。

### （可选）手动安全组配置
<a name="_optional_manual_security_group_configuration"></a>

如果您需要创建其他安全组或修改自动创建的规则，可以参考以下命令。默认情况下，以下命令会创建一个允许所有出站访问的安全组。您可以将出站访问范围限定为仅包含上述规则。如果您考虑限制出站规则，我们建议您首先全面测试所有应用程序和容器组，然后再将更改后的规则应用于生产集群。
+ 请将第一个命令中的 `SG_NAME` 替换为安全组的名称
+ 请将第一个命令中的 `VPC_ID` 替换为在上一步中创建的 VPC 的 ID
+ 请将第二个命令中的 `SG_ID` 替换为您在第一个命令中创建的安全组的 ID
+ 请将第二个命令中的 `REMOTE_NODE_CIDR` 和 `REMOTE_POD_CIDR` 替换为混合节点和本地网络的相应值。

```
aws ec2 create-security-group \
    --group-name SG_NAME \
    --description "security group for hybrid nodes" \
    --vpc-id VPC_ID
```

```
aws ec2 authorize-security-group-ingress \
    --group-id SG_ID \
    --ip-permissions '[{"IpProtocol": "tcp", "FromPort": 443, "ToPort": 443, "IpRanges": [{"CidrIp": "REMOTE_NODE_CIDR"}, {"CidrIp": "REMOTE_POD_CIDR"}]}]'
```

# 为混合节点准备操作系统
<a name="hybrid-nodes-os"></a>

Bottlerocket、Amazon Linux 2023（AL2023）、Ubuntu 和 RHEL 均已经过持续验证，可用作混合节点的节点操作系统。AWS 仅在 VMware vSphere 环境中支持 Bottlerocket。在 Amazon EC2 之外运行时，AL2023 不属于 AWS Support 计划的范围。AL2023 只能在本地虚拟化环境中使用；有关更多信息，请参阅《Amazon Linux 2023 User Guide》[https://docs.aws.amazon.com/linux/al2023/ug/outside-ec2.html](https://docs.aws.amazon.com/linux/al2023/ug/outside-ec2.html)。AWS 支持混合节点与 Ubuntu 和 RHEL 操作系统的集成，但不提供对操作系统本身的支持。

操作系统的预置和管理由您负责。首次测试混合节点时，最简单的方法是在一台已预置好的主机上运行 Amazon EKS 混合节点功能 CLI (`nodeadm`)。对于生产部署，建议在操作系统映像中包含 `nodeadm` 并将其配置为作为 systemd 服务运行，从而在主机启动时自动将主机加入 Amazon EKS 集群。如果在 vSphere 上将 Bottlerocket 作为节点操作系统使用，则无需使用 `nodeadm`，因为 Bottlerocket 已经包含混合节点功能所需的依赖项，并且会在主机启动时自动连接到您配置的集群。

## 版本兼容性
<a name="_version_compatibility"></a>

下表列举了经过验证可用作混合节点节点操作系统的兼容操作系统版本。如果使用此表中未包含的其他操作系统变体或版本，则混合节点与相关操作系统变体或版本的兼容性不属于 AWS Support 的范围。混合节点与底层基础设施无关，x86 和 ARM 架构均受支持。


| 操作系统 | 版本 | 
| --- | --- | 
|  Amazon Linux  |  Amazon Linux 2023（AL2023）  | 
|  Bottlerocket  |  运行 Kubernetes v1.28 及更高版本的 v1.37.0 及以上版本的 VMware 变体  | 
|  Ubuntu  |  Ubuntu 20.04、Ubuntu 22.04、Ubuntu 24.04  | 
|  Red Hat Enterprise Linux  |  RHEL 8、RHEL 9  | 

## 操作系统注意事项
<a name="_operating_system_considerations"></a>

### General
<a name="_general"></a>
+ Amazon EKS 混合节点功能 CLI (`nodeadm`) 可用于简化混合节点组件和依赖项的安装和配置。您可以在操作系统映像生成管道期间运行 `nodeadm install` 进程，也可以在每台本地主机的运行时中运行该进程。有关 `nodeadm` 将安装的组件的更多信息，请参阅[混合节点 `nodeadm` 参考](hybrid-nodes-nodeadm.md)。
+ 如果您使用本地环境的代理来访问互联网，则安装和升级过程需要完成额外的操作系统配置，才能将软件包管理器配置为使用该代理。有关说明，请参阅[为混合节点功能配置代理](hybrid-nodes-proxy.md)：

### Bottlerocket
<a name="_bottlerocket"></a>
+ 连接 Bottlerocket 节点的步骤和工具与连接其他操作系统节点的步骤不同，将在[连接使用 Bottlerocket 的混合节点](hybrid-nodes-bottlerocket.md)中单独介绍，而不是使用[连接混合节点](hybrid-nodes-join.md)中的步骤。
+ 适用于 Bottlerocket 的步骤不使用混合节点 CLI 工具 `nodeadm`。
+ 仅支持将 Bottlerocket 版本 v1.37.0 及更高版本的 VMware 变体与 EKS 混合节点结合使用。Bottlerocket 的 VMware 变体支持 Kubernetes 版本 1.28 及更高版本。不支持将[其他 Bottlerocket 变体](https://bottlerocket.dev/en/os/1.36.x/concepts/variants)用作混合节点操作系统。注意：Bottlerocket 的 VMware 变体仅支持 x86\$164 架构。

### Containerd
<a name="_containerd"></a>
+ Containerd 是标准的 Kubernetes 容器运行时，也是混合节点以及所有 Amazon EKS 节点计算类型的一个依赖项。Amazon EKS 混合节点功能 CLI (`nodeadm`) 会尝试在 `nodeadm install` 进程中安装 containerd。您可以使用 `--containerd-source` 命令行选项在 `nodeadm install` 运行时中配置 containerd 安装。有效选项为 `none`、`distro`、和 `docker`。如果使用 RHEL，则 `distro` 不是有效选项，并且您可以将 `nodeadm` 配置为按照 Docker 存储库中的 containerd 版本，也可以手动安装 containerd。使用 AL2023 或 Ubuntu 时，`nodeadm` 默认为安装操作系统发行版中的 containerd。如果不希望 nodeadm 安装 containerd，请使用 `--containerd-source none` 选项。

### Ubuntu
<a name="_ubuntu"></a>
+ 如果您使用的是 Ubuntu 24.04，则可能需要更新 containerd 版本或更改 AppArmor 配置，以采用一个可让容器组（pod）正确终止的修复程序，请参阅 [Ubuntu \$12065423](https://bugs.launchpad.net/ubuntu/+source/containerd-app/\+bug/2065423)。需要重启后才能将更改应用于 AppArmor 配置文件。最新版本 Ubuntu 24.04 的包管理器中包含更新的 containerd 版本，其中具有该修复程序（containerd 版本 1.7.19\$1）。

### ARM
<a name="_arm"></a>
+ 如果使用的是 ARM 硬件，则需要带有加密扩展（ARMv8.2\$1crypto）的 ARMv8.2 兼容处理器，才能运行 1.31 版本及更高版本的 EKS kube-proxy 附加组件。Raspberry Pi 5 之前的所有 Raspberry Pi 系统以及基于 Cortex-A72 的处理器都不符合此要求。要解决此问题，可以继续使用 1.30 版本的 EKS kube-proxy 附加组件，直到其延期支持在 2026 年 7 月终止（请参阅 [Kubernetes 发布日历](https://docs.aws.amazon.com/eks/latest/userguide/kubernetes-versions.html)）；也可以使用来自上游的自定义 kube-proxy 映像。
+ Kube-proxy 日志中的以下错误消息表明存在这样的不兼容性问题：

```
Fatal glibc error: This version of Amazon Linux requires a newer ARM64 processor compliant with at least ARM architecture 8.2-a with Cryptographic extensions. On EC2 this is Graviton 2 or later.
```

## 生成操作系统映像
<a name="_building_operating_system_images"></a>

Amazon EKS 提供了[示例 Packer 模板](https://github.com/aws/eks-hybrid/tree/main/example/packer)，您可以使用这些模板来创建包含 `nodeadm` 的操作系统映像，并将其配置为在主机启动时运行。建议使用此过程以避免在每台主机上分别拉取混合节点的依赖项，并自动完成混合节点的引导过程。您可以将示例 Packer 模板与 Ubuntu 22.04、Ubuntu 24.04、RHEL 8 或 RHEL 9 ISO 映像一起使用，并且可以输出以下格式的映像：OVA、Qcow2 或 Raw。

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

在使用示例 Packer 模板之前，必须在运行 Packer 的计算机上安装以下项目。
+ Packer 版本 1.11.0 或更高版本。有关安装 Packer 的说明，请参阅 Packer 文档中的 [Install Packer](https://developer.hashicorp.com/packer/tutorials/docker-get-started/get-started-install-cli)。
+ 如果生成 OVA，则必须已安装 VMware vSphere 插件 1.4.0 或更高版本
+ 如果生成 `Qcow2` 或原始映像，则必须已安装 QEMU 插件版本 1.x

### 设置环境变量
<a name="_set_environment_variables"></a>

在运行此 Packer 生成版本之前，请在运行 Packer 的计算机上设置以下环境变量。

 **General** 

要生成各种操作系统和输出格式的映像，必须设置以下环境变量。


| 环境变量 | 类型 | 说明 | 
| --- | --- | --- | 
|  PKR\$1SSH\$1PASSWORD  |  字符串  |  Packer 使用 `ssh_username` 和 `ssh_password` 变量以在预置时通过 SSH 连接到创建的计算机。这需要与在相应操作系统的 kickstart 文件或 user-data 文件中创建初始用户时使用的密码一致。默认设置为“builder器”或“ubuntu”，具体因操作系统而异。设置密码时，请务必在相应的 `ks.cfg` 或 `user-data` 文件中进行更改以确保一致。  | 
|  ISO\$1URL  |  字符串  |  要使用的 ISO URL。这可以是从服务器下载的 Web 链接，也可以是本地文件的绝对路径  | 
|  ISO\$1CHECKSUM  |  字符串  |  所提供 ISO 的相关校验和。  | 
|  CREDENTIAL\$1PROVIDER  |  字符串  |  混合节点的凭证提供者。SSM 混合激活的有效值为 `ssm`（默认），IAM Roles Anywhere 的有效值为 `iam`  | 
|  K8S\$1VERSION  |  字符串  |  适用于混合节点的 Kubernetes 版本（例如 `1.31`）。有关支持的 Kubernetes 版本，请参阅 [Amazon EKS 支持的版本](https://docs.aws.amazon.com/eks/latest/userguide/kubernetes-versions.html)。  | 
|  NODEADM\$1ARCH  |  字符串  |  适用于 `nodeadm install` 的架构。选择 `amd` 或 `arm`。  | 

 **RHEL** 

如果使用 RHEL，则必须设置以下环境变量。


| 环境变量 | 类型 | 说明 | 
| --- | --- | --- | 
|  RH\$1USERNAME  |  字符串  |  RHEL 订阅管理员用户名  | 
|  RH\$1PASSWORD  |  字符串  |  RHEL 订阅管理器密码  | 
|  RHEL\$1VERSION  |  字符串  |  使用的 Rhel iso 版本。有效值为 `8` 或 `9`。  | 

 **Ubuntu** - 

没有特定于 Ubuntu 的环境变量。

 **vSphere** 

如果构建 VMware vSphere OVA，则必须设置以下环境变量。


| 环境变量 | 类型 | 说明 | 
| --- | --- | --- | 
|  VSPHERE\$1SERVER  |  字符串  |  vSphere 服务器地址  | 
|  VSPHERE\$1USER  |  字符串  |  vSphere 用户名  | 
|  VSPHERE\$1PASSWORD  |  字符串  |  vSphere 密码  | 
|  VSPHERE\$1DATACENTER  |  字符串  |  vSphere 数据中心名称  | 
|  VSPHERE\$1CLUSTER  |  字符串  |  vSphere 集群名称  | 
|  VSPHERE\$1DATASTORE  |  字符串  |  vSphere 数据存储名称  | 
|  VSPHERE\$1NETWORK  |  字符串  |  vSphere 网络名称  | 
|  VSPHERE\$1OUTPUT\$1FOLDER  |  字符串  |  模板的 vSphere 输出文件夹  | 

 **QEMU** 


| 环境变量 | 类型 | 说明 | 
| --- | --- | --- | 
|  PACKER\$1OUTPUT\$1FORMAT  |  字符串  |  QEMU 生成器的输出格式。有效值为 `qcow2` 和 `raw`。  | 

 **验证模版** 

在运行生成的版本之前，请在设置环境变量后使用以下命令验证模板。如果您的模板使用其他名称，请相应替换 `template.pkr.hcl`。

```
packer validate template.pkr.hcl
```

### 生成映像
<a name="_build_images"></a>

使用以下命令生成映像，并使用 `-only` 标志来指定映像的目标和操作系统。如果您的模板使用其他名称，请相应替换 `template.pkr.hcl`。

 **vSphere OVA** 

**注意**  
如果将 RHEL 与 vSphere 结合使用，则需要将 kickstart 文件转换为 OEMDRV 映像，然后将其传递为要用于启动的 ISO。有关更多信息，请参阅 EKS 混合节点 GitHub 存储库中的 [Packer Readme](https://github.com/aws/eks-hybrid/tree/main/example/packer#utilizing-rhel-with-vsphere)。

 **Ubuntu 22.04 OVA** 

```
packer build -only=general-build.vsphere-iso.ubuntu22 template.pkr.hcl
```

 **Ubuntu 24.04 OVA** 

```
packer build -only=general-build.vsphere-iso.ubuntu24 template.pkr.hcl
```

 **RHEL 8 OVA** 

```
packer build -only=general-build.vsphere-iso.rhel8 template.pkr.hcl
```

 **RHEL 9 OVA** 

```
packer build -only=general-build.vsphere-iso.rhel9 template.pkr.hcl
```

 **QEMU** 

**注意**  
如果要为其生成映像的特定主机 CPU 生成与生成器主机不匹配，请参阅 [QEMU](https://www.qemu.org/docs/master/system/qemu-cpu-models.html) 文档以获取与主机 CPU 匹配的名称，并在运行以下命令时将 `-cpu` 标志与该主机 CPU 的名称结合使用。

 **Ubuntu 22.04 Qcow2 / Raw** 

```
packer build -only=general-build.qemu.ubuntu22 template.pkr.hcl
```

 **Ubuntu 24.04 Qcow2 / Raw** 

```
packer build -only=general-build.qemu.ubuntu24 template.pkr.hcl
```

 **RHEL 8 Qcow2 / Raw** 

```
packer build -only=general-build.qemu.rhel8 template.pkr.hcl
```

 **RHEL 9 Qcow2 / Raw** 

```
packer build -only=general-build.qemu.rhel9 template.pkr.hcl
```

### 通过 user-data 传递 nodeadm 配置
<a name="_pass_nodeadm_configuration_through_user_data"></a>

您可以通过 cloud-init 在 user-data 中传递 `nodeadm` 的配置，从而配置混合节点并在主机启动时自动将其连接到 EKS 集群。以下示例演示了如何在将 VMware vSphere 作为混合节点的基础设施时实现这一点。

1. 按照 GitHub 上 [govc readme](https://github.com/vmware/govmomi/blob/main/govc/README.md) 中的说明安装 `govc` CLI。

1. 运行上一节中的 Packer 版本并预置模板后，您可以通过使用以下方法克隆模板来创建多个不同的节点。您必须为要创建的用于混合节点的每个新 VM 克隆该模板。请将以下命令中的变量替换为您的环境的相应值。当您通过 `metadata.yaml` 文件注入 VM 的名称时，以下命令中的 `VM_NAME` 将用作 `NODE_NAME`。

   ```
   govc vm.clone -vm "/PATH/TO/TEMPLATE" -ds="YOUR_DATASTORE" \
       -on=false -template=false -folder=/FOLDER/TO/SAVE/VM "VM_NAME"
   ```

1. 在为每个新 VM 克隆该模板后，为您的 VM 创建一个 `userdata.yaml` 和 `metadata.yaml`。VM 可以共享同一 `userdata.yaml` 和 `metadata.yaml`，并且您将在以下步骤中为每个 VM 填充这些参数。`nodeadm` 配置是在 `userdata.yaml` 的 `write_files` 部分中创建和定义的。以下示例将 AWS SSM 混合激活作为混合节点的本地凭证提供者。有关 `nodeadm` 配置的更多信息，请参阅[混合节点 `nodeadm` 参考](hybrid-nodes-nodeadm.md)。

    **userdata.yaml：**

   ```
   #cloud-config
   users:
     - name: # username for login. Use 'builder' for RHEL or 'ubuntu' for Ubuntu.
       passwd: # password to login. Default is 'builder' for RHEL.
       groups: [adm, cdrom, dip, plugdev, lxd, sudo]
       lock-passwd: false
       sudo: ALL=(ALL) NOPASSWD:ALL
       shell: /bin/bash
   
   write_files:
     - path: /usr/local/bin/nodeConfig.yaml
       permissions: '0644'
       content: |
         apiVersion: node.eks.aws/v1alpha1
         kind: NodeConfig
         spec:
             cluster:
                 name: # Cluster Name
                 region: # AWS region
             hybrid:
                 ssm:
                     activationCode: # Your ssm activation code
                     activationId: # Your ssm activation id
   
   runcmd:
     - /usr/local/bin/nodeadm init -c file:///usr/local/bin/nodeConfig.yaml >> /var/log/nodeadm-init.log 2>&1
   ```

    **metadata.yaml：**

   为您的环境创建一个 `metadata.yaml`。保留文件中的 `"$NODE_NAME"` 变量格式，因为这将使用后续步骤中的值填充。

   ```
   instance-id: "$NODE_NAME"
   local-hostname: "$NODE_NAME"
   network:
     version: 2
     ethernets:
       nics:
         match:
           name: ens*
         dhcp4: yes
   ```

1. 使用以下命令将 `userdata.yaml` 和 `metadata.yaml` 文件添加为 `gzip+base64` 字符串。应为要创建的每个 VM 运行以下命令。请将 `VM_NAME` 替换为要更新的 VM 的名称。

   ```
   export NODE_NAME="VM_NAME"
   export USER_DATA=$(gzip -c9 <userdata.yaml | base64)
   
   govc vm.change -dc="YOUR_DATASTORE" -vm "$NODE_NAME" -e guestinfo.userdata="${USER_DATA}"
   govc vm.change -dc="YOUR_DATASTORE" -vm "$NODE_NAME" -e guestinfo.userdata.encoding=gzip+base64
   
   envsubst '$NODE_NAME' < metadata.yaml > metadata.yaml.tmp
   export METADATA=$(gzip -c9 <metadata.yaml.tmp | base64)
   
   govc vm.change -dc="YOUR_DATASTORE" -vm "$NODE_NAME" -e guestinfo.metadata="${METADATA}"
   govc vm.change -dc="YOUR_DATASTORE" -vm "$NODE_NAME" -e guestinfo.metadata.encoding=gzip+base64
   ```

1. 将新 VM 开机，这时应会自动连接到您配置的 EKS 集群。

   ```
   govc vm.power -on "${NODE_NAME}"
   ```

# 准备用于混合节点的凭证
<a name="hybrid-nodes-creds"></a>

Amazon EKS 混合节点功能使用由 AWS SSM 混合激活或 AWS IAM Roles Anywhere 预置的临时 IAM 凭证，来进行 Amazon EKS 集群身份验证。您必须使用 AWS SSM 混合激活，或将 AWS IAM Roles Anywhere 与 Amazon EKS 混合节点功能 CLI (`nodeadm`) 配合使用。您不应同时使用 AWS SSM 混合激活和 AWS IAM Roles Anywhere。如果您没有具有证书颁发机构（CA）的现有公钥基础设施（PKI）和本地环境的证书，我们建议您使用 AWS SSM 混合激活。如果您在确实具有现有的 PKI 和本地证书，请使用 AWS IAM Roles Anywhere。

## 混合节点 IAM 角色
<a name="hybrid-nodes-role"></a>

您必须首先为您的混合节点凭证创建一个将与 AWS SSM 混合激活或 AWS IAM Roles Anywhere 结合使用的 IAM 角色，然后才能将混合节点连接到 Amazon EKS 集群。创建集群后，您将使用此角色和某个 Amazon EKS 访问条目或 `aws-auth` ConfigMap 条目，来将该 IAM 角色映射到 Kubernetes 基于角色的访问控制（RBAC）。有关将混合节点 IAM 角色与 Kubernetes RBAC 关联的更多信息，请参阅[准备混合节点的集群访问权限](hybrid-nodes-cluster-prep.md)。

混合节点 IAM 角色必须具有以下权限。
+ 需为 `nodeadm` 配置权限，使其能够调用 `eks:DescribeCluster` 操作，以获取待接入混合节点的目标集群相关信息。若未启用 `eks:DescribeCluster` 操作权限，则必须在传入 `nodeadm init` 命令的节点配置中，手动指定 Kubernetes API 端点、集群 CA 证书包以及服务 IPv4 CIDR。
+ 需为 `nodeadm` 配置权限，使其能够调用 `eks:ListAccessEntries` 操作，以列出待接入混合节点的目标集群中的访问条目。若未启用 `eks:ListAccessEntries` 操作权限，则在执行 `nodeadm init` 命令时，必须传入 `--skip cluster-access-validation` 标记。
+ 如 [AmazonEC2ContainerRegistryPullOnly](https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AmazonEC2ContainerRegistryPullOnly.html) 策略所定义，kubelet 使用来自 Amazon Elastic Container Registry（Amazon ECR）的容器映像的权限。
+ 如果使用 AWS SSM，则需要 `nodeadm init` 的权限以使用 [https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AmazonSSMManagedInstanceCore.html](https://docs.aws.amazon.com/aws-managed-policy/latest/reference/AmazonSSMManagedInstanceCore.html) 策略中定义的 AWS SSM 混合激活。
+ 如果使用 AWS SSM，则为使用 `nodeadm uninstall` 的 `ssm:DeregisterManagedInstance` 操作和 `ssm:DescribeInstanceInformation` 操作注销实例的权限。
+ （可选）Amazon EKS 容器组身份代理使用 `eks-auth:AssumeRoleForPodIdentity` 操作检索容器组凭证的权限。

## 设置 AWS SSM 混合激活
<a name="hybrid-nodes-ssm"></a>

必须首先创建并配置一个混合节点 IAM 角色，然后才能设置 AWS SSM 混合激活。有关更多信息，请参阅 [创建混合节点 IAM 角色](#hybrid-nodes-create-role)。按照《AWS Systems Manager 用户指南》中[创建混合激活以将节点注册到 Systems Manager](https://docs.aws.amazon.com/systems-manager/latest/userguide/hybrid-activation-managed-nodes.html) 部分的说明，为您的混合节点创建一个 AWS SSM 混合激活。将主机作为混合节点注册到 Amazon EKS 集群时，您收到的激活码和 ID 将与 `nodeadm` 结合使用。在为混合节点创建并准备好了 Amazon EKS 集群后，您可以稍后再回到此步骤。

**重要**  
根据您创建激活的方式，Systems Manager 立即将激活码和 ID 返回到控制台或命令窗口。复制此信息并将其存储在安全位置。如果您离开该控制台或关闭命令窗口，可能会丢失此信息。如果您丢失对应信息，则必须创建一个新激活。

默认情况下，AWS SSM 混合激活会处于活动状态 24 小时。您也可以用时间戳格式（例如 `2024-08-01T00:00:00`）来指定 `--expiration-date` 何时创建混合激活。当凭证提供者为 AWS SSM 时，混合节点的节点名称将不可配置，而是由 AWS SSM 自动生成的。您可以在 AWS Systems Manager 控制台中的 Fleet Manager 下查看和管理 AWS SSM 托管式实例。每个账户在每个 AWS 区域最多可以免费注册 1000 个标准[混合激活节点](https://docs.aws.amazon.com/systems-manager/latest/userguide/activations.html)。但是，注册超过 1000 个混合节点需要激活高级实例套餐。使用高级实例套餐将会产生费用，并且该费用未包含在 [Amazon EKS 混合节点功能](https://aws.amazon.com/eks/pricing/)定价中。有关更多信息，请参阅 [AWS Systems Manager 定价](https://aws.amazon.com/systems-manager/pricing/)。

请参阅以下示例，了解如何使用混合节点 IAM 角色创建 AWS SSM 混合激活。将 AWS SSM 混合激活作为混合节点凭证使用时，混合节点名称的格式将为 `mi-012345678abcdefgh`，AWS SSM 预置的临时凭证有效期为 1 小时。当凭证提供者为 AWS SSM 时，您无法更改节点名称或凭证有效期。临时凭证将由 AWS SSM 自动轮换，但此轮换不会影响节点或应用程序的状态。

我们建议您为每个 EKS 集群使用一个 AWS SSM 混合激活来限制混合节点 IAM 角色的 AWS SSM `ssm:DeregisterManagedInstance` 权限，使其只能注销与您的 AWS SSM 混合激活关联的实例。本页中的示例使用了一个具有 EKS 集群 ARN 的标签，该标签可用于将您的 AWS SSM 混合激活映射到该 EKS 集群。您也可以根据自己的权限边界和要求，使用自己偏好的标签和方法来确定 AWS SSM 权限的范围。以下命令中的 `REGISTRATION_LIMIT` 选项是一个整型，用于限制可以使用 AWS SSM 混合激活的计算机数量（例如 `10`）

```
aws ssm create-activation \
     --region AWS_REGION \
     --default-instance-name eks-hybrid-nodes \
     --description "Activation for EKS hybrid nodes" \
     --iam-role AmazonEKSHybridNodesRole \
     --tags Key=EKSClusterARN,Value=arn:aws:eks:AWS_REGION:AWS_ACCOUNT_ID:cluster/CLUSTER_NAME \
     --registration-limit REGISTRATION_LIMIT
```

请参阅[创建混合激活以将节点注册到 Systems Manager](https://docs.aws.amazon.com/systems-manager/latest/userguide/hybrid-activation-managed-nodes.html) 部分的说明，以详细了解有关 AWS SSM 混合激活的可用配置设置。

## 设置 AWS IAM Roles Anywhere
<a name="hybrid-nodes-iam-roles-anywhere"></a>

按照《IAM Roles Anywhere 用户指南》中 [Getting started with IAM Roles Anywhere](https://docs.aws.amazon.com/rolesanywhere/latest/userguide/getting-started.html) 部分的说明，设置将用作混合节点 IAM 角色的临时 IAM 凭证的信任锚和配置文件。创建配置文件时，您可以仅创建配置文件而不添加任何角色。您可以首先创建此配置文件，然后返回这些步骤来创建混合节点 IAM 角色，最后再将创建的角色添加到您的配置文件。您也可以使用本页后面的 AWS CloudFormation 步骤来完成混合节点的 IAM Roles Anywhere 设置。

将混合节点 IAM 角色添加到配置文件时，请在 AWS IAM Roles Anywhere 控制台中**编辑配置文件**页面底部的**自定义角色**会话名称面板中，选择**接受自定义角色会话名称**。这对应于 `CreateProfile` API 的 [acceptRoleSessionName](https://docs.aws.amazon.com/rolesanywhere/latest/APIReference/API_CreateProfile.html#rolesanywhere-CreateProfile-request-acceptRoleSessionName) 字段。选择此选项后，您可以在引导阶段传递到 `nodeadm` 的配置中为混合节点提供自定义节点名称。在 `nodeadm init` 过程中必须传递一个自定义节点名称。创建配置文件后，您可以通过更新配置文件来接受自定义角色会话名称。

您可以通过 AWS IAM Roles Anywhere 配置文件的 [durationSeconds](https://docs.aws.amazon.com/rolesanywhere/latest/userguide/authentication-create-session#credentials-object) 字段，来配置 AWS IAM Roles Anywhere 的凭证有效期。默认有效期为 1 小时，最长可为 12 小时。混合节点 IAM 角色的 `MaxSessionDuration` 设置必须大于 AWS IAM Roles Anywhere 配置文件中的 `durationSeconds` 设置。有关 `MaxSessionDuration` 的更多信息，请参阅 [UpdateRole API 文档](https://docs.aws.amazon.com/systems-manager/latest/APIReference/API_UpdateRole.html)。

您通过证书颁发机构（CA）为每台计算机生成的证书和密钥必须放置在每个混合节点的 `/etc/iam/pki` 目录中，并且证书的文件名必须为 `server.pem`，密钥的文件名必须为 `server.key`。

## 创建混合节点 IAM 角色
<a name="hybrid-nodes-create-role"></a>

要运行本节中的步骤，使用 AWS 控制台或 AWS CLI 的 IAM 主体必须具有以下权限。
+  `iam:CreatePolicy` 
+  `iam:CreateRole` 
+  `iam:AttachRolePolicy` 
+ 如果使用的是 AWS IAM Roles Anywhere
  +  `rolesanywhere:CreateTrustAnchor` 
  +  `rolesanywhere:CreateProfile` 
  +  `iam:PassRole` 

### AWS CloudFormation
<a name="hybrid-nodes-creds-cloudformation"></a>

安装并配置 AWS CLI（如果尚未执行此操作）。请参阅[安装或更新到最新版本的 AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)。

 **AWS SSM 混合激活的步骤** 

CloudFormation 堆栈将创建具有上述权限的混合节点 IAM 角色。CloudFormation 模板不会创建 AWS SSM 混合激活。

1. 下载适用于混合节点的 AWS SSM CloudFormation 模板：

   ```
   curl -OL 'https://raw.githubusercontent.com/aws/eks-hybrid/refs/heads/main/example/hybrid-ssm-cfn.yaml'
   ```

1. 使用以下选项创建 `cfn-ssm-parameters.json`：

   1. 将 `ROLE_NAME` 替换为混合节点 IAM 角色的名称。如果您未指定名称，则默认情况下 CloudFormation 模板将使用 `AmazonEKSHybridNodesRole` 作为其创建的角色的名称。

   1. 请将 `TAG_KEY` 替换为您在创建 AWS SSM 混合激活时使用的 AWS SSM 资源标签键。在条件中使用标签键和标签值组合，从而让 `ssm:DeregisterManagedInstance` 仅允许混合节点 IAM 角色注销与您的 AWS SSM 混合激活关联的 AWS SSM 托管式实例。在 CloudFormation 模板中，`TAG_KEY` 默认为 `EKSClusterARN`。

   1. 请将 `TAG_VALUE` 替换为您在创建 AWS SSM 混合激活时使用的 AWS SSM 资源标签值。在条件中使用标签键和标签值组合，从而让 `ssm:DeregisterManagedInstance` 仅允许混合节点 IAM 角色注销与您的 AWS SSM 混合激活关联的 AWS SSM 托管式实例。如果您使用 `EKSClusterARN` 的默认值 `TAG_KEY`，则请将 EKS 集群 ARN 传递为 `TAG_VALUE`。EKS 集群 ARN 的格式为 ` arn:aws:eks:AWS_REGION:AWS_ACCOUNT_ID:cluster/CLUSTER_NAME`。

      ```
      {
        "Parameters": {
          "RoleName": "ROLE_NAME",
          "SSMDeregisterConditionTagKey": "TAG_KEY",
          "SSMDeregisterConditionTagValue": "TAG_VALUE"
        }
      }
      ```

1. 部署 CloudFormation 堆栈。请将 `STACK_NAME` 替换 CloudFormation 堆栈的名称。

   ```
   aws cloudformation deploy \
       --stack-name STACK_NAME \
       --template-file hybrid-ssm-cfn.yaml \
       --parameter-overrides file://cfn-ssm-parameters.json \
       --capabilities CAPABILITY_NAMED_IAM
   ```

 **AWS IAM Roles Anywhere 的步骤** 

CloudFormation 堆栈会使用您配置的证书颁发机构（CA）来创建 AWS IAM Roles Anywhere 信任锚，创建 AWS IAM Roles Anywhere 配置文件，并创建具有前文所述权限的混合节点 IAM 角色。

1. 设置证书颁发机构（CA）

   1. 要使用 AWS 私有 CA 资源，请打开 [AWS Private Certificate Authority 控制台](https://console.aws.amazon.com/acm-pca/home)。按照 [AWS Private CA 用户指南](https://docs.aws.amazon.com/privateca/latest/userguide/PcaWelcome.html)中的说明进行操作。

   1. 要使用外部 CA，请按照相关 CA 提供的说明进行操作。您需要在后续步骤中提供证书正文。

   1. 公有 CA 颁发的证书不能用作信任锚。

1. 下载适用于混合节点的 AWS IAM Roles Anywhere CloudFormation 模板

   ```
   curl -OL 'https://raw.githubusercontent.com/aws/eks-hybrid/refs/heads/main/example/hybrid-ira-cfn.yaml'
   ```

1. 使用以下选项创建 `cfn-iamra-parameters.json`：

   1. 将 `ROLE_NAME` 替换为混合节点 IAM 角色的名称。如果您未指定名称，则默认情况下 CloudFormation 模板将使用 `AmazonEKSHybridNodesRole` 作为其创建的角色的名称。

   1. 请将 `CERT_ATTRIBUTE` 替换为用于唯一标识主机的每台计算机的证书属性。使用的证书属性必须与您在将混合节点连接到集群时用于 `nodeadm` 配置的 nodeName 一致。有关更多信息，请参阅[混合节点 `nodeadm` 参考](hybrid-nodes-nodeadm.md)。默认情况下，CloudFormation 模板将 `${aws:PrincipalTag/x509Subject/CN}` 作为 `CERT_ATTRIBUTE`，这将对应于每台计算机的证书的 CN 字段。您也可以将 `$(aws:PrincipalTag/x509SAN/Name/CN}` 传递为您的 `CERT_ATTRIBUTE`。

   1. 请将 `CA_CERT_BODY` 替换为 CA 的证书正文，不带换行符。`CA_CERT_BODY` 必须采用隐私增强邮件（PEM）格式。如果您具有 PEM 格式的 CA 证书，请在将 CA 证书正文放入 `cfn-iamra-parameters.json` 文件之前移除换行符和 BEGIN CERTIFICATE 和 END CERTIFICATE 行。

      ```
      {
        "Parameters": {
          "RoleName": "ROLE_NAME",
          "CertAttributeTrustPolicy": "CERT_ATTRIBUTE",
          "CABundleCert": "CA_CERT_BODY"
        }
      }
      ```

1. 部署 CloudFormation 模板。请将 `STACK_NAME` 替换 CloudFormation 堆栈的名称。

   ```
   aws cloudformation deploy \
       --stack-name STACK_NAME \
       --template-file hybrid-ira-cfn.yaml \
       --parameter-overrides file://cfn-iamra-parameters.json
       --capabilities CAPABILITY_NAMED_IAM
   ```

### AWS CLI
<a name="hybrid-nodes-creds-awscli"></a>

安装并配置 AWS CLI（如果尚未执行此操作）。请参阅[安装或更新到最新版本的 AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html)。

 **创建 EKS 描述集群策略** 

1. 使用以下内容创建名为 `eks-describe-cluster-policy.json` 的文件：

   ```
   {
       "Version":"2012-10-17",		 	 	 
       "Statement": [
           {
               "Effect": "Allow",
               "Action": [
                   "eks:DescribeCluster"
               ],
               "Resource": "*"
           }
       ]
   }
   ```

1. 使用以下命令创建此策略：

   ```
   aws iam create-policy \
       --policy-name EKSDescribeClusterPolicy \
       --policy-document file://eks-describe-cluster-policy.json
   ```

 **AWS SSM 混合激活的步骤** 

1. 使用以下内容创建名为 `eks-hybrid-ssm-policy.json` 的文件。此策略将授予对 `ssm:DescribeInstanceInformation` 和 `ssm:DeregisterManagedInstance` 这两个操作的权限。此策略将根据您在信任策略中指定的资源标签，将 `ssm:DeregisterManagedInstance` 权限范围限定为与您的 AWS SSM 混合激活关联的 AWS SSM 托管式实例。

   1. 请将 `AWS_REGION` 替换为您的 AWS SSM 混合激活的 AWS 区域。

   1. 将 `AWS_ACCOUNT_ID` 替换为您的AWS账户 ID。

   1. 请将 `TAG_KEY` 替换为您在创建 AWS SSM 混合激活时使用的 AWS SSM 资源标签键。在条件中使用标签键和标签值组合，从而让 `ssm:DeregisterManagedInstance` 仅允许混合节点 IAM 角色注销与您的 AWS SSM 混合激活关联的 AWS SSM 托管式实例。在 CloudFormation 模板中，`TAG_KEY` 默认为 `EKSClusterARN`。

   1. 请将 `TAG_VALUE` 替换为您在创建 AWS SSM 混合激活时使用的 AWS SSM 资源标签值。在条件中使用标签键和标签值组合，从而让 `ssm:DeregisterManagedInstance` 仅允许混合节点 IAM 角色注销与您的 AWS SSM 混合激活关联的 AWS SSM 托管式实例。如果您使用 `EKSClusterARN` 的默认值 `TAG_KEY`，则请将 EKS 集群 ARN 传递为 `TAG_VALUE`。EKS 集群 ARN 的格式为 ` arn:aws:eks:AWS_REGION:AWS_ACCOUNT_ID:cluster/CLUSTER_NAME`。

      ```
      {
          "Version":"2012-10-17",		 	 	 
          "Statement": [
              {
                  "Effect": "Allow",
                  "Action": "ssm:DescribeInstanceInformation",
                  "Resource": "*"
              },
              {
                  "Effect": "Allow",
                  "Action": "ssm:DeregisterManagedInstance",
                  "Resource": "arn:aws:ssm:us-east-1:123456789012:managed-instance/*",
                  "Condition": {
                      "StringEquals": {
                          "ssm:resourceTag/TAG_KEY": "TAG_VALUE"
                      }
                  }
              }
          ]
      }
      ```

1. 使用以下命令创建此策略

   ```
   aws iam create-policy \
       --policy-name EKSHybridSSMPolicy \
       --policy-document file://eks-hybrid-ssm-policy.json
   ```

1. 创建一个名为 `eks-hybrid-ssm-trust.json`的文件。请将 `AWS_REGION` 替换为您的 AWS SSM 混合激活所在的 AWS 区域，将 `AWS_ACCOUNT_ID` 替换为您的 AWS 账户 ID。

   ```
   {
      "Version":"2012-10-17",		 	 	 
      "Statement":[
         {
            "Sid":"",
            "Effect":"Allow",
            "Principal":{
               "Service":"ssm.amazonaws.com"
            },
            "Action":"sts:AssumeRole",
            "Condition":{
               "StringEquals":{
                  "aws:SourceAccount":"123456789012"
               },
               "ArnEquals":{
                  "aws:SourceArn":"arn:aws:ssm:us-east-1:123456789012:*"
               }
            }
         }
      ]
   }
   ```

1. 使用以下命令创建此角色。

   ```
   aws iam create-role \
       --role-name AmazonEKSHybridNodesRole \
       --assume-role-policy-document file://eks-hybrid-ssm-trust.json
   ```

1. 附加您在之前步骤中创建的 `EKSDescribeClusterPolicy` 和 `EKSHybridSSMPolicy`。将 `AWS_ACCOUNT_ID` 替换为您的AWS账户 ID。

   ```
   aws iam attach-role-policy \
       --role-name AmazonEKSHybridNodesRole \
       --policy-arn arn:aws:iam::AWS_ACCOUNT_ID:policy/EKSDescribeClusterPolicy
   ```

   ```
   aws iam attach-role-policy \
       --role-name AmazonEKSHybridNodesRole \
       --policy-arn arn:aws:iam::AWS_ACCOUNT_ID:policy/EKSHybridSSMPolicy
   ```

1. 附加 `AmazonEC2ContainerRegistryPullOnly` 和 `AmazonSSMManagedInstanceCore` AWS 托管式策略。

   ```
   aws iam attach-role-policy \
       --role-name AmazonEKSHybridNodesRole \
       --policy-arn arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryPullOnly
   ```

   ```
   aws iam attach-role-policy \
       --role-name AmazonEKSHybridNodesRole \
       --policy-arn arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
   ```

 **AWS IAM Roles Anywhere 的步骤** 

要使用 AWS IAM Roles Anywhere，您必须在创建混合节点 IAM 角色之前设置 AWS IAM Roles Anywhere信任锚。有关说明，请参阅[设置 AWS IAM Roles Anywhere](#hybrid-nodes-iam-roles-anywhere)：

1. 创建一个名为 `eks-hybrid-iamra-trust.json`的文件。请将 `TRUST_ANCHOR ARN` 替换为您在“[设置 AWS IAM Roles Anywhere](#hybrid-nodes-iam-roles-anywhere)”步骤中创建的信任锚的 ARN。只有当角色会话名称与混合节点上安装的 x509 证书中的 CN 一致时，此信任策略中的条件才会将 AWS IAM Roles Anywhere 代入混合节点 IAM 角色的权限范围限定为仅交换临时 IAM 凭证。您也可以使用其他证书属性来唯一标识节点。您在信任策略中使用的证书属性必须与您在 `nodeadm` 配置中设置的 `nodeName` 对应。有关更多信息，请参阅[混合节点 `nodeadm` 参考](hybrid-nodes-nodeadm.md)。

   ```
   {
       "Version":"2012-10-17",		 	 	 
       "Statement": [
           {
               "Effect": "Allow",
               "Principal": {
                   "Service": "rolesanywhere.amazonaws.com"
               },
               "Action": [
                   "sts:TagSession",
                   "sts:SetSourceIdentity"
               ],
               "Condition": {
                   "StringEquals": {
                       "aws:PrincipalTag/x509Subject/CN": "${aws:PrincipalTag/x509Subject/CN}"
                   },
                   "ArnEquals": {
                       "aws:SourceArn": "arn:aws:rolesanywhere:us-east-1:123456789012:trust-anchor/TA_ID"
                   }
               }
           },
           {
               "Effect": "Allow",
               "Principal": {
                   "Service": "rolesanywhere.amazonaws.com"
               },
               "Action": "sts:AssumeRole",
               "Condition": {
                   "StringEquals": {
                       "sts:RoleSessionName": "${aws:PrincipalTag/x509Subject/CN}",
                       "aws:PrincipalTag/x509Subject/CN": "${aws:PrincipalTag/x509Subject/CN}"
                   },
                   "ArnEquals": {
                       "aws:SourceArn": "arn:aws:rolesanywhere:us-east-1:123456789012:trust-anchor/TA_ID"
                   }
               }
           }
       ]
   }
   ```

1. 使用以下命令创建此角色。

   ```
   aws iam create-role \
       --role-name AmazonEKSHybridNodesRole \
       --assume-role-policy-document file://eks-hybrid-iamra-trust.json
   ```

1. 附加您在之前步骤中创建的 `EKSDescribeClusterPolicy`。将 `AWS_ACCOUNT_ID` 替换为您的AWS账户 ID。

   ```
   aws iam attach-role-policy \
       --role-name AmazonEKSHybridNodesRole \
       --policy-arn arn:aws:iam::AWS_ACCOUNT_ID:policy/EKSDescribeClusterPolicy
   ```

1. 附加 `AmazonEC2ContainerRegistryPullOnly` AWS 托管式策略

   ```
   aws iam attach-role-policy \
       --role-name AmazonEKSHybridNodesRole \
       --policy-arn arn:aws:iam::aws:policy/AmazonEC2ContainerRegistryPullOnly
   ```

### AWS 管理控制台
<a name="hybrid-nodes-creds-console"></a>

 **创建 EKS 描述集群策略** 

1. 打开 [Amazon IAM 控制台](https://console.aws.amazon.com/iam/home) 

1. 在左侧导航窗格中，选择 **Policies（策略）**。

1. 在**策略**页面上，选择**创建策略**。

1. 在“指定权限”页面的“选择服务”面板中，选择 EKS。

   1. 筛选 **DescribeCluster** 的操作，然后选择 **DescribeCluster** 读取操作。

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

1. 在**检查并创建**页面上

   1. 输入策略的**策略名称**，如 `EKSDescribeClusterPolicy`。

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

 **AWS SSM 混合激活的步骤** 

1. 打开 [Amazon IAM 控制台](https://console.aws.amazon.com/iam/home) 

1. 在左侧导航窗格中，选择 **Policies（策略）**。

1. 在**策略**页面上，选择**创建策略**。

1. 在**指定权限**页面右上角的**策略编辑器**导航中，选择 **JSON**。粘贴以下代码段。请将 `AWS_REGION` 替换为您的 AWS SSM 混合激活所在的 AWS 区域，并将 `AWS_ACCOUNT_ID` 替换为您的 AWS 账户 ID。请将 `TAG_KEY` 和 `TAG_VALUE` 替换为您在创建 AWS SSM 混合激活时使用的 AWS SSM 资源标签键。

   ```
   {
       "Version":"2012-10-17",		 	 	 
       "Statement": [
           {
               "Effect": "Allow",
               "Action": "ssm:DescribeInstanceInformation",
               "Resource": "*"
           },
           {
               "Effect": "Allow",
               "Action": "ssm:DeregisterManagedInstance",
               "Resource": "arn:aws:ssm:us-east-1:123456789012:managed-instance/*",
               "Condition": {
                   "StringEquals": {
                       "ssm:resourceTag/TAG_KEY": "TAG_VALUE"
                   }
               }
           }
       ]
   }
   ```

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

1. 在**检查并创建**页面上，

   1. 输入策略的**策略**名称，如 `EKSHybridSSMPolicy` 

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

1. 在左侧导航窗格中，选择 **Roles**（角色）。

1. 在 **Roles**（角色）页面上，选择 **Create role**（创建角色）。

1. 在 **Select trusted entity**（选择受信任的实体）页面上，请执行以下操作：

   1. 在**可信实体类型**部分中，选择**自定义信任策略**。将以下策略复制粘贴到自定义信任策略编辑器中。请将 `AWS_REGION` 替换为您的 AWS SSM 混合激活所在的 AWS 区域，将 `AWS_ACCOUNT_ID` 替换为您的 AWS 账户 ID。

      ```
      {
         "Version":"2012-10-17",		 	 	 
         "Statement":[
            {
               "Sid":"",
               "Effect":"Allow",
               "Principal":{
                  "Service":"ssm.amazonaws.com"
               },
               "Action":"sts:AssumeRole",
               "Condition":{
                  "StringEquals":{
                     "aws:SourceAccount":"123456789012"
                  },
                  "ArnEquals":{
                     "aws:SourceArn":"arn:aws:ssm:us-east-1:123456789012:*"
                  }
               }
            }
         ]
      }
      ```

   1. 选择下一步。

1. 在**添加权限**页面上，附加自定义策略或执行以下操作：

   1. 在**筛选策略**对话框中，输入 `EKSDescribeClusterPolicy` 或您上面创建的策略的名称。选中搜索结果中您的策略左侧的复选框。

   1. 在**筛选策略**对话框中，输入 `EKSHybridSSMPolicy` 或您上面创建的策略的名称。选中搜索结果中您的策略左侧的复选框。

   1. 在 **Filter policies (筛选器策略)** 框中，输入 `AmazonEC2ContainerRegistryPullOnly`。选中搜索结果中 `AmazonEC2ContainerRegistryPullOnly` 左侧的复选框。

   1. 在 **Filter policies (筛选器策略)** 框中，输入 `AmazonSSMManagedInstanceCore`。选中搜索结果中 `AmazonSSMManagedInstanceCore` 左侧的复选框。

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

1. 在 **Name, review, and create**（命名、查看和创建）页面中，请执行以下操作：

   1. 对于 **Role name**（角色名称），请为角色输入唯一名称，例如 `AmazonEKSHybridNodesRole`。

   1. 对于 **Description**（说明），请将当前文本替换为描述性文本，例如 `Amazon EKS - Hybrid Nodes role`。

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

 **AWS IAM Roles Anywhere 的步骤** 

要使用 AWS IAM Roles Anywhere，您必须在创建混合节点 IAM 角色之前设置 AWS IAM Roles Anywhere信任锚。有关说明，请参阅[设置 AWS IAM Roles Anywhere](#hybrid-nodes-iam-roles-anywhere)：

1. 打开 [Amazon IAM 控制台](https://console.aws.amazon.com/iam/home) 

1. 在左侧导航窗格中，选择 **Roles**（角色）。

1. 在 **Roles**（角色）页面上，选择 **Create role**（创建角色）。

1. 在 **Select trusted entity**（选择受信任的实体）页面上，请执行以下操作：

   1. 在**可信实体类型**部分中，选择**自定义信任策略**。将以下策略复制粘贴到自定义信任策略编辑器中。请将 `TRUST_ANCHOR ARN` 替换为您在“[设置 AWS IAM Roles Anywhere](#hybrid-nodes-iam-roles-anywhere)”步骤中创建的信任锚的 ARN。只有当角色会话名称与混合节点上安装的 x509 证书中的 CN 一致时，此信任策略中的条件才会将 AWS IAM Roles Anywhere 代入混合节点 IAM 角色的权限范围限定为仅交换临时 IAM 凭证。您也可以使用其他证书属性来唯一标识节点。您在信任策略中使用的证书属性必须与您在 nodeadm 配置中设置的 nodeName 对应。有关更多信息，请参阅[混合节点 `nodeadm` 参考](hybrid-nodes-nodeadm.md)。

      ```
      {
          "Version":"2012-10-17",		 	 	 
          "Statement": [
              {
                  "Effect": "Allow",
                  "Principal": {
                      "Service": "rolesanywhere.amazonaws.com"
                  },
                  "Action": [
                      "sts:TagSession",
                      "sts:SetSourceIdentity"
                  ],
                  "Condition": {
                      "StringEquals": {
                          "aws:PrincipalTag/x509Subject/CN": "${aws:PrincipalTag/x509Subject/CN}"
                      },
                      "ArnEquals": {
                          "aws:SourceArn": "arn:aws:rolesanywhere:us-east-1:123456789012:trust-anchor/TA_ID"
                      }
                  }
              },
              {
                  "Effect": "Allow",
                  "Principal": {
                      "Service": "rolesanywhere.amazonaws.com"
                  },
                  "Action": "sts:AssumeRole",
                  "Condition": {
                      "StringEquals": {
                          "sts:RoleSessionName": "${aws:PrincipalTag/x509Subject/CN}",
                          "aws:PrincipalTag/x509Subject/CN": "${aws:PrincipalTag/x509Subject/CN}"
                      },
                      "ArnEquals": {
                          "aws:SourceArn": "arn:aws:rolesanywhere:us-east-1:123456789012:trust-anchor/TA_ID"
                      }
                  }
              }
          ]
      }
      ```

   1. 选择下一步。

1. 在**添加权限**页面上，附加自定义策略或执行以下操作：

   1. 在**筛选策略**对话框中，输入 `EKSDescribeClusterPolicy` 或您上面创建的策略的名称。选中搜索结果中您的策略左侧的复选框。

   1. 在 **Filter policies (筛选器策略)** 框中，输入 `AmazonEC2ContainerRegistryPullOnly`。选中搜索结果中 `AmazonEC2ContainerRegistryPullOnly` 左侧的复选框。

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

1. 在 **Name, review, and create**（命名、查看和创建）页面中，请执行以下操作：

   1. 对于 **Role name**（角色名称），请为角色输入唯一名称，例如 `AmazonEKSHybridNodesRole`。

   1. 对于 **Description**（说明），请将当前文本替换为描述性文本，例如 `Amazon EKS - Hybrid Nodes role`。

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

# 创建具有混合节点的 Amazon EKS 集群
<a name="hybrid-nodes-cluster-create"></a>

本主题概述了创建启用混合节点功能的 Amazon EKS 集群时可用的选项，并介绍了相关注意事项。EKS 混合节点功能提供的 [Kubernetes 版本支持](https://docs.aws.amazon.com/eks/latest/userguide/kubernetes-versions.html)与具有云端节点的 Amazon EKS 集群相同，包括标准和扩展支持。

如果您不计划使用 EKS 混合节点功能，请参阅有关 Amazon EKS 创建集群的主文档：[创建一个 Amazon EKS 集群。](create-cluster.md)。

## 先决条件
<a name="hybrid-nodes-cluster-create-prep"></a>
+ 已完成[混合节点的先决条件设置](hybrid-nodes-prereqs.md)。在创建启用混合节点功能的集群之前，必须确定本地节点和可选的容器组 CIDR，根据 EKS 要求和混合节点要求创建 VPC 和子网，并且具有包含本地入站规则和（可选）容器组 CIDR 的安全组。有关这些先决条件的更多信息，请参阅[准备混合节点的联网](hybrid-nodes-networking.md)。
+ 已在您的设备上安装并配置了最新版本的 AWS 命令行界面（AWS CLI）。要查看当前版本，请使用 `aws --version`。yum、apt-get 或适用于 macOS 的 Homebrew 等软件包管理器通常比 AWS CLI 的最新版本落后几个版本。要安装最新版本，请参阅《AWS 命令行界面用户指南》中的[安装或更新到最新版本的 AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html) 和[配置 AWS CLI 设置](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-quickstart.html#cli-configure-quickstart-config)。
+ 一个具有创建 IAM 角色和附加策略以及创建和描述 EKS 集群的权限的 [IAM 主体](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles#iam-term-principal)

## 注意事项
<a name="hybrid-nodes-cluster-create-consider"></a>
+ 集群的集群身份验证模式必须为 `API` 或 `API_AND_CONFIG_MAP`。
+ 集群必须使用 IPv4 地址系列。
+ 集群必须使用公有或私有集群端点连接。集群不能使用“公有和私有”集群端点连接，因为 Amazon EKS Kubernetes API 服务器端点将解析为在您的 VPC 之外运行的混合节点公有 IP。
+ 具有混合节点的 Amazon EKS 集群支持 OIDC 身份验证。
+ 您可以从现有集群中添加、更改或移除混合节点配置。有关更多信息，请参阅 [在现有 Amazon EKS 集群上启用混合节点或修改配置](hybrid-nodes-cluster-update.md)。

## 第 1 步：创建集群 IAM 角色
<a name="hybrid-nodes-cluster-create-iam"></a>

如果您已经拥有集群 IAM 角色，或者您将使用 `eksctl` 或AWS CloudFormation 创建集群，则可以跳过此步骤。默认情况下，`eksctl` 和 AWS CloudFormation 模板会为您创建集群 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#iam-term-principal)分配 `iam:CreateRole` 操作（权限）。

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

1. 您可以分配 Amazon EKS 托管策略或创建自己的自定义策略。有关必须在自定义策略中使用的最低权限，请参阅 [Amazon EKS 节点 IAM 角色](create-node-role.md)。将名为 `AmazonEKSClusterPolicy` 的 Amazon EKS 托管 IAM 策略附加到角色。要将 IAM 策略附加到某个 [IAM 主体](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles#iam-term-principal)，必须为附加该策略的主体分配以下 IAM 操作（权限）之一：`iam:AttachUserPolicy` 或 `iam:AttachRolePolicy`。

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

## 第 2 步：创建启用混合节点功能的集群
<a name="hybrid-nodes-cluster-create-cluster"></a>

您可以使用以下工具来创建集群：
+  [eksctl](#hybrid-nodes-cluster-create-eksctl) 
+  [AWS CloudFormation](#hybrid-nodes-cluster-create-cfn) 
+  [AWS CLI](#hybrid-nodes-cluster-create-cli) 
+  [AWS 管理控制台](#hybrid-nodes-cluster-create-console) 

### 创建启用混合节点功能的集群 – eksctl
<a name="hybrid-nodes-cluster-create-eksctl"></a>

您需要安装最新版本的 `eksctl` 命令行工具。要安装或更新 `eksctl`，请参阅 `eksctl` 文档中的 [Installation](https://eksctl.io/installation)。

1. 创建 `cluster-config.yaml` 以定义启用混合节点功能的 Amazon EKS IPv4 集群。在 `cluster-config.yaml` 中进行以下替换。有关完整的设置列表，请参阅 [eksctl 文档](https://eksctl.io/getting-started/)。

   1. 将 `CLUSTER_NAME` 替换为您的集群名称。名称只能包含字母数字字符（区分大小写）和连字符。该名称必须以字母数字字符开头，且不得超过 100 个字符。对于您在其中创建集群的 AWS 区域和 AWS 账户，该名称必须在其内具有唯一性。

   1. 请将 `AWS_REGION` 替换为要在其中创建集群的 AWS 区域。

   1. 将 `K8S_VERSION` 替换为 [Amazon EKS 支持的版本](https://docs.aws.amazon.com/eks/latest/userguide/kubernetes-versions.html)。

   1. 请根据您在 [准备用于混合节点的凭证](hybrid-nodes-creds.md) 步骤中配置的凭证提供者，将 `CREDS_PROVIDER` 替换为 `ssm` 或 `ira`。

   1. 如果凭证提供者设置为 `ira`，请替换 `CA_BUNDLE_CERT`，这会将 AWS IAM Roles Anywhere 作为凭证提供者。CA\$1BUNDLE\$1CERT 是证书颁发机构（CA）的证书正文，具体取决于您选择的 CA。该证书必须采用隐私增强邮件（PEM）格式。

   1. 请将 `GATEWAY_ID` 替换为要连接到 VPC 的虚拟专用网关或中转网关的 ID。

   1. 请将 `REMOTE_NODE_CIDRS` 替换为混合节点的本地节点 CIDR。

   1. 对于在混合节点上运行的工作负载，请将 `REMOTE_POD_CIDRS` 替换为本地容器组 CIDR；如果您不在混合节点上运行 Webhook，则请从配置中移除该行。如果您的 CNI 在容器组流量离开本地主机时不使用网络地址转换（NATI）或容器组 IP 地址伪装，则必须配置 `REMOTE_POD_CIDRS`。如果在混合节点上运行 Webhook，则必须配置 `REMOTE_POD_CIDRS`，更多信息请参阅[为混合节点配置 Webhook](hybrid-nodes-webhooks.md)。

   1. 本地节点和容器组 CIDR 块必须满足以下要求：

      1. 位于 IPv4 RFC–1918 范围之一：`10.0.0.0/8`、`172.16.0.0/12` 或 `192.168.0.0/16`，或者在 RFC 6598 定义的 CGNAT 范围内：`100.64.0.0/10`。

      1. 不相互重叠，也不与集群的 `VPC CIDR` 或 Kubernetes 服务 IPv4 CIDR 重叠

         ```
         apiVersion: eksctl.io/v1alpha5
         kind: ClusterConfig
         
         metadata:
           name: CLUSTER_NAME
           region: AWS_REGION
           version: "K8S_VERSION"
         
         remoteNetworkConfig:
           iam:
             provider: CREDS_PROVIDER # default SSM, can also be set to IRA
             # caBundleCert: CA_BUNDLE_CERT
           vpcGatewayID: GATEWAY_ID
           remoteNodeNetworks:
           - cidrs: ["REMOTE_NODE_CIDRS"]
           remotePodNetworks:
           - cidrs: ["REMOTE_POD_CIDRS"]
         ```

1. 运行如下命令：

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

   集群预配置需要几分钟时间。在创建集群时，将显示几行输出。输出的最后一行类似于以下示例行。

   ```
   [✓]  EKS cluster "CLUSTER_NAME" in "REGION" region is ready
   ```

1. 继续[第 3 步：更新 kubeconfig](#hybrid-nodes-cluster-create-kubeconfig)。

### 创建启用混合节点功能的集群 – AWS CloudFormation
<a name="hybrid-nodes-cluster-create-cfn"></a>

CloudFormation 堆栈使用您指定的 `RemoteNodeNetwork` 和 `RemotePodNetwork` 来创建 EKS 集群 IAM 角色和 EKS 集群。如果您需要自定义未在 CloudFormation 模板中公开的 EKS 集群设置，请修改 CloudFormation 模板。

1. 下载 CloudFormation 模板文件。

   ```
   curl -OL 'https://raw.githubusercontent.com/aws/eks-hybrid/refs/heads/main/example/hybrid-eks-cfn.yaml'
   ```

1. 创建 `cfn-eks-parameters.json` 并指定每个值的配置。

   1.  `CLUSTER_NAME`：要创建的 EKS 集群的名称

   1.  `CLUSTER_ROLE_NAME`：要创建的 EKS 集群 IAM 角色的名称。模板中的默认值为“EKSClusterRole”。

   1.  `SUBNET1_ID`：您在先决条件步骤中创建的第一个子网的 ID

   1.  `SUBNET2_ID`：您在先决条件步骤中创建的第二个子网的 ID

   1.  `SG_ID`：您在先决条件步骤中创建的安全组 ID

   1.  `REMOTE_NODE_CIDRS`：混合节点的本地节点 CIDR

   1.  `REMOTE_POD_CIDRS`：在混合节点上运行的工作负载的本地容器组 CIDR。如果您的 CNI 在容器组流量离开本地主机时不使用网络地址转换（NATI）或容器组 IP 地址伪装，则必须配置 `REMOTE_POD_CIDRS`。如果在混合节点上运行 Webhook，则必须配置 `REMOTE_POD_CIDRS`，更多信息请参阅[为混合节点配置 Webhook](hybrid-nodes-webhooks.md)。

   1. 本地节点和容器组 CIDR 块必须满足以下要求：

      1. 位于 IPv4 RFC–1918 范围之一：`10.0.0.0/8`、`172.16.0.0/12` 或 `192.168.0.0/16`，或者在 RFC 6598 定义的 CGNAT 范围内：`100.64.0.0/10`。

      1. 不相互重叠，也不与集群的 `VPC CIDR` 或 Kubernetes 服务 IPv4 CIDR 重叠。

   1.  `CLUSTER_AUTH`：集群的集群身份验证模式。有效值为 `API` 和 `API_AND_CONFIG_MAP`。模版中的默认值为 `API_AND_CONFIG_MAP`。

   1.  `CLUSTER_ENDPOINT`：集群的集群端点连接。有效值为“公有”或“私有”。模板中的默认值为“私有”，因此只能从 VPC 内连接到 Kubernetes API 端点。

   1.  `K8S_VERSION`：要用于集群的 Kubernetes 版本。请参阅 [Amazon EKS 支持的版本](https://docs.aws.amazon.com/eks/latest/userguide/kubernetes-versions.html)。

      ```
      {
        "Parameters": {
          "ClusterName": "CLUSTER_NAME",
          "ClusterRoleName": "CLUSTER_ROLE_NAME",
          "SubnetId1": "SUBNET1_ID",
          "SubnetId2": "SUBNET2_ID",
          "SecurityGroupId" "SG_ID",
          "RemoteNodeCIDR": "REMOTE_NODE_CIDRS",
          "RemotePodCIDR": "REMOTE_POD_CIDRS",
          "ClusterAuthMode": "CLUSTER_AUTH",
          "ClusterEndpointConnectivity": "CLUSTER_ENDPOINT",
          "K8sVersion": "K8S_VERSION"
        }
       }
      ```

1. 部署 CloudFormation 堆栈。请将 `STACK_NAME` 替换为 CloudFormation 堆栈的名称，并将 `AWS_REGION` 替换为将会创建集群的 AWS 区域。

   ```
   aws cloudformation deploy \
       --stack-name STACK_NAME \
       --region AWS_REGION \
       --template-file hybrid-eks-cfn.yaml \
       --parameter-overrides file://cfn-eks-parameters.json \
       --capabilities CAPABILITY_NAMED_IAM
   ```

   集群预配置需要几分钟时间。您可以使用以下命令检查堆栈的状态。请将 `STACK_NAME` 替换为 CloudFormation 堆栈的名称，并将 `AWS_REGION` 替换为将会创建集群的 AWS 区域。

   ```
   aws cloudformation describe-stacks \
       --stack-name STACK_NAME \
       --region AWS_REGION \
       --query 'Stacks[].StackStatus'
   ```

1. 继续[第 3 步：更新 kubeconfig](#hybrid-nodes-cluster-create-kubeconfig)。

### 创建启用混合节点功能的集群 – AWS CLI
<a name="hybrid-nodes-cluster-create-cli"></a>

1. 运行以下命令创建启用混合节点功能的 EKS 集群。在运行此命令之前，请将以下参数替换为相应的设置。有关完整的设置列表，请参阅[创建一个 Amazon EKS 集群。](create-cluster.md)文档。

   1.  `CLUSTER_NAME`：要创建的 EKS 集群的名称

   1.  `AWS_REGION`：将创建集群的 AWS 区域。

   1.  `K8S_VERSION`：要用于集群的 Kubernetes 版本。请参阅“Amazon EKS 支持的版本”。

   1.  `ROLE_ARN`：您为集群配置的 Amazon EKS 集群角色。有关更多信息，请参阅“Amazon EKS 集群 IAM 角色”。

   1.  `SUBNET1_ID`：您在先决条件步骤中创建的第一个子网的 ID

   1.  `SUBNET2_ID`：您在先决条件步骤中创建的第二个子网的 ID

   1.  `SG_ID`：您在先决条件步骤中创建的安全组 ID

   1. 您可以将 `API` 和 `API_AND_CONFIG_MAP` 作为集群访问身份验证模式。在下面的命令中，集群访问身份验证模式设置为 `API_AND_CONFIG_MAP`。

   1. 您可以使用 `endpointPublicAccess` 和 `endpointPrivateAccess` 参数来启用或禁用对集群 Kubernetes API 服务器端点的公有和私有访问。在下面的命令中，`endpointPublicAccess` 设置为 false，`endpointPrivateAccess` 设置为 true。

   1.  `REMOTE_NODE_CIDRS`：混合节点的本地节点 CIDR。

   1.  `REMOTE_POD_CIDRS`（可选）：在混合节点上运行的工作负载的本地容器组 CIDR。

   1. 本地节点和容器组 CIDR 块必须满足以下要求：

      1. 位于 IPv4 RFC–1918 范围之一：`10.0.0.0/8`、`172.16.0.0/12` 或 `192.168.0.0/16`，或者在 RFC 6598 定义的 CGNAT 范围内：`100.64.0.0/10`。

      1. 不相互重叠，也不与 Amazon EKS 集群的 `VPC CIDR` 或 Kubernetes 服务 IPv4 CIDR 重叠。

         ```
         aws eks create-cluster \
             --name CLUSTER_NAME \
             --region AWS_REGION \
             --kubernetes-version K8S_VERSION \
             --role-arn ROLE_ARN \
             --resources-vpc-config subnetIds=SUBNET1_ID,SUBNET2_ID,securityGroupIds=SG_ID,endpointPrivateAccess=true,endpointPublicAccess=false \
             --access-config authenticationMode=API_AND_CONFIG_MAP \
             --remote-network-config '{"remoteNodeNetworks":[{"cidrs":["REMOTE_NODE_CIDRS"]}],"remotePodNetworks":[{"cidrs":["REMOTE_POD_CIDRS"]}]}'
         ```

1. 预置集群需要几分钟时间。可使用以下命令查询集群的状态。请将 `CLUSTER_NAME` 替换为要创建的集群的名称，并将 `AWS_REGION` 替换为要创建集群的 AWS 区域。在返回的输出为 `ACTIVE` 之前，请勿继续执行下一步。

   ```
   aws eks describe-cluster \
       --name CLUSTER_NAME \
       --region AWS_REGION \
       --query "cluster.status"
   ```

1. 继续[第 3 步：更新 kubeconfig](#hybrid-nodes-cluster-create-kubeconfig)。

### 创建启用混合节点功能的集群 – AWS 管理控制台
<a name="hybrid-nodes-cluster-create-console"></a>

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

1. 请选择 Add cluster（添加集群），然后选择 Create（创建）。

1. 在 Configure cluster（配置集群）页面上，输入以下字段：

   1.  **Name**（名称）– 集群的名称。名称只能包含字母数字字符（区分大小写）、连字符和下划线。该名称必须以字母数字字符开头，且不得超过 100 个字符。对于您在其中创建集群的 AWS 区域和 AWS 账户，该名称必须在其内具有唯一性。

   1.  **集群 IAM 角色** – 选择您创建的 Amazon EKS 集群 IAM 角色，以允许 Kubernetes 控制面板来代表您管理 AWS 资源。

   1.  **Kubernetes version（Kubernetes 版本）**– 要用于集群的 Kubernetes 的版本。建议选择最新版本，除非您需要早期版本。

   1.  **升级策略** – 选择“扩展”或“标准”。

      1.  **扩展：**选中此选项后，将从发布之日起为 Kubernetes 版本提供 26 个月的支持。扩展支持期会额外按小时收取费用，从标准支持期结束后开始计算。扩展支持终止时，集群将自动升级到下一个版本。

      1.  **标准：**选中此选项后，将从发布之日起为 Kubernetes 版本提供 14 个月的支持。此选项不会产生额外的成本。标准支持终止时，集群将自动升级到下一个版本。

   1.  **集群访问权限** – 选择允许还是禁止集群管理员访问权限并选择身份验证模式。启用混合节点功能的集群支持以下身份验证模式。

      1.  **EKS API**：集群将仅从 EKS 访问条目 API 中获取已通过身份验证的 IAM 主体。

      1.  **EKS API 和 ConfigMap**：集群将从 EKS 访问条目 API 和 `aws-auth` ConfigMap 中获取已通过身份验证的 IAM 主体。

   1.  **Secrets encryption**（密钥加密）–（可选）选择此选项以使用 KMS 密钥启用 Kubernetes 密钥的密钥加密。您也可以在创建集群后启用此功能。在启用此功能之前，请确保您熟悉[在现有集群上使用 KMS 加密 Kubernetes 密钥](enable-kms.md)中的信息。

   1.  **ARC 可用区转移**：若启用该功能，EKS 会将集群注册到 ARC 可用区转移服务，使您能够借助可用区流量转移能力，将应用流量从某一可用区（AZ）中迁出。

   1.  **Tags（标签）**– （可选）向集群添加任何标签。有关更多信息，请参阅 [使用标签整理 Amazon EKS 资源](eks-using-tags.md)。

   1. 完成此页面后，请选择**下一步**。

1. 在 **Specify networking (指定联网)** 页面上，为以下字段选择值：

   1.  **VPC** – 选择符合[查看 Amazon EKS 对 VPC 和子网的联网要求](network-reqs.md)和 [Amazon EKS 混合节点功能要求](hybrid-nodes-prereqs.md)的现有 VPC。在选择 VPC 之前，我们建议您熟悉“查看有关 VPC、子网和混合节点的 Amazon EKS 联网要求”中的所有要求和注意事项。集群创建后，您无法更改要使用的 VPC。如果没有列出任何 VPC，则需要先创建一个。有关更多信息，请参阅[为您的 Amazon EKS 集群创建 Amazon VPC](creating-a-vpc.md)和 [Amazon EKS 混合节点功能联网要求](hybrid-nodes-prereqs.md)。

   1.  **Subnets**（子网）– 预设情况下，已预先选中在之前字段中指定的 VPC 中的所有可用子网。您必须至少选择两个子网。

   1.  **Security groups**（安全组）–（可选）指定您希望 Amazon EKS 将之与其创建的网络接口关联的一个或多个安全组。您指定的安全组中必须至少有一个含有本地节点和（可选）容器组 CIDR 的入站规则。有关更多信息，请参阅 [Amazon EKS 混合节点功能联网要求](hybrid-nodes-networking.md)。无论您是否选择任何安全组，Amazon EKS 都会创建一个安全组，以实现集群和 VPC 之间的通信。Amazon EKS 将此安全组以及您选择的任何安全组与它创建的网络接口关联起来。要详细了解 Amazon EKS 创建的集群安全组，请参阅[查看集群的 Amazon EKS 安全组要求](sec-group-reqs.md)。您可以修改 Amazon EKS 创建的集群安全组中的规则。

   1.  **选择集群 IP 地址系列** – 对于启用混合节点功能的集群必须选择 IPv4。

   1. （可选）选择**配置 Kubernetes 服务 IP 地址范围**，然后指定一个**服务 IPv4 范围**。

   1.  选择**配置远程网络以启用混合节点**，并为混合节点指定本地节点和容器组 CIDR。

   1. 如果您的 CNI 在容器组流量离开本地主机时不使用网络地址转换（NATI）或容器组 IP 地址伪装，则必须配置远程容器组 CIDR。如果在混合节点上运行 Webhook，则必须配置远程容器组 CIDR。

   1. 本地节点和容器组 CIDR 块必须满足以下要求：

      1. 位于 IPv4 RFC–1918 范围之一：`10.0.0.0/8`、`172.16.0.0/12` 或 `192.168.0.0/16`，或者在 RFC 6598 定义的 CGNAT 范围内：`100.64.0.0/10`。

      1. 不相互重叠，也不与集群的 `VPC CIDR` 或 Kubernetes 服务 IPv4 CIDR 重叠

   1. 对于**集群端点访问**中，选择一个选项。创建集群后，您可以更改此选项。对于启用混合节点功能的集群，您必须选择“公有”或“私有”。在选择非默认选项之前，请务必熟悉这些选项及其影响。有关更多信息，请参阅 [集群 API 服务器端点](cluster-endpoint.md)。

   1. 完成此页面后，请选择**下一步**。

1. （可选）在**配置**可观测性页面上，选择要开启的指标和控制面板日志记录选项。默认情况下，每种日志类型都处于关闭状态。

   1. 有关 Prometheus 指标选项的更多信息，请参阅[使用 Prometheus 监控集群指标](prometheus.md)。

   1. 有关 EKS 控制面板日志记录选项的更多信息，请参阅[将控制面板日志发送到 CloudWatch Logs](control-plane-logs.md)。

   1. 完成此页面后，请选择**下一步**。

1. 在 **Select add-ons**（选择附加组件）页面上，选择要添加到集群的附加组件。

   1. 您可以根据需要选择任意数量的 **Amazon EKS 附加组件**和 **AWS Marketplace 附加组件**。与混合节点功能不兼容的 Amazon EKS 附加组件带有“与混合节点功能不兼容”标志，并且此类附加组件使用反亲和性规则来防止其在混合节点上运行。有关更多信息，请参阅“为混合节点配置附加组件”。如果未列出要安装的 **AWS Marketplace 附加组件**，则可以通过在搜索框中输入文本来搜索可用的 **AWS Marketplace 附加组件**。您也可以按 **category**（类别）、**vendor**（供应商）或 **pricing model**（定价模式）进行搜索，然后从搜索结果中选择附加组件。

   1. CoreDNS 和 kube-proxy 等附加组件会默认安装。如果您禁用任何默认插件，则可能会影响您运行 Kubernetes 应用程序的能力。

   1. 完成此页中步骤后，请选择 `Next`。

1. 在**配置选定插件设置**页面上，选择要安装的版本。

   1. 创建集群后，您可以随时更新到更高版本。创建集群后，您可以更新每个附加组件的配置。有关配置附加组件的更多信息，请参阅[更新 Amazon EKS 附加组件](updating-an-add-on.md)。有关兼容混合节点功能的附加组件版本，请参阅[为混合节点配置附加组件](hybrid-nodes-add-ons.md)。

   1. 完成此页面后，请选择下一步。

1. 在 **Review and create (审核和创建)** 页面上，审核您在之前页面输入或选择的信息。如果需要进行更改，请选择 **Edit**（编辑）。在您感到满意后，选择**创建**。**Status**（状态）字段在预置集群时显示 **CREATING**（正在创建）。集群预配置需要几分钟时间。

1. 继续[第 3 步：更新 kubeconfig](#hybrid-nodes-cluster-create-kubeconfig)。

## 第 3 步：更新 kubeconfig
<a name="hybrid-nodes-cluster-create-kubeconfig"></a>

如果您使用 `eksctl` 创建了集群，则可以跳过此步骤。这是因为 `eksctl` 已经为您完成了此步骤。通过向 `kubectl` 文件添加新上下文，从而启用 `kubectl` 与集群之间的通信。有关如何创建和更新文件的更多信息，请参阅 [通过创建 kubeconfig 文件将 kubectl 连接到 EKS 集群](create-kubeconfig.md)。

```
aws eks update-kubeconfig --name CLUSTER_NAME --region AWS_REGION
```

示例输出如下。

```
Added new context arn:aws:eks:AWS_REGION:111122223333:cluster/CLUSTER_NAME to /home/username/.kube/config
```

通过运行以下命令以确认与集群的通信。

```
kubectl get svc
```

示例输出如下。

```
NAME         TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)   AGE
kubernetes   ClusterIP   10.100.0.1   <none>        443/TCP   28h
```

## 第 4 步：集群设置
<a name="_step_4_cluster_setup"></a>

然后请参阅[准备混合节点的集群访问权限](hybrid-nodes-cluster-prep.md)以启用让混合节点能够加入集群的访问权限。

# 在现有 Amazon EKS 集群上启用混合节点或修改配置
<a name="hybrid-nodes-cluster-update"></a>

本主题概述了添加、更改或移除 Amazon EKS 集群的混合节点配置时可用的选项，并介绍了相关注意事项。

要让 Amazon EKS 集群能够使用混合节点，请在 `RemoteNetworkConfig` 配置中添加本地节点的 IP 地址 CIDR 范围以及可选的容器组（pod）网络。EKS 使用此 CIDR 列表来实现集群与本地网络之间的连接。有关更新集群配置时选项的完整列表，请参阅《Amazon EKS API Reference**》中的 [UpdateClusterConfig](https://docs.aws.amazon.com/eks/latest/APIReference/API_UpdateClusterConfig.html)。

您可以对集群中的 EKS 混合节点网络配置执行以下任一操作：
+  [添加远程网络配置，以在现有集群中启用 EKS 混合节点。](#hybrid-nodes-cluster-enable-existing)
+  [在现有集群中添加、更改或移除远程节点网络或远程容器组（pod）网络。](#hybrid-nodes-cluster-update-config)
+  [移除所有远程节点网络 CIDR 范围，以在现有集群中禁用 EKS 混合节点。](#hybrid-nodes-cluster-disable)

## 先决条件
<a name="hybrid-nodes-cluster-enable-prep"></a>
+ 在为混合节点启用 Amazon EKS 集群之前，请确保您的环境满足 [混合节点的先决条件设置](hybrid-nodes-prereqs.md) 中概述的要求以及 [准备混合节点的联网](hybrid-nodes-networking.md)、[为混合节点准备操作系统](hybrid-nodes-os.md) 和 [准备用于混合节点的凭证](hybrid-nodes-creds.md) 中详细介绍的要求。
+ 集群必须使用 IPv4 地址系列。
+ 集群的集群身份验证模式必须为 `API` 或 `API_AND_CONFIG_MAP`。[更改身份验证模式以使用访问条目](setting-up-access-entries.md) 中介绍了修改集群身份验证模式的流程。
+ 我们建议为 Amazon EKS Kubernetes API 服务器端点使用公有或私有端点访问权限，但不要同时启用这两者。如果您选择“公有和私有”，Amazon EKS Kubernetes API 服务器端点将始终解析为在您的 VPC 之外运行的混合节点公有 IP，这可能会阻止您的混合节点加入集群。[集群 API 服务器端点](cluster-endpoint.md) 中介绍了修改集群网络访问权限的流程。
+ 已在您的设备上安装并配置了最新版本的 AWS 命令行界面（AWS CLI）。要查看当前版本，请使用 `aws --version`。yum、apt-get 或适用于 macOS 的 Homebrew 等软件包管理器通常比 AWS CLI 的最新版本落后几个版本。要安装最新版本，请参阅《AWS 命令行界面用户指南》中的[安装或更新到最新版本的 AWS CLI](https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html) 和[配置 AWS CLI 设置](https://docs.aws.amazon.com/cli/latest/userguide/cli-configure-quickstart.html#cli-configure-quickstart-config)。
+ 有权限在您的 Amazon EKS 集群上调用 [UpdateClusterConfig](https://docs.aws.amazon.com/eks/latest/APIReference/API_UpdateClusterConfig.html) 的 [IAM 主体](https://docs.aws.amazon.com/IAM/latest/UserGuide/id_roles#iam-term-principal)。
+ 将附加组件更新到兼容混合节点的版本。有关兼容混合节点功能的附加组件版本，请参阅[为混合节点配置附加组件](hybrid-nodes-add-ons.md)。
+ 如果您正在运行与混合节点不兼容的附加组件，请确保附加组件 [DaemonSet](https://kubernetes.io/docs/concepts/workloads/controllers/daemonset/) 或 [Deployment](https://kubernetes.io/docs/concepts/workloads/controllers/deployment/) 具有以下亲和性规则来防止部署到混合节点。如果以下亲和性规则尚不存在，请添加该规则。

  ```
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: eks.amazonaws.com/compute-type
            operator: NotIn
            values:
            - hybrid
  ```

## 注意事项
<a name="hybrid-nodes-cluster-enable-consider"></a>

`remoteNetworkConfig` JSON 对象在更新期间具有以下行为：
+ 您未指定的任何现有配置部分均保持不变。如果您未指定 `remoteNodeNetworks` 或 `remotePodNetworks` 中的任何一个，则该部分将保持不变。
+ 如果要修改 CIDR 的 `remoteNodeNetworks` 或 `remotePodNetworks` 列表，则必须在最终配置中指定所需的 CIDR 的完整列表。如果您指定了对 `remoteNodeNetworks` 或 `remotePodNetworks` CIDR 列表的更改，EKS 将在更新期间替换原始列表。
+ 本地节点和容器组 CIDR 块必须满足以下要求：

  1. 位于 IPv4 RFC–1918 范围之一：10.0.0.0/8、172.16.0.0/12 或 192.168.0.0/16，或者在 RFC 6598 定义的 CGNAT 范围内：`100.64.0.0/10`

  1. 不相互重叠，也不与 Amazon EKS 集群的所有 VPC CIDR 或 Kubernetes 服务 IPv4 CIDR 重叠。

## 在现有集群上启用混合节点
<a name="hybrid-nodes-cluster-enable-existing"></a>

您可以使用以下方法在现有集群中启用 EKS 混合节点：
+  [AWS CloudFormation](#hybrid-nodes-cluster-enable-cfn) 
+  [AWS CLI](#hybrid-nodes-cluster-enable-cli) 
+  [AWS 管理控制台](#hybrid-nodes-cluster-enable-console) 

### 在现有集群中启用 EKS 混合节点 – AWS CloudFormation
<a name="hybrid-nodes-cluster-enable-cfn"></a>

1. 要在集群中启用 EKS 混合节点，请将 `RemoteNodeNetwork` 和（可选）`RemotePodNetwork` 添加到您的 CloudFormation 模板并更新堆栈。请注意，`RemoteNodeNetwork` 列表最多包含一个 `Cidrs` 项目，而 `Cidrs` 列表可包含多个 IP CIDR 范围。

   ```
   RemoteNetworkConfig:
     RemoteNodeNetworks:
       - Cidrs: [RemoteNodeCIDR]
     RemotePodNetworks:
       - Cidrs: [RemotePodCIDR]
   ```

1. 继续[准备混合节点的集群访问权限](hybrid-nodes-cluster-prep.md)。

### 在现有集群中启用 EKS 混合节点 – AWS CLI
<a name="hybrid-nodes-cluster-enable-cli"></a>

1. 运行以下命令，为 EKS 集群启用 EKS 混合节点的 `RemoteNetworkConfig`。在运行此命令之前，请将以下参数替换为相应的设置。有关设置的完整列表，请参阅《Amazon EKS API Reference》**中的 [UpdateClusterConfig](https://docs.aws.amazon.com/eks/latest/APIReference/API_UpdateClusterConfig.html)。

   1.  `CLUSTER_NAME`：要更新的 EKS 集群的名称。

   1.  `AWS_REGION`：EKS 集群正在运行的 AWS 区域。

   1.  `REMOTE_NODE_CIDRS`：混合节点的本地节点 CIDR。

   1.  `REMOTE_POD_CIDRS`（可选）：在混合节点上运行的工作负载的本地容器组 CIDR。

      ```
      aws eks update-cluster-config \
          --name CLUSTER_NAME \
          --region AWS_REGION \
          --remote-network-config '{"remoteNodeNetworks":[{"cidrs":["REMOTE_NODE_CIDRS"]}],"remotePodNetworks":[{"cidrs":["REMOTE_POD_CIDRS"]}]}'
      ```

1. 更新集群需要几分钟时间。可使用以下命令查询集群的状态。请将 `CLUSTER_NAME` 替换为要修改的集群的名称，并将 `AWS_REGION` 替换为运行集群的 AWS 区域。在返回的输出为 `ACTIVE` 之前，请勿继续执行下一步。

   ```
   aws eks describe-cluster \
       --name CLUSTER_NAME \
       --region AWS_REGION \
       --query "cluster.status"
   ```

1. 继续[准备混合节点的集群访问权限](hybrid-nodes-cluster-prep.md)。

### 在现有集群中启用 EKS 混合节点 – AWS 管理控制台
<a name="hybrid-nodes-cluster-enable-console"></a>

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

1. 选择集群的名称可以显示集群信息。

1. 选择**联网**选项卡，然后选择**更新**。

1. 在下拉列表中，选择**远程网络**。

1.  选择**配置远程网络以启用混合节点**，并为混合节点指定本地节点和容器组 CIDR。

1. 选择 **Save changes（保存更改）**以完成操作。等待集群状态恢复为**活动**。

1. 继续[准备混合节点的集群访问权限](hybrid-nodes-cluster-prep.md)。

## 更新现有集群中的混合节点配置
<a name="hybrid-nodes-cluster-update-config"></a>

您可以使用以下任何一种方法修改现有混合集群中的 `remoteNetworkConfig`：
+  [AWS CloudFormation](#hybrid-nodes-cluster-update-cfn) 
+  [AWS CLI](#hybrid-nodes-cluster-update-cli) 
+  [AWS 管理控制台](#hybrid-nodes-cluster-update-console) 

### 更新现有集群中的混合配置 – AWS CloudFormation
<a name="hybrid-nodes-cluster-update-cfn"></a>

1. 使用新的网络 CIDR 值更新您的 CloudFormation 模板。

   ```
   RemoteNetworkConfig:
     RemoteNodeNetworks:
       - Cidrs: [NEW_REMOTE_NODE_CIDRS]
     RemotePodNetworks:
       - Cidrs: [NEW_REMOTE_POD_CIDRS]
   ```
**注意**  
更新 `RemoteNodeNetworks` 或 `RemotePodNetworks` CIDR 列表时，请包含全部 CIDR（新的和现有的）。更新期间，EKS 会替换整个列表。在更新请求中省略这些字段会保留其现有配置。

1. 使用修改后的模板更新您的 CloudFormation 堆栈，然后等待堆栈更新完成。

### 更新现有集群中的混合配置 – AWS CLI
<a name="hybrid-nodes-cluster-update-cli"></a>

1. 要修改远程网络 CIDR，请运行以下命令。将这些值替换为相应的设置：

   ```
   aws eks update-cluster-config
   --name CLUSTER_NAME
   --region AWS_REGION
   --remote-network-config '{"remoteNodeNetworks":[{"cidrs":["NEW_REMOTE_NODE_CIDRS"]}],"remotePodNetworks":[{"cidrs":["NEW_REMOTE_POD_CIDRS"]}]}'
   ```
**注意**  
更新 `remoteNodeNetworks` 或 `remotePodNetworks` CIDR 列表时，请包含全部 CIDR（新的和现有的）。更新期间，EKS 会替换整个列表。在更新请求中省略这些字段会保留其现有配置。

1. 等待集群状态恢复为“ACTIVE”，然后再继续。

### 更新现有集群中的混合配置 – AWS 管理控制台
<a name="hybrid-nodes-cluster-update-console"></a>

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

1. 选择集群的名称可以显示集群信息。

1. 选择**联网**选项卡，然后选择**更新**。

1. 在下拉列表中，选择**远程网络**。

1. 根据需要更新 `Remote node networks` 和 `Remote pod networks - Optional` 下方的 CIDR。

1. 选择**保存更改**，然后等待集群状态恢复为**活动**。

## 在现有集群中禁用混合节点
<a name="hybrid-nodes-cluster-disable"></a>

您可以使用以下方法在现有集群中禁用 EKS 混合节点：
+  [AWS CloudFormation](#hybrid-nodes-cluster-disable-cfn) 
+  [AWS CLI](#hybrid-nodes-cluster-disable-cli) 
+  [AWS 管理控制台](#hybrid-nodes-cluster-disable-console) 

### 在现有集群中禁用 EKS 混合节点 – AWS CloudFormation
<a name="hybrid-nodes-cluster-disable-cfn"></a>

1. 要在集群中禁用 EKS 混合节点，请在 CloudFormation 模板中将 `RemoteNodeNetworks` 和 `RemotePodNetworks` 设置为空数组，然后更新堆栈。

   ```
   RemoteNetworkConfig:
     RemoteNodeNetworks: []
     RemotePodNetworks: []
   ```

### 在现有集群中禁用 EKS 混合节点 – AWS CLI
<a name="hybrid-nodes-cluster-disable-cli"></a>

1. 运行以下命令，从 EKS 集群中移除 `RemoteNetworkConfig`。在运行此命令之前，请将以下参数替换为相应的设置。有关设置的完整列表，请参阅《Amazon EKS API Reference》**中的 [UpdateClusterConfig](https://docs.aws.amazon.com/eks/latest/APIReference/API_UpdateClusterConfig.html)。

   1.  `CLUSTER_NAME`：要更新的 EKS 集群的名称。

   1.  `AWS_REGION`：EKS 集群正在运行的 AWS 区域。

      ```
      aws eks update-cluster-config \
          --name CLUSTER_NAME \
          --region AWS_REGION \
          --remote-network-config '{"remoteNodeNetworks":[],"remotePodNetworks":[]}'
      ```

1. 更新集群需要几分钟时间。可使用以下命令查询集群的状态。请将 `CLUSTER_NAME` 替换为要修改的集群的名称，并将 `AWS_REGION` 替换为运行集群的 AWS 区域。在返回的输出为 `ACTIVE` 之前，请勿继续执行下一步。

   ```
   aws eks describe-cluster \
       --name CLUSTER_NAME \
       --region AWS_REGION \
       --query "cluster.status"
   ```

### 在现有集群中禁用 EKS 混合节点 – AWS 管理控制台
<a name="hybrid-nodes-cluster-disable-console"></a>

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

1. 选择集群的名称可以显示集群信息。

1. 选择**联网**选项卡，然后选择**更新**。

1. 在下拉列表中，选择**远程网络**。

1. 选择**配置远程网络以启用混合节点**，然后移除 `Remote node networks` 和 `Remote pod networks - Optional` 下的所有 CIDR。

1. 选择 **Save changes（保存更改）**以完成操作。等待集群状态恢复为**活动**。

# 准备混合节点的集群访问权限
<a name="hybrid-nodes-cluster-prep"></a>

在将混合节点连接到 Amazon EKS 集群之前，您必须为混合节点 IAM 角色授予加入集群的 Kubernetes 权限。有关如何创建混合节点 IAM 角色的信息，请参阅[准备用于混合节点的凭证](hybrid-nodes-creds.md)。Amazon EKS 支持通过两种方式将 IAM 主体关联到 Kubernetes 基于角色的访问控制（RBAC）、Amazon EKS 访问条目和 `aws-auth` ConfigMap。有关 Amazon EKS 访问权限管理的更多信息，请参阅[向 IAM 用户和角色授予对 Kubernetes API 的访问权限](grant-k8s-access.md)。

按照以下过程将混合节点 IAM 角色与 Kubernetes 权限关联起来。要使用 Amazon EKS 访问条目，集群必须是使用 `API` 或 `API_AND_CONFIG_MAP` 身份验证模式创建的。要使用 `aws-auth` ConfigMap，集群必须是使用 `API_AND_CONFIG_MAP` 身份验证模式创建的。启用混合节点功能的 Amazon EKS 集群不支持仅 `CONFIG_MAP` 身份验证模式。

## 将 Amazon EKS 访问条目用于混合节点 IAM 角色
<a name="_using_amazon_eks_access_entries_for_hybrid_nodes_iam_role"></a>

一种名为 HYBRID\$1LINUX 的混合节点 Amazon EKS 访问条目类型可以与 IAM 角色一起使用。使用此访问条目类型，用户名将被自动设置为 system:node:\$1\$1SessionName\$1\$1。有关创建访问条目的更多信息，请参阅[创建访问条目](creating-access-entries.md)。

### AWS CLI
<a name="shared_aws_cli"></a>

1. 您必须已在设备上安装和配置最新版本的 AWS CLI。要查看当前版本，请使用 `aws --version`。yum、apt-get 或适用于 macOS 的 Homebrew 等软件包管理器通常比 AWS CLI 的最新版本落后几个版本。要安装最新版本，请参阅《AWS 命令行界面用户指南》中的“安装”和“使用 aws configure 快速配置”。

1. 使用以下命令创建访问条目。请将 CLUSTER\$1NAME 替换为集群的名称，将 HYBRID\$1NODES\$1ROLE\$1ARN 替换为您在[准备用于混合节点的凭证](hybrid-nodes-creds.md)步骤中创建的角色的 ARN。

   ```
   aws eks create-access-entry --cluster-name CLUSTER_NAME \
       --principal-arn HYBRID_NODES_ROLE_ARN \
       --type HYBRID_LINUX
   ```

### AWS 管理控制台
<a name="hybrid-nodes-cluster-prep-console"></a>

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

1. 选择已启用混合节点功能的集群的名称。

1. 选择**访问**选项卡。

1. 选择**创建访问条目**。

1. 对于 **IAM 主体**，请选择您在[准备用于混合节点的凭证](hybrid-nodes-creds.md)步骤中创建的混合节点 IAM 角色。

1. 对于**类型**，选择 **Hybrid Linux**。

1. （可选）对于**标签**，为访问条目分配标签。例如，为了更轻松地查找所有具有相同标签的资源。

1. 选择**跳过以检查并创建**。不能向 Hybrid Linux 访问条目添加策略或更改其访问权限范围。

1. 查看访问条目的配置。如果有任何内容看起来不正确，请选择**上一步**以返回步骤并更正错误。如果配置正确，请选择**创建**。

## 将 aws-auth ConfigMap 用于混合节点 IAM 角色
<a name="_using_aws_auth_configmap_for_hybrid_nodes_iam_role"></a>

在以下步骤中，您将使用您在[准备用于混合节点的凭证](hybrid-nodes-creds.md)步骤中创建的混合节点 IAM 角色的 ARN 来创建或更新 `aws-auth` ConfigMap。

1. 检查您的集群是否已有现有的 `aws-auth` ConfigMap。请注意如果您使用特定的 `kubeconfig` 文件，请使用 `--kubeconfig` 标志。

   ```
   kubectl describe configmap -n kube-system aws-auth
   ```

1. 如果您看到有 `aws-auth` ConfigMap，则请根据需要对其进行更新。

   1. 打开该 ConfigMap 进行编辑。

      ```
      kubectl edit -n kube-system configmap/aws-auth
      ```

   1. 根据需要添加新的 `mapRoles` 条目。将 `HYBRID_NODES_ROLE_ARN` 替换为混合节点 IAM 角色的 ARN。注意，`{{SessionName}}` 是保存在 ConfigMap 中的正确模板格式。请勿将其替换为其他值。

      ```
      data:
        mapRoles: |
        - groups:
          - system:bootstrappers
          - system:nodes
          rolearn: HYBRID_NODES_ROLE_ARN
          username: system:node:{{SessionName}}
      ```

   1. 保存文件并退出文本编辑器。

1. 如果集群没有现有的 `aws-auth` ConfigMap，请使用以下命令创建一个。将 `HYBRID_NODES_ROLE_ARN` 替换为混合节点 IAM 角色的 ARN。注意，`{{SessionName}}` 是保存在 ConfigMap 中的正确模板格式。请勿将其替换为其他值。

   ```
   kubectl apply -f=/dev/stdin <<-EOF
   apiVersion: v1
   kind: ConfigMap
   metadata:
     name: aws-auth
     namespace: kube-system
   data:
     mapRoles: |
     - groups:
       - system:bootstrappers
       - system:nodes
       rolearn: HYBRID_NODES_ROLE_ARN
       username: system:node:{{SessionName}}
   EOF
   ```

# 在混合节点上运行本地工作负载
<a name="hybrid-nodes-tutorial"></a>

在启用了混合节点功能的 EKS 集群中，您可以使用与 AWS 云端相同的 Amazon EKS 集群、功能和工具，在自己的基础设施上运行本地和边缘应用程序。

以下章节包含有关使用混合节点的分步指导。

**Topics**
+ [连接混合节点](hybrid-nodes-join.md)
+ [连接使用 Bottlerocket 的混合节点](hybrid-nodes-bottlerocket.md)
+ [升级混合节点](hybrid-nodes-upgrade.md)
+ [修补混合节点](hybrid-nodes-security.md)
+ [删除混合节点](hybrid-nodes-remove.md)

# 连接混合节点
<a name="hybrid-nodes-join"></a>

**注意**  
以下步骤适用于运行除 Bottlerocket 以外的兼容操作系统的混合节点。有关连接运行 Bottlerocket 的混合节点的步骤，请参阅[连接使用 Bottlerocket 的混合节点](hybrid-nodes-bottlerocket.md)。

本主题介绍如何将混合节点连接到 Amazon EKS 集群。混合节点加入集群后，将在 Amazon EKS 控制台和兼容 Kubernetes 的工具（例如 kubectl）中显示并且状态为“未就绪”。完成本页介绍的步骤后，[为混合节点配置 CNI](hybrid-nodes-cni.md) 以确保混合节点可以随时用于运行应用程序。

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

在将混合节点连接到 Amazon EKS 集群之前，请确保您已完成先决步骤。
+ 您已建立从本地环境到托管 Amazon EKS 集群的 AWS 区域的连接。请参阅[准备混合节点的联网](hybrid-nodes-networking.md)了解更多信息。
+ 您已在本地主机上安装了适用于混合节点的兼容操作系统。请参阅[为混合节点准备操作系统](hybrid-nodes-os.md)了解更多信息。
+ 您已经创建了混合节点 IAM 角色并设置了本地凭证提供者（AWS Systems Manager 混合激活或 AWS IAM Roles Anywhere）。请参阅[准备用于混合节点的凭证](hybrid-nodes-creds.md)了解更多信息。
+ 您已经创建启用了混合节点的 Amazon EKS 集群。请参阅[创建具有混合节点的 Amazon EKS 集群](hybrid-nodes-cluster-create.md)了解更多信息。
+ 您已为您的混合节点 IAM 角色关联了 Kubernetes 基于角色的访问控制（RBAC）权限。请参阅[准备混合节点的集群访问权限](hybrid-nodes-cluster-prep.md)了解更多信息。

## 第 1 步：在每台本地主机上安装混合节点 CLI (`nodeadm`)
<a name="_step_1_install_the_hybrid_nodes_cli_nodeadm_on_each_on_premises_host"></a>

如果您预构建的操作系统映像已经包含 Amazon EKS 混合节点功能 CLI (`nodeadm`)，则可以跳过此步骤。有关 `nodeadm` 混合节点版本的更多信息，请参阅[混合节点 `nodeadm` 参考](hybrid-nodes-nodeadm.md)。

`nodeadm` 的混合节点版本在 Amazon S3 中托管，由 Amazon CloudFront 分发。要在每台本地主机上安装 `nodeadm`，您可以在本地主机上运行以下命令。

 **x86\$164 主机：**

```
curl -OL 'https://hybrid-assets.eks.amazonaws.com/releases/latest/bin/linux/amd64/nodeadm'
```

 **ARM 主机** 

```
curl -OL 'https://hybrid-assets.eks.amazonaws.com/releases/latest/bin/linux/arm64/nodeadm'
```

将可执行文件权限添加到每台主机上下载的二进制文件。

```
chmod +x nodeadm
```

## 第 2 步：使用 `nodeadm` 安装混合节点依赖项
<a name="_step_2_install_the_hybrid_nodes_dependencies_with_nodeadm"></a>

如果在预构建的操作系统映像中安装混合节点依赖项，则可以跳过此步骤。`nodeadm install` 命令可用于安装混合节点必需的所有依赖项。混合节点依赖项包括 containerd、kubelet、kubectl 以及 AWS SSM 或 AWS IAM Roles Anywhere 组件。要详细了解 [混合节点 `nodeadm` 参考](hybrid-nodes-nodeadm.md) 安装的组件和文件位置，请参阅`nodeadm install`。要详细了解必须在本地防火墙中为 `nodeadm install` 进程允许的域，请参阅[准备混合节点的联网](hybrid-nodes-networking.md)。

运行以下命令，从而在本地主机上安装混合节点依赖项。运行以下命令的用户必须具有您主机上的 sudo/root 访问权限。

**重要**  
运行混合节点 CLI (`nodeadm`) 的用户必须具有您主机上的 sudo/root 访问权限。
+ 请 `K8S_VERSION` 替换为 Amazon EKS 集群的 Kubernetes 次要版本，例如 `1.31`。有关支持的 Kubernetes 版本的列表，请参阅 [Amazon EKS 支持的版本](https://docs.aws.amazon.com/eks/latest/userguide/kubernetes-versions.html)。
+ 请将 `CREDS_PROVIDER` 替换为您使用的本地凭证提供者。AWS SSM 的有效值为 `ssm`，AWS IAM Roles Anywhere 的有效值为 `iam-ra`。

```
nodeadm install K8S_VERSION --credential-provider CREDS_PROVIDER
```

## 第 3 步：将混合节点连接到集群
<a name="_step_3_connect_hybrid_nodes_to_your_cluster"></a>

在将混合节点连接到集群之前，请确保您的本地防火墙和集群安全组中已经允许在 Amazon EKS 控制面板与混合节点之间进行通信所必需的权限。此步骤中出现的大多数问题都与防火墙配置、安全组配置或混合节点 IAM 角色配置有关。

**重要**  
运行混合节点 CLI (`nodeadm`) 的用户必须具有您主机上的 sudo/root 访问权限。

1. 在每台主机上创建一个包含适用于部署的值的 `nodeConfig.yaml` 文件。有关可用配置设置的完整说明，请参阅[混合节点 `nodeadm` 参考](hybrid-nodes-nodeadm.md)。如果混合节点 IAM 角色没有执行 `eks:DescribeCluster` 操作的权限，则必须在 `nodeConfig.yaml` 的集群部分中传递 Kubernetes API 端点、集群 CA 捆绑和 Kubernetes 服务 IPv4 CIDR。

   1. 如果您的本地凭证提供者为 AWS SSM 混合激活，请使用以下 `nodeConfig.yaml` 示例。

      1. 将 `CLUSTER_NAME` 替换为您的集群名称。

      1. 请将 AWS 替换为集群所在的 `AWS_REGION` 区域。例如 `us-west-2`。

      1. 请将 `ACTIVATION_CODE` 替换为创建 AWS SSM 混合激活时收到的激活码。请参阅[准备用于混合节点的凭证](hybrid-nodes-creds.md)了解更多信息。

      1. 请将 `ACTIVATION_ID` 替换为创建 AWS SSM 混合激活时收到的激活 ID。您可以通过 AWS Systems Manager 控制台或 AWS CLI `aws ssm describe-activations` 命令查看此信息。

         ```
         apiVersion: node.eks.aws/v1alpha1
         kind: NodeConfig
         spec:
           cluster:
             name: CLUSTER_NAME
             region: AWS_REGION
           hybrid:
             ssm:
               activationCode: ACTIVATION_CODE
               activationId: ACTIVATION_ID
         ```

   1. 如果您的本地凭证提供者为 AWS IAM Roles Anywhere，请使用以下 `nodeConfig.yaml` 示例。

      1. 将 `CLUSTER_NAME` 替换为您的集群名称。

      1. 请将 AWS 替换为集群所在的 `AWS_REGION` 区域。例如 `us-west-2`。

      1. 请将 `NODE_NAME` 替换为节点的名称。如果您为混合节点 IAM 角色配置的信任策略使用 `"sts:RoleSessionName": "${aws:PrincipalTag/x509Subject/CN}"` 资源条件，则节点名称必须与主机上证书的 CN 一致。您使用的 `nodeName` 长度不得超过 64 个字符。

      1. 请将 `TRUST_ANCHOR_ARN` 替换为您在“准备用于混合节点的凭证”步骤中配置的信任锚的 ARN。

      1. 请将 `PROFILE_ARN` 替换为您在“[准备用于混合节点的凭证](hybrid-nodes-creds.md)”步骤中配置的信任锚的 ARN。

      1. 将 `ROLE_ARN` 替换为混合节点 IAM 角色的 ARN。

      1. 请将 `CERTIFICATE_PATH` 替换为磁盘中指向节点证书的路径。如果不指定此参数，则默认值为 `/etc/iam/pki/server.pem`。

      1. 请将 `KEY_PATH` 替换为磁盘中指向证书私有密钥的路径。如果不指定此参数，则默认值为 `/etc/iam/pki/server.key`。

         ```
         apiVersion: node.eks.aws/v1alpha1
         kind: NodeConfig
         spec:
           cluster:
             name: CLUSTER_NAME
             region: AWS_REGION
           hybrid:
             iamRolesAnywhere:
               nodeName: NODE_NAME
               trustAnchorArn: TRUST_ANCHOR_ARN
               profileArn: PROFILE_ARN
               roleArn: ROLE_ARN
               certificatePath: CERTIFICATE_PATH
               privateKeyPath: KEY_PATH
         ```

1. 使用您的 `nodeConfig.yaml` 运行 `nodeadm init` 命令，从而将混合节点连接到 Amazon EKS 集群。

   ```
   nodeadm init -c file://nodeConfig.yaml
   ```

如果上述命令成功完成，则表示混合节点已加入您的 Amazon EKS 集群。您可以在 Amazon EKS 控制台中导航到集群的“计算”选项卡（[确保 IAM 主体具有查看权限](view-kubernetes-resources.md#view-kubernetes-resources-permissions)）或使用 `kubectl get nodes` 来验证此信息。

**重要**  
您的节点将处于 `Not Ready` 状态，此状态符合预期，是因混合节点上缺少正在运行的 CNI 所致。如果节点未加入集群，请参阅[混合节点故障排除](hybrid-nodes-troubleshooting.md)。

## 第 4 步：为混合节点配置 CNI
<a name="_step_4_configure_a_cni_for_hybrid_nodes"></a>

要使混合节点能够随时运行应用程序，请继续完成[为混合节点配置 CNI](hybrid-nodes-cni.md)中的步骤。

# 连接使用 Bottlerocket 的混合节点
<a name="hybrid-nodes-bottlerocket"></a>

本主题介绍如何将运行 Bottlerocket 的混合节点连接到 Amazon EKS 集群。[Bottlerocket](https://aws.amazon.com/bottlerocket/) 是由 AWS 赞助并提供支持的开源 Linux 发行版。Bottlerocket 专为托管容器工作负载而构建。您可以借助 Bottlerocket 实现容器基础设施自动更新，由此提高容器化部署的可用性，降低运营成本。Bottlerocket 仅包含运行容器所需的必备软件，可提高资源利用率、减少安全威胁并降低管理开销。

仅支持将 Bottlerocket 版本 v1.37.0 及更高版本的 VMware 变体与 EKS 混合节点结合使用。Bottlerocket 的 VMware 变体支持 Kubernetes 版本 1.28 及更高版本。这些变体的操作系统映像包括 kubelet、containerd、aws-iam-authenticator 以及适用于 EKS 混合节点功能的其他软件先决条件。您可以使用 Bottlerocket [设置](https://github.com/bottlerocket-os/bottlerocket#settings)文件来配置这些组件，该文件包含用于 Bottlerocket 引导容器和管理容器的 base64 编码用户数据。通过配置这些设置，可让 Bottlerocket 使用您的混合节点凭证提供程序来完成集群对混合节点的身份验证。混合节点加入集群后，将在 Amazon EKS 控制台以及 `kubectl` 等兼容 Kubernetes 的工具中显示并且状态为 `Not Ready`。完成本页介绍的步骤后，[为混合节点配置 CNI](hybrid-nodes-cni.md) 以确保混合节点可以随时用于运行应用程序。

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

在将混合节点连接到 Amazon EKS 集群之前，请确保您已完成先决步骤。
+ 您已建立从本地环境到托管 Amazon EKS 集群的 AWS 区域的连接。请参阅[准备混合节点的联网](hybrid-nodes-networking.md)了解更多信息。
+ 您已经创建了混合节点 IAM 角色并设置了本地凭证提供者（AWS Systems Manager 混合激活或 AWS IAM Roles Anywhere）。请参阅[准备用于混合节点的凭证](hybrid-nodes-creds.md)了解更多信息。
+ 您已经创建启用了混合节点的 Amazon EKS 集群。请参阅[创建具有混合节点的 Amazon EKS 集群](hybrid-nodes-cluster-create.md)了解更多信息。
+ 您已为您的混合节点 IAM 角色关联了 Kubernetes 基于角色的访问控制（RBAC）权限。请参阅[准备混合节点的集群访问权限](hybrid-nodes-cluster-prep.md)了解更多信息。

## 第 1 步：创建 Bottlerocket 设置 TOML 文件
<a name="_step_1_create_the_bottlerocket_settings_toml_file"></a>

要为混合节点配置 Bottlerocket，您需要创建一个包含必要配置的 `settings.toml` 文件。TOML 文件的内容因您使用的凭证提供程序（SSM 或 IAM Roles Anywhere）而异。在预置 Bottlerocket 实例时，此文件将作为用户数据传递。

**注意**  
下方提供的 TOML 文件仅包含将 Bottlerocket VMWare 机器初始化为 EKS 集群节点所需的最低配置项。Bottlerocket 提供了丰富的配置项，可满足多种不同的使用案例。因此，若需配置混合节点初始化之外的更多功能，请查阅 [Bottlerocket 文档](https://bottlerocket.dev/en)，获取所使用版本的完整配置项列表（例如，[此处](https://bottlerocket.dev/en/os/1.51.x/api/settings-index)列出了 Bottlerocket 1.51.x 版本的全部可用配置项）。

### SSM
<a name="_ssm"></a>

如果将 AWS Systems Manager 作为凭证提供程序，请创建一个包含以下内容的 `settings.toml` 文件：

```
[settings.kubernetes]
cluster-name = "<cluster-name>"
api-server = "<api-server-endpoint>"
cluster-certificate = "<cluster-certificate-authority>"
hostname-override = "<hostname>"
provider-id = "eks-hybrid:///<region>/<cluster-name>/<hostname>"
authentication-mode = "aws"
cloud-provider = ""
server-tls-bootstrap = true

[settings.network]
hostname = "<hostname>"

[settings.aws]
region = "<region>"

[settings.kubernetes.credential-providers.ecr-credential-provider]
enabled = true
cache-duration = "12h"
image-patterns = [
    "*.dkr.ecr.*.amazonaws.com",
    "*.dkr.ecr.*.amazonaws.com.rproxy.govskope.us.cn",
    "*.dkr.ecr.*.amazonaws.eu",
    "*.dkr.ecr-fips.*.amazonaws.com",
    "*.dkr.ecr-fips.*.amazonaws.eu",
    "public.ecr.aws"
]

[settings.kubernetes.node-labels]
"eks.amazonaws.com/compute-type" = "hybrid"
"eks.amazonaws.com/hybrid-credential-provider" = "ssm"

[settings.host-containers.admin]
enabled = true
user-data = "<base64-encoded-admin-container-userdata>"

[settings.bootstrap-containers.eks-hybrid-setup]
mode = "always"
user-data = "<base64-encoded-bootstrap-container-userdata>"

[settings.host-containers.control]
enabled = true
```

将占位符替换为以下值：
+  `<cluster-name>`：Amazon EKS 集群的名称。
+  `<api-server-endpoint>`：集群的 API 服务器端点。
+  `<cluster-certificate-authority>`：集群的 base64 编码 CA 捆绑包。
+  `<region>`：托管集群的 AWS 区域，例如“us-east-1”。
+  `<hostname>`：Bottlerocket 实例的主机名，这也将被配置为节点名称。这可以是您选择的任何唯一值，但必须符合 [Kubernetes 对象命名惯例](https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names)。此外，使用的主机名称长度不能超过 64 个字符。注意：使用 SSM 提供程序时，在将实例注册到 SSM 后，该主机名和节点名称将替换为托管实例 ID（例如，`mi-*` ID）。
+  `<base64-encoded-admin-container-userdata>`：Bottlerocket 管理容器配置的 base64 编码内容。启用管理容器后，您将能够通过 SSH 连接到 Bottlerocket 实例，以便进行系统探索和调试。虽然这不是必需设置，但为了便于故障排除，我们建议将其启用。有关使用管理容器进行身份验证的更多信息，请参阅 [Bottlerocket 管理容器文档](https://github.com/bottlerocket-os/bottlerocket-admin-container#authenticating-with-the-admin-container)。例如，管理容器接受 JSON 格式的 SSH 用户和密钥输入。

```
{
  "user": "<ssh-user>",
  "ssh": {
    "authorized-keys": [
      "<ssh-authorized-key>"
    ]
  }
}
```
+  `<base64-encoded-bootstrap-container-userdata>`：Bottlerocket 引导容器配置的 base64 编码内容。有关其配置的更多信息，请参阅 [Bottlerocket 引导容器文档](https://github.com/bottlerocket-os/bottlerocket-bootstrap-container)。引导容器负责将实例注册为 AWS SSM 托管式实例，并将其作为 Kubernetes 节点加入 Amazon EKS 集群。传递到引导容器的用户数据采用命令调用的形式，这会将您之前创建的 SSM 混合激活码和 ID 作为输入接受：

```
eks-hybrid-ssm-setup --activation-id=<activation-id> --activation-code=<activation-code> --region=<region>
```

### IAM Roles Anywhere
<a name="_iam_roles_anywhere"></a>

如果将 AWS IAM Roles Anywhere 作为凭证提供程序，请创建一个包含以下内容的 `settings.toml` 文件：

```
[settings.kubernetes]
cluster-name = "<cluster-name>"
api-server = "<api-server-endpoint>"
cluster-certificate = "<cluster-certificate-authority>"
hostname-override = "<hostname>"
provider-id = "eks-hybrid:///<region>/<cluster-name>/<hostname>"
authentication-mode = "aws"
cloud-provider = ""
server-tls-bootstrap = true

[settings.network]
hostname = "<hostname>"

[settings.aws]
region = "<region>"
config = "<base64-encoded-aws-config-file>"

[settings.kubernetes.credential-providers.ecr-credential-provider]
enabled = true
cache-duration = "12h"
image-patterns = [
    "*.dkr.ecr.*.amazonaws.com",
    "*.dkr.ecr.*.amazonaws.com.rproxy.govskope.us.cn",
    "*.dkr.ecr.*.amazonaws.eu",
    "*.dkr.ecr-fips.*.amazonaws.com",
    "*.dkr.ecr-fips.*.amazonaws.eu",
    "public.ecr.aws"
]

[settings.kubernetes.node-labels]
"eks.amazonaws.com/compute-type" = "hybrid"
"eks.amazonaws.com/hybrid-credential-provider" = "iam-ra"

[settings.host-containers.admin]
enabled = true
user-data = "<base64-encoded-admin-container-userdata>"

[settings.bootstrap-containers.eks-hybrid-setup]
mode = "always"
user-data = "<base64-encoded-bootstrap-container-userdata>"
```

将占位符替换为以下值：
+  `<cluster-name>`：Amazon EKS 集群的名称。
+  `<api-server-endpoint>`：集群的 API 服务器端点。
+  `<cluster-certificate-authority>`：集群的 base64 编码 CA 捆绑包。
+  `<region>`：托管集群的 AWS 区域，例如“us-east-1”
+  `<hostname>`：Bottlerocket 实例的主机名，这也将被配置为节点名称。这可以是您选择的任何唯一值，但必须符合 [Kubernetes 对象命名惯例](https://kubernetes.io/docs/concepts/overview/working-with-objects/names/#names)。此外，使用的主机名称长度不能超过 64 个字符。注意：使用 IAM-RA 提供程序时，如果您为混合节点 IAM 角色配置的信任策略使用 `"sts:RoleSessionName": "${aws:PrincipalTag/x509Subject/CN}"` 资源条件，则节点名称必须与主机上证书的 CN 一致。
+  `<base64-encoded-aws-config-file>`：AWS 配置文件的 Base64 编码内容。该文件的内容应会如下所示：

```
[default]
credential_process = aws_signing_helper credential-process --certificate /root/.aws/node.crt --private-key /root/.aws/node.key --profile-arn <profile-arn> --role-arn <role-arn> --trust-anchor-arn <trust-anchor-arn> --role-session-name <role-session-name>
```
+  `<base64-encoded-admin-container-userdata>`：Bottlerocket 管理容器配置的 base64 编码内容。启用管理容器后，您将能够通过 SSH 连接到 Bottlerocket 实例，以便进行系统探索和调试。虽然这不是必需设置，但为了便于故障排除，我们建议将其启用。有关使用管理容器进行身份验证的更多信息，请参阅 [Bottlerocket 管理容器文档](https://github.com/bottlerocket-os/bottlerocket-admin-container#authenticating-with-the-admin-container)。例如，管理容器接受 JSON 格式的 SSH 用户和密钥输入。

```
{
  "user": "<ssh-user>",
  "ssh": {
    "authorized-keys": [
      "<ssh-authorized-key>"
    ]
  }
}
```
+  `<base64-encoded-bootstrap-container-userdata>`：Bottlerocket 引导容器配置的 base64 编码内容。有关其配置的更多信息，请参阅 [Bottlerocket 引导容器文档](https://github.com/bottlerocket-os/bottlerocket-bootstrap-container)。引导容器负责在实例上创建 IAM Roles Anywhere 主机证书和证书私有密钥文件。然后，`aws_signing_helper` 将会使用这些证书和文件来获取临时证书，以用于 Amazon EKS 集群身份验证。传递到引导容器的用户数据采用命令调用的形式，这会将您之前创建的证书和私有密钥内容作为输入接受：

```
eks-hybrid-iam-ra-setup --certificate=<certificate> --key=<private-key>
```

## 第 2 步：预置 Bottlerocket vSphere 虚拟机及用户数据
<a name="_step_2_provision_the_bottlerocket_vsphere_vm_with_user_data"></a>

构造 TOML 文件后，在创建 vSphere 虚拟机期间将其传递为用户数据。请注意，在虚拟机首次开机之前，必须配置用户数据。因此，您需要在创建实例时提供用户数据；如果您希望先行创建虚拟机，则在您为其配置用户数据前，虚拟机必须处于关机状态。例如，假设使用 `govc` CLI：

### 首次创建虚拟机
<a name="_creating_vm_for_the_first_time"></a>

```
govc vm.create \
  -on=true \
  -c=2 \
  -m=4096 \
  -net.adapter=<network-adapter> \
  -net=<network-name> \
  -e guestinfo.userdata.encoding="base64" \
  -e guestinfo.userdata="$(base64 -w0 settings.toml)" \
  -template=<template-name> \
  <vm-name>
```

### 更新现有虚拟机的用户数据
<a name="_updating_user_data_for_an_existing_vm"></a>

```
govc vm.create \
    -on=false \
    -c=2 \
    -m=4096 \
    -net.adapter=<network-adapter> \
    -net=<network-name> \
    -template=<template-name> \
    <vm-name>

govc vm.change
    -vm <vm-name> \
    -e guestinfo.userdata="$(base64 -w0 settings.toml)" \
    -e guestinfo.userdata.encoding="base64"

govc vm.power -on <vm-name>
```

在以上章节中，`-e guestinfo.userdata.encoding="base64"` 选项用于指定用户数据采用 base64 编码。`-e guestinfo.userdata` 选项将 `settings.toml` 文件的 base64 编码内容作为用户数据传递给 Bottlerocket 实例。将占位符替换为您的具体值，例如 Bottlerocket OVA 模板和联网详细信息。

## 第 3 步：验证混合节点连接
<a name="_step_3_verify_the_hybrid_node_connection"></a>

Bottlerocket 实例启动后，将会尝试加入您的 Amazon EKS 集群。您可以在 Amazon EKS 控制台中导航到集群的“计算”选项卡或运行以下命令，从而验证连接：

```
kubectl get nodes
```

**重要**  
您的节点将处于 `Not Ready` 状态，此状态符合预期，是因混合节点上缺少正在运行的 CNI 所致。如果节点未加入集群，请参阅[混合节点故障排除](hybrid-nodes-troubleshooting.md)。

## 第 4 步：为混合节点配置 CNI
<a name="_step_4_configure_a_cni_for_hybrid_nodes"></a>

要使混合节点能够随时运行应用程序，请继续完成[为混合节点配置 CNI](hybrid-nodes-cni.md)中的步骤。

# 升级集群的混合节点
<a name="hybrid-nodes-upgrade"></a>

升级混合节点的指南与在 Amazon EC2 中运行的自主管理型 Amazon EKS 节点类似。我们建议您在目标 Kubernetes 版本上创建新的混合节点，从容地将现有应用程序迁移到新 Kubernetes 版本上的混合节点，然后再从集群中移除旧 Kubernetes 版本上的混合节点。在开始升级之前，请务必检查 [Amazon EKS 升级最佳实践](https://docs.aws.amazon.com/eks/latest/best-practices/cluster-upgrades.html)。Amazon EKS 混合节点功能[支持的 Kubernetes 版本](https://docs.aws.amazon.com/eks/latest/userguide/kubernetes-versions.html)与具有云节点的 Amazon EKS 集群相同，包括标准和扩展支持。

Amazon EKS 混合节点功能使用的节点[版本偏斜策略](https://kubernetes.io/releases/version-skew-policy/#supported-version-skew)与上游 Kubernetes 相同。Amazon EKS 混合节点功能不能使用比 Amazon EKS 控制面板更高的版本，混合节点的 Kubernetes 次要版本最多可比 Amazon EKS 控制面板早三个次要版本。

如果您没有剩余容量可用来创建具有目标 Kubernetes 版本的新混合节点，以满足割接迁移升级策略的需要，则可以使用 Amazon EKS 混合节点 CLI (`nodeadm`) 就地升级混合节点的 Kubernetes 版本。

**重要**  
如果您使用 `nodeadm` 就地升级混合节点，则在关闭旧版本的 Kubernetes 组件以及安装和启动新的 Kubernetes 版本组件的过程中，节点会有停机时间。

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

在升级之前，请确保您已满足以下先决条件。
+ 升级混合节点的目标 Kubernetes 版本必须等于或早于 Amazon EKS 控制面板的版本。
+ 如果您遵循割接迁移升级策略，则在目标 Kubernetes 版本上安装的新混合节点必须满足[混合节点的先决条件设置](hybrid-nodes-prereqs.md)要求。这包括拥有在创建 Amazon EKS 集群期间传递的远程节点网络 CIDR 中的 IP 地址。
+ 无论是割接迁移升级还是就地升级，混合节点必须有权访问[所需的域](hybrid-nodes-networking.md#hybrid-nodes-networking-on-prem)才能拉取混合节点依赖项的新版本。
+ 您必须已在本地计算机或用于与 Amazon EKS Kubernetes API 端点进行交互的实例上安装 kubectl。
+ 您的 CNI 版本必须支持要升级到的 Kubernetes 版本。如果不支持，请在升级混合节点之前先升级 CNI 版本。请参阅[为混合节点配置 CNI](hybrid-nodes-cni.md)了解更多信息。

## 割接迁移（蓝绿迁移）升级
<a name="hybrid-nodes-upgrade-cutover"></a>

 *割接迁移升级*是指首先在新主机上创建具有目标 Kubernetes 版本的新混合节点，从容地将现有应用程序迁移到目标 Kubernetes 版本的新混合节点，然后再从集群中移除旧 Kubernetes 版本的混合节点的过程。这种策略也称为蓝绿迁移。

1. 按照 [连接混合节点](hybrid-nodes-join.md) 步骤将新主机作为混合节点连接。运行 `nodeadm install` 命令时，请使用目标 Kubernetes 版本。

1. 启用目标 Kubernetes 版本的新混合节点与旧 Kubernetes 版本的混合节点之间的通信。此配置让容器组可在将工作负载迁移到目标 Kubernetes 版本的混合节点后进行相互通信。

1. 确认目标 Kubernetes 版本的混合节点已成功加入集群并处于“就绪”状态。

1. 使用以下命令，将要移除的每个节点标记为不可调度。这样可确保新容器组不会在要替换的节点上调度或重新调度。有关更多信息，请参阅 Kubernetes 文档中的 [kubectl cordon](https://kubernetes.io/docs/reference/kubectl/generated/kubectl_cordon/)。请将 `NODE_NAME` 替换为旧 Kubernetes 版本混合节点的名称。

   ```
   kubectl cordon NODE_NAME
   ```

   您可以使用以下代码段标识并封锁使用特定 Kubernetes 版本（此示例中为版本 `1.28`）的所有节点。

   ```
   K8S_VERSION=1.28
   for node in $(kubectl get nodes -o json | jq --arg K8S_VERSION "$K8S_VERSION" -r '.items[] | select(.status.nodeInfo.kubeletVersion | match("\($K8S_VERSION)")).metadata.name')
   do
       echo "Cordoning $node"
       kubectl cordon $node
   done
   ```

1. 如果混合节点上当前部署运行的 CoreDNS 副本少于 2 个，请将部署横向扩展到至少 2 个副本。我们建议您在混合节点上运行至少两个 CoreDNS 副本，以确保正常运行期间的恢复能力。

   ```
   kubectl scale deployments/coredns --replicas=2 -n kube-system
   ```

1. 使用以下命令清空要从集群中删除的每个使用旧版本 Kubernetes 的混合节点。有关清空节点的更多信息，请参阅 Kubernetes 文档中的[安全地清空一个节点](https://kubernetes.io/docs/tasks/administer-cluster/safely-drain-node/)。请将 `NODE_NAME` 替换为旧 Kubernetes 版本混合节点的名称。

   ```
   kubectl drain NODE_NAME --ignore-daemonsets --delete-emptydir-data
   ```

   您可以使用以下代码段标识并清空特定 Kubernetes 版本（此示例中为版本 `1.28`）的所有节点。

   ```
   K8S_VERSION=1.28
   for node in $(kubectl get nodes -o json | jq --arg K8S_VERSION "$K8S_VERSION" -r '.items[] | select(.status.nodeInfo.kubeletVersion | match("\($K8S_VERSION)")).metadata.name')
   do
       echo "Draining $node"
       kubectl drain $node --ignore-daemonsets --delete-emptydir-data
   done
   ```

1. 您可以使用 `nodeadm` 停止混合节点构件并将其从主机中移除。您必须使用具有 root/sudo 权限的用户运行 `nodeadm`。默认情况下，如果节点上还有容器组，则 `nodeadm uninstall` 不会执行。有关更多信息，请参阅 [混合节点 `nodeadm` 参考](hybrid-nodes-nodeadm.md)。

   ```
   nodeadm uninstall
   ```

1. 停止并卸载混合节点构件后，从集群中移除节点资源。

   ```
   kubectl delete node node-name
   ```

   您可以使用以下代码段标识并删除特定 Kubernetes 版本（此示例中为版本 `1.28`）的所有节点。

   ```
   K8S_VERSION=1.28
   for node in $(kubectl get nodes -o json | jq --arg K8S_VERSION "$K8S_VERSION" -r '.items[] | select(.status.nodeInfo.kubeletVersion | match("\($K8S_VERSION)")).metadata.name')
   do
       echo "Deleting $node"
       kubectl delete node $node
   done
   ```

1. 运行上述步骤后，您的混合节点上可能会剩下一些构件，具体取决于您选择的 CNI。请参阅[为混合节点配置 CNI](hybrid-nodes-cni.md)了解更多信息。

## 就地升级
<a name="hybrid-nodes-upgrade-inplace"></a>

就地升级过程是指使用 `nodeadm upgrade` 升级混合节点的 Kubernetes 版本，而不使用新的物理或虚拟主机和割接迁移策略。`nodeadm upgrade` 进程会关闭在混合节点上运行的现有较早版本的 Kubernetes 组件，卸载现有较早版本的 Kubernetes 组件，安装新的目标 Kubernetes 组件，然后启动新的目标 Kubernetes 组件。强烈建议一次升级一个节点，以尽可能减少对混合节点上运行的应用程序的影响。此过程的持续时间取决于网络带宽和延迟。

1. 使用以下命令将要升级的节点标记为不可调度。这样可确保新容器组不会在要升级的节点上调度或重新调度。有关更多信息，请参阅 Kubernetes 文档中的 [kubectl cordon](https://kubernetes.io/docs/reference/kubectl/generated/kubectl_cordon/)。请将 `NODE_NAME` 替换为要升级的混合节点的名称

   ```
   kubectl cordon NODE_NAME
   ```

1. 使用以下命令清空您要升级的节点。有关清空节点的更多信息，请参阅 Kubernetes 文档中的[安全地清空一个节点](https://kubernetes.io/docs/tasks/administer-cluster/safely-drain-node/)。请将 `NODE_NAME` 替换为要升级的混合节点的名称。

   ```
   kubectl drain NODE_NAME --ignore-daemonsets --delete-emptydir-data
   ```

1. 在要升级的混合节点上运行 `nodeadm upgrade`。您必须使用具有 root/sudo 权限的用户运行 `nodeadm`。无论是使用 AWS SSM 还是 AWS IAM Roles Anywhere 凭证提供者，节点名称都会通过升级保留。在升级过程中，您无法更改凭证提供者。有关 `nodeConfig.yaml` 的配置值，请参阅 [混合节点 `nodeadm` 参考](hybrid-nodes-nodeadm.md)。请将 `K8S_VERSION` 替换为要升级到的目标 Kubernetes 版本。

   ```
   nodeadm upgrade K8S_VERSION -c file://nodeConfig.yaml
   ```

1. 要允许在升级后在节点上调度容器组（pod），请键入以下内容。请将 `NODE_NAME` 替换为节点的名称。

   ```
   kubectl uncordon NODE_NAME
   ```

1. 观察混合节点的状态，等待节点关闭并在新的 Kubernetes 版本上重新启动并进入“就绪”状态。

   ```
   kubectl get nodes -o wide -w
   ```

# 混合节点的安全更新修补
<a name="hybrid-nodes-security"></a>

本主题介绍为在混合节点上运行的特定程序包和依赖项执行就地安全更新修补的过程。作为一项最佳实践，我们建议您定期更新混合节点以获取 CVE 和安全补丁。

有关升级 Kubernetes 版本的步骤，请参阅[升级集群的混合节点](hybrid-nodes-upgrade.md)。

可能需要安装安全补丁的软件的一个例子是 `containerd`。

## `Containerd`
<a name="_containerd"></a>

 `containerd` 是适用于 EKS 混合节点功能的标准 Kubernetes 容器运行时和核心依赖项，用于管理容器生命周期，包括提取映像和管理容器执行等。在混合节点上，您可以通过 [nodeadm CLI](https://docs.aws.amazon.com/eks/latest/userguide/hybrid-nodes-nodeadm.html) 来安装 `containerd`，也可以手动安装。`nodeadm` 将从操作系统分发的程序包或 Docker 程序包安装 `containerd`，具体取决于节点使用的操作系统。

`containerd` 中的 CVE 发布后，您可以使用以下方案，在混合节点上升级到 `containerd` 的修补版本。

## 第 1 步：检查补丁是否已发布
<a name="_step_1_check_if_the_patch_published_to_package_managers"></a>

您可以参考相应的安全公告，检查 `containerd` CVE 补丁是否已发布到相应的各个操作系统程序包管理器：
+  [Amazon Linux 2023](https://alas.aws.amazon.com/alas2023.html) 
+  [RHEL](https://access.redhat.com/security/security-updates/security-advisories) 
+  [Ubuntu 20.04](https://ubuntu.com/security/notices?order=newest&release=focal) 
+  [Ubuntu 22.04](https://ubuntu.com/security/notices?order=newest&release=jammy) 
+  [Ubuntu 24.04](https://ubuntu.com/security/notices?order=newest&release=noble) 

如果将该 Docker 存储库作为 `containerd` 的来源，您可以检查 [Docker 安全公告](https://docs.docker.com/security/security-announcements/)，来确定已修补版本是否在 Docker 存储库中可用。

## 第 2 步：选择安装补丁的方法
<a name="_step_2_choose_the_method_to_install_the_patch"></a>

在节点上就地修补和安装安全升级的方法有三种。具体可以使用的方法，取决于程序包管理器中的操作系统是否提供补丁：

1. 使用 `nodeadm upgrade` 发布到程序包管理器的安装补丁，详情请参阅[第 2 a 步](#hybrid-nodes-security-nodeadm)。

1. 直接使用程序包管理器安装补丁，详情请参见[第 2 b 步](#hybrid-nodes-security-package)。

1. 安装未在程序包管理器中发布的自定义补丁。对于[第 2 c 步](#hybrid-nodes-security-manual) 中 `containerd` 的自定义补丁，有一些特殊注意事项需要注意。

## 第 2 a 步：使用 `nodeadm upgrade` 修补
<a name="hybrid-nodes-security-nodeadm"></a>

确认 `containerd` CVE 补丁已发布到操作系统或 Docker 存储库（Apt 或 RPM）后，您可以使用 `nodeadm upgrade` 命令升级到最新版本的 `containerd`。由于这不属于 Kubernetes 版本升级，因此您必须将当前的 Kubernetes 版本传递给 `nodeadm` 升级命令。

```
nodeadm upgrade K8S_VERSION --config-source file:///root/nodeConfig.yaml
```

## 第 2 b 步：使用操作系统程序包管理器修补
<a name="hybrid-nodes-security-package"></a>

您也可以通过相应的程序包管理器来获取更新，并使用该更新来升级 `containerd` 程序包，如下所示。

 **Amazon Linux 2023** 

```
sudo yum update -y
sudo yum install -y containerd
```

 **RHEL** 

```
sudo yum install -y yum-utils
sudo yum-config-manager --add-repo https://download.docker.com/linux/rhel/docker-ce.repo
sudo yum update -y
sudo yum install -y containerd
```

 **Ubuntu** 

```
sudo mkdir -p /etc/apt/keyrings
sudo curl -fsSL https://download.docker.com/linux/ubuntu/gpg -o /etc/apt/keyrings/docker.asc
echo \
  "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.asc] https://download.docker.com/linux/ubuntu \
  $(. /etc/os-release && echo "${UBUNTU_CODENAME:-$VERSION_CODENAME}") stable" | \
  sudo tee /etc/apt/sources.list.d/docker.list > /dev/null
sudo apt update -y
sudo apt install -y --only-upgrade containerd.io
```

## 第 2 c 步：`Containerd` CVE 补丁未在程序包管理器中发布
<a name="hybrid-nodes-security-manual"></a>

如果修补后的 `containerd` 版本只能通过其他方式获取，而未在程序包管理器中提供，例如对于 GitHub 发行版，可以从 GitHub 官方网站安装 `containerd`。

1. 如果计算机已作为混合节点加入集群，则需要运行 `nodeadm uninstall` 命令。

1. 安装官方 `containerd` 二进制文件。您可以使用 GitHub 上的[官方安装步骤](https://github.com/containerd/containerd/blob/main/docs/getting-started.md#option-1-from-the-official-binaries)。

1. 运行 `nodeadm install` 命令并将 `--containerd-source` 参数设置为 `none`，这将跳过通过 `nodeadm` 安装 `containerd` 的过程。对于节点运行的任何操作系统，您可以在 `containerd` 来源中使用 `none` 的值。

   ```
   nodeadm install K8S_VERSION --credential-provider CREDS_PROVIDER --containerd-source none
   ```

# 移除混合节点
<a name="hybrid-nodes-remove"></a>

本主题介绍如何删除 Amazon EKS 集群中的混合节点。必须使用您选择的兼容 Kubernetes 的工具（例如 [kubectl](https://kubernetes.io/docs/reference/kubectl/)）来删除混合节点。从 Amazon EKS 集群中移除节点对象后，将停止收取混合节点的费用。有关混合节点定价的更多信息，请参阅 [Amazon EKS 定价](https://aws.amazon.com/eks/pricing/)。

**重要**  
移除节点对于在节点上运行的工作负载而言是破坏性的。在删除混合节点之前，我们建议您首先清空节点以将容器组转移到其他活动节点。有关清空节点的更多信息，请参阅 Kubernetes 文档中的[安全地清空一个节点](https://kubernetes.io/docs/tasks/administer-cluster/safely-drain-node/)。

在用于与 Amazon EKS 集群的 Kubernetes API 端点进行交互的本地计算机或实例上运行以下 kubectl 步骤。如果您使用特定的 `kubeconfig` 文件，请使用 `--kubeconfig` 标志。

## 第 1 步：列出节点
<a name="_step_1_list_your_nodes"></a>

```
kubectl get nodes
```

## 第 2 步：清空节点
<a name="_step_2_drain_your_node"></a>

有关 `kubectl drain` 命令的更多信息，请参阅 Kubernetes 文档中的 [kubectl drain](https://kubernetes.io/docs/reference/kubectl/generated/kubectl_drain/)。

```
kubectl drain --ignore-daemonsets <node-name>
```

## 第 3 步：停止并卸载混合节点构件
<a name="_step_3_stop_and_uninstall_hybrid_nodes_artifacts"></a>

您可以使用 Amazon EKS 混合节点功能 CLI (`nodeadm`) 来停止混合节点构件并将其从主机中移除。您必须使用具有 root/sudo 权限的用户运行 `nodeadm`。默认情况下，如果节点上还有容器组，则 `nodeadm uninstall` 不会执行。如果您将 AWS Systems Manager（SSM）作为凭证提供者，则 `nodeadm uninstall` 命令会将主机从 AWS SSM 托管式实例中注销。有关更多信息，请参阅 [混合节点 `nodeadm` 参考](hybrid-nodes-nodeadm.md)。

```
nodeadm uninstall
```

## 第 4 步：删除集群中的节点
<a name="_step_4_delete_your_node_from_the_cluster"></a>

停止并卸载混合节点构件后，从集群中移除节点资源。

```
kubectl delete node <node-name>
```

## 第 5 步：检查剩余的构件
<a name="_step_5_check_for_remaining_artifacts"></a>

运行上述步骤后，您的混合节点上可能会剩下一些构件，具体取决于您选择的 CNI。参阅 [为混合节点配置 CNI](hybrid-nodes-cni.md) 了解更多信息。

# 为混合节点配置应用程序联网、附加组件和 Webhook
<a name="hybrid-nodes-configure"></a>

为混合节点创建 EKS 集群后，请为应用程序联网（CNI、BGP、入口、负载均衡、网络策略）、附加组件、Webhook 和代理设置配置附加功能。有关兼容混合节点功能的 EKS 和社区附加组件的完整列表，请参阅[为混合节点配置附加组件](hybrid-nodes-add-ons.md)。

 **EKS 集群见解** EKS 包括见解检查，可检查混合节点设置中可能损害集群或工作负载功能的错误配置。有关集群见解的更多信息，请参阅[利用集群见解为 Kubernetes 版本升级做好准备并对错误配置进行问题排查](cluster-insights.md)。

以下列出了可用于混合节点的常用功能和附加组件：
+  **容器网络接口（CNI）**：AWS 支持 [Cilium](https://docs.cilium.io/en/stable/index.html) 作为混合节点的 CNI。有关更多信息，请参阅 [为混合节点配置 CNI](hybrid-nodes-cni.md)。注意：AWS VPC CNI 不能用于混合节点。
+  混合节点加入 EKS 集群时会自动安装 **CoreDNS 以及 `kube-proxy` **: CoreDNS 和 `kube-proxy`。这些附加组件可以在集群创建后作为 EKS 附加组件进行管理。
+  **入口和负载均衡**：您可以将 AWS 负载均衡器控制器和应用程序负载均衡器（ALB）或目标类型为 `ip` 的网络负载均衡器（NLB）用于在混合节点上运行的工作负载。对于在混合节点上运行的工作负载，AWS 支持 Cilium 的内置入口、网关和 Kubernetes 服务负载均衡功能。有关更多信息，请参阅[为混合节点配置 Kubernetes 入口](hybrid-nodes-ingress.md)和[为混合节点配置 LoadBalancer 类型服务](hybrid-nodes-load-balancing.md)。
+  **指标**：您可以将 Amazon Managed Service for Prometheus（AMP）无代理抓取程序、AWS Distro for Open Telemetry（ADOT）以及 Amazon CloudWatch 可观测性代理与混合节点结合使用。要将 AMP 无代理抓取程序用于混合节点的容器组（pod）指标，相关容器组必须可以从您用于 EKS 集群的 VPC 进行访问。
+  **日志**：您可以为启用混合节点功能的集群启用 EKS 控制面板日志记录。您可以将 ADOT EKS 附加组件和 Amazon CloudWatch 可观测性代理 EKS 附加组件用于混合节点和容器组（pod）日志记录。
+  **容器组身份和 IRSA**：您可以将 Amazon EKS 容器组身份和服务账户 IAM 角色（IRSA）与在混合节点上运行的应用程序配合使用，从而为使用其他 AWS 服务在混合节点上运行的容器组（pod）实现精细访问控制。
+  **Webhook**：如果运行 Webhook，请参阅[为混合节点配置 Webhook](hybrid-nodes-webhooks.md)，以了解在无法将本地容器组网络设置为可路由时，选择在云节点上运行 Webhook 的注意事项和步骤。
+  **代理**：如果在本地环境中使用代理服务器来处理离开数据中心或边缘环境的流量，则需要将混合节点和集群配置为使用您的代理服务器。有关更多信息，请参阅 [为混合节点功能配置代理](hybrid-nodes-proxy.md)。

**Topics**
+ [

# 为混合节点配置 CNI
](hybrid-nodes-cni.md)
+ [

# 为混合节点配置附加组件
](hybrid-nodes-add-ons.md)
+ [

# 为混合节点配置 Webhook
](hybrid-nodes-webhooks.md)
+ [

# 为混合节点功能配置代理
](hybrid-nodes-proxy.md)
+ [

# 为混合节点配置 Cilium BGP
](hybrid-nodes-cilium-bgp.md)
+ [

# 为混合节点配置 Kubernetes 入口
](hybrid-nodes-ingress.md)
+ [

# 为混合节点配置 LoadBalancer 类型服务
](hybrid-nodes-load-balancing.md)
+ [

# 为混合节点配置 Kubernetes 网络策略
](hybrid-nodes-network-policies.md)

# 为混合节点配置 CNI
<a name="hybrid-nodes-cni"></a>

Cilium 是 AWS 支持的 Amazon EKS 混合节点功能容器网络接口（CNI）。您必须为混合节点安装 CNI 才能使其做好服务工作负载的准备。在 CNI 开始运行之前，混合节点的状态会显示为 `Not Ready`。您可以使用自己选择的工具（例如 Helm）来管理该 CNI。本页上的说明涵盖了 Cilium 生命周期管理（安装、升级、删除）。有关如何配置 Cilium 的入口、负载均衡和网络策略的信息，请参阅[Cilium 入口和 Cilium 网关概述](hybrid-nodes-ingress.md#hybrid-nodes-ingress-cilium)、[服务类型 LoadBalancer](hybrid-nodes-ingress.md#hybrid-nodes-ingress-cilium-loadbalancer)和[为混合节点配置 Kubernetes 网络策略](hybrid-nodes-network-policies.md)。

在 AWS 云中的节点上运行时，AWS 不支持 Cilium。Amazon VPC CNI 与混合节点功能不兼容，并且 VPC CNI 使用 `eks.amazonaws.com/compute-type: hybrid` 标签配置了反亲和性。

本页之前的 Calico 文档已移至 [EKS Hybrid Examples Repository](https://github.com/aws-samples/eks-hybrid-examples)。

## 版本兼容性
<a name="hybrid-nodes-cilium-version-compatibility"></a>

对于 Amazon EKS 所支持的全部 Kubernetes 版本，其 EKS 混合节点均兼容 Cilium `v1.17.x` 与 `v1.18.x` 版本。

**注意**  
 **Cilium v1.18.3 内核版本要求**：由于该版本存在内核版本限制（要求 Linux 内核版本 ≥ 5.10），因此 Cilium v1.18.3 无法在以下节点上使用：
+ Ubuntu 20.04
+ Red Hat Enterprise Linux (RHEL) 8

有关系统要求，请参阅 [Cilium 系统要求](https://docs.cilium.io/en/stable/operations/system_requirements/)。

有关 Amazon EKS 支持的 Kubernetes 版本，请参阅 [Kubernetes 版本支持](https://docs.aws.amazon.com/eks/latest/userguide/kubernetes-versions.html)。EKS 混合节点功能提供的 Kubernetes 版本支持与具有云端节点的 Amazon EKS 集群相同。

## 支持的功能
<a name="hybrid-nodes-cilium-support"></a>

 AWS 维护基于开源 [Cilium 项目](https://github.com/cilium/cilium)的适用于 EKS 混合节点的 Cilium 构建版本。要获得 AWS 对 Cilium 的支持，您必须使用由 AWS 维护的 Cilium 构建版本和支持的 Cilium 版本。

 AWS 为 Cilium 以下功能的默认配置提供技术支持，以用于 EKS 混合节点。如果您计划使用不属于 AWS 支持范围的功能，建议您获得 Cilium 的替代商业支持，或者利用内部专业知识对 Cilium 项目进行问题排查并提供修复。


| Cilium 功能 | 由 AWS 支持  | 
| --- | --- | 
|  Kubernetes 网络合规性  |  是  | 
|  核心集群连接性  |  是  | 
|  IP 系列  |  IPv4  | 
|  生命周期管理  |  Helm  | 
|  联网模式  |  VXLAN 封装  | 
|  IP 地址管理（IPAM）  |  Cilium IPAM 集群范围  | 
|  网络策略  |  Kubernetes 网络策略  | 
|  边界网关协议（BGP）  |  Cilium BGP 控制面板  | 
|  Kubernetes 入口  |  Cilium 入口、Cilium 网关  | 
|  服务 LoadBalancer IP 分配  |  Cilium 负载均衡器 IPAM  | 
|  服务 LoadBalancer IP 地址通告  |  Cilium BGP 控制面板  | 
|  kube-proxy 替换  |  是  | 

## Cilium 注意事项
<a name="hybrid-nodes-cilium-considerations"></a>
+  **Helm 存储库**：AWS 在 [Amazon EKS Cilium/Cilium](https://gallery.ecr.aws/eks/cilium/cilium) 的 Amazon Elastic Container Registry Public（Amazon ECR Public）中托管 Cilium Helm 图表。可用版本包括：
  + Cilium v1.17.9：`oci://public.ecr.aws/eks/cilium/cilium:1.17.9-0`
  + Cilium v1.18.3：`oci://public.ecr.aws/eks/cilium/cilium:1.18.3-0`

    本主题中的命令使用此存储库。请注意，某些 `helm repo` 命令对于 Amazon ECR Public 中的 Helm 存储库无效，因此您无法从本地 Helm 存储库名称中引用此存储库。因此请在大多数命令中使用完整的 URI。
+ [默认情况下，Cilium 配置为在覆盖/隧道模式下运行，并以 VXLAN 为封装方法](https://docs.cilium.io/en/stable/network/concepts/routing/#encapsulation)。此模式对底层物理网络的要求最低。
+ 默认情况下，对于离开集群的所有容器组流量，Cilium 会将其源 IP 地址[伪装](https://docs.cilium.io/en/stable/network/concepts/masquerading/)为该节点的 IP 地址。如果禁用伪装功能，则您的容器组（pod）CIDR 必须可在本地网络上路由。
+ 如果在混合节点上运行 Webhook，则您的容器组（pod）CIDR 必须可在本地网络上路由。如果容器组 CIDR 无法在本地网络上路由，则建议在同一集群中的云端节点上运行 Webhook。有关更多信息，请参阅 [为混合节点配置 Webhook](hybrid-nodes-webhooks.md) 和 [准备混合节点的联网](hybrid-nodes-networking.md)。
+  AWS 建议使用 Cilium 的内置 BGP 功能，使您的容器组（pod）CIDR 可在本地网络上路由。有关如何为 Cilium BGP 配置混合节点的更多信息，请参阅[为混合节点配置 Cilium BGP](hybrid-nodes-cilium-bgp.md)。
+ Cilium 中的默认 IP 地址管理（IPAM）称为[集群范围](https://docs.cilium.io/en/stable/network/concepts/ipam/cluster-pool/)，其中 Cilium 管理器根据用户配置的容器组（pod）CIDR 为每个节点分配 IP 地址。

## 在混合节点上安装 Cilium
<a name="hybrid-nodes-cilium-install"></a>

### 过程
<a name="_procedure"></a>

1. 创建一个名为 `cilium-values.yaml` 的 YAML 文件。以下示例通过设置 Cilium 代理和管理器的 `eks.amazonaws.com/compute-type: hybrid` 标签的亲和性，将 Cilium 配置为仅在混合节点上运行。
   + 使用为 EKS 集群的*远程容器组（pod）网络*配置的相同 容器组（pod）CIDR，对 `clusterPoolIpv4PodCIDRList` 进行配置。例如 `10.100.0.0/24`。Cilium 管理器从配置的 `clusterPoolIpv4PodCIDRList` IP 空间内分配 IP 地址切片。容器组（pod）CIDR 不得与本地节点 CIDR、VPC CIDR 或 Kubernetes 服务 CIDR 重叠。
   + 根据每个节点所需的容器组数量配置 `clusterPoolIpv4MaskSize`。例如，`25` 对应于分段大小 /25，每个节点 128 个容器组。
   + 在集群上部署 Cilium 之后，请勿更改 `clusterPoolIpv4PodCIDRList` 或 `clusterPoolIpv4MaskSize`，请参阅 [Expanding the cluster pool](https://docs.cilium.io/en/stable/network/concepts/ipam/cluster-pool/#expanding-the-cluster-pool) 了解更多信息。
   + 如果在 kube-proxy 替换模式下运行 Cilium，请在 Helm 值中设置 `kubeProxyReplacement: "true"`，并确保在与 Cilium 相同的节点上没有运行现有的 kube-proxy 部署。
   + 以下示例禁用了 Cilium 用于 L7 网络策略和入口的 Envoy 第 7 层（L7）代理。有关更多信息，请参阅[为混合节点配置 Kubernetes 网络策略](hybrid-nodes-network-policies.md)和[Cilium 入口和 Cilium 网关概述](hybrid-nodes-ingress.md#hybrid-nodes-ingress-cilium)。
   + 以下示例配置 `loadBalancer.serviceTopology`: `true`，以便在您为服务配置了服务流量分发功能的情况下，该功能可以正常运行。有关更多信息，请参阅 [配置服务流量分布](hybrid-nodes-webhooks.md#hybrid-nodes-mixed-service-traffic-distribution)。
   + 有关适用于 Cilium 的完整 Helm 值列表，请参阅 Cilium 文档中的 [Helm reference](https://docs.cilium.io/en/stable/helm-reference/)。

     ```
     affinity:
       nodeAffinity:
         requiredDuringSchedulingIgnoredDuringExecution:
           nodeSelectorTerms:
           - matchExpressions:
             - key: eks.amazonaws.com/compute-type
               operator: In
               values:
               - hybrid
     ipam:
       mode: cluster-pool
       operator:
         clusterPoolIPv4MaskSize: 25
         clusterPoolIPv4PodCIDRList:
         - POD_CIDR
     loadBalancer:
       serviceTopology: true
     operator:
       affinity:
         nodeAffinity:
           requiredDuringSchedulingIgnoredDuringExecution:
             nodeSelectorTerms:
             - matchExpressions:
               - key: eks.amazonaws.com/compute-type
                 operator: In
                 values:
                   - hybrid
       unmanagedPodWatcher:
         restart: false
     loadBalancer:
       serviceTopology: true
     envoy:
       enabled: false
     kubeProxyReplacement: "false"
     ```

1. 在集群上安装 Cilium。
   + 将 `CILIUM_VERSION` 替换为某个 Cilium 版本（例如 `1.17.9-0` 或 `1.18.3-0`）。建议使用 Cilium 次要版本的最新补丁版本。
   + 确保节点符合所选版本的内核版本要求。Cilium v1.18.3 要求 Linux 内核版本 ≥ 5.10。
   + 如果使用特定的 kubeconfig 文件，请在 Helm install 命令中使用 `--kubeconfig` 标志。

     ```
     helm install cilium oci://public.ecr.aws/eks/cilium/cilium \
         --version CILIUM_VERSION \
         --namespace kube-system \
         --values cilium-values.yaml
     ```

1. 使用以下命令确认 Cilium 安装是否成功。您应会看到 `cilium-operator` 部署以及在每个混合节点上运行的 `cilium-agent`。此外，混合节点现在的状态应为 `Ready`。有关如何配置 Cilium BGP 以向本地网络通告您的容器组（pod）CIDR 的信息，请转到[为混合节点配置 Cilium BGP](hybrid-nodes-cilium-bgp.md)。

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

   ```
   NAME                              READY   STATUS    RESTARTS   AGE
   cilium-jjjn8                      1/1     Running   0          11m
   cilium-operator-d4f4d7fcb-sc5xn   1/1     Running   0          11m
   ```

   ```
   kubectl get nodes
   ```

   ```
   NAME                   STATUS   ROLES    AGE   VERSION
   mi-04a2cf999b7112233   Ready    <none>   19m   v1.31.0-eks-a737599
   ```

## 在混合节点上升级 Cilium
<a name="hybrid-nodes-cilium-upgrade"></a>

在升级 Cilium 部署之前，请仔细查看 [Cilium 升级文档](https://docs.cilium.io/en/v1.17/operations/upgrade/)和升级说明，以了解目标 Cilium 版本中的更改。

1. 确保已在命令行环境中安装了 `helm` CLI。有关安装说明，请参阅 [Helm 文档](https://helm.sh/docs/intro/quickstart/)。

1. 运行 Cilium 升级预检。请将 `CILIUM_VERSION` 替换为您的目标 Cilium 版本。建议运行 Cilium 次要版本的最新补丁版本。您可以在 Cilium 文档的 [Stable Releases section](https://github.com/cilium/cilium#stable-releases) 部分找到给定次要 Cilium 版本的最新补丁版本。

   ```
   helm install cilium-preflight oci://public.ecr.aws/eks/cilium/cilium --version CILIUM_VERSION \
     --namespace=kube-system \
     --set preflight.enabled=true \
     --set agent=false \
     --set operator.enabled=false
   ```

1. 应用 `cilium-preflight.yaml` 后，请确保状态为 `READY` 的容器组（pod）数量与正在运行的 Cilium 容器组（pod）数量相同。

   ```
   kubectl get ds -n kube-system | sed -n '1p;/cilium/p'
   ```

   ```
   NAME                      DESIRED   CURRENT   READY   UP-TO-DATE   AVAILABLE   NODE SELECTOR   AGE
   cilium                    2         2         2       2            2           <none>          1h20m
   cilium-pre-flight-check   2         2         2       2            2           <none>          7m15s
   ```

1. 一旦状态为 READY 的容器组数量相等，请确保 Cilium 执行前部署也标记为 READY 1/1。如果显示为 READY 0/1，请先查阅 [CNP Validation](https://docs.cilium.io/en/v1.17/operations/upgrade/#cnp-validation) 部分并解决部署问题，然后再继续升级。

   ```
   kubectl get deployment -n kube-system cilium-pre-flight-check -w
   ```

   ```
   NAME                      READY   UP-TO-DATE   AVAILABLE   AGE
   cilium-pre-flight-check   1/1     1            0           12s
   ```

1. 删除预检

   ```
   helm uninstall cilium-preflight --namespace kube-system
   ```

1. 在运行 `helm upgrade` 命令之前，请将部署值保留在 `existing-cilium-values.yaml` 中，或在运行升级命令时为您的设置使用 `--set` 命令行选项。升级操作会覆盖 Cilium ConfigMap，因此在升级时传递配置值至关重要。

   ```
   helm get values cilium --namespace kube-system -o yaml > existing-cilium-values.yaml
   ```

1. 在正常的集群操作期间，所有 Cilium 组件都应运行相同的版本。以下步骤介绍了如何将所有组件从一个稳定版本升级到更高的稳定版本。从一个次要版本升级到另一个次要版本时，建议先升级到现有 Cilium 次要版本的最新补丁版本。为尽可能减少中断，请将 `upgradeCompatibility` 选项设置为此集群中安装的初始 Cilium 版本。

   ```
   helm upgrade cilium oci://public.ecr.aws/eks/cilium/cilium --version CILIUM_VERSION \
     --namespace kube-system \
     --set upgradeCompatibility=1.X \
     -f existing-cilium-values.yaml
   ```

1. （可选）如果由于问题出现需要回滚升级，请运行以下命令。

   ```
   helm history cilium --namespace kube-system
   helm rollback cilium [REVISION] --namespace kube-system
   ```

## 从混合节点中删除 Cilium
<a name="hybrid-nodes-cilium-delete"></a>

1. 运行以下命令从集群中卸载所有 Cilium 组件。请注意，卸载 CNI 可能会影响节点和容器组（pod）的运行状况，因此不应在生产集群上执行卸载。

   ```
   helm uninstall cilium --namespace kube-system
   ```

   从集群中移除 CNI 时，Cilium 配置的接口和路由默认不会移除，有关更多信息，请参阅 [GitHub issue](https://github.com/cilium/cilium/issues/34289)。

1. 要清理磁盘上的配置文件和资源，如果使用的是标准配置目录，则可以移除 GitHub Cilium 存储库中 [`cni-uninstall.sh` 脚本](https://github.com/cilium/cilium/blob/main/plugins/cilium-cni/cni-uninstall.sh)所显示的文件。

1. 要从集群中移除 Cilium 自定义资源定义（CRD），可以运行以下命令。

   ```
   kubectl get crds -oname | grep "cilium" | xargs kubectl delete
   ```

# 为混合节点配置附加组件
<a name="hybrid-nodes-add-ons"></a>

本页介绍通过 Amazon EKS 混合节点功能运行 AWS 附加组件和社区附加组件的注意事项。要详细了解 Amazon EKS 附加组件以及在集群中创建、升级和移除附加组件的过程，请参阅 [Amazon EKS 附加组件](eks-add-ons.md)。除本页中另有说明的外，对于具有混合节点的 Amazon EKS 集群，创建、升级和删除 Amazon EKS 附加组件的过程与使用在 AWS 云端运行的节点的 Amazon EKS 集群相同。仅本页包含的组件已通过 Amazon EKS 混合节点功能兼容性验证。

下列 AWS 附加组件与 Amazon EKS 混合节点功能兼容。


|  AWS 附加组件 | 兼容的附加组件版本 | 
| --- | --- | 
|  kube-proxy  |  v1.25.14-eksbuild.2 及更高版本  | 
|  CoreDNS  |  v1.9.3-eksbuild.7 及更高版本  | 
|   AWS Distro for OpenTelemetry (ADOT)  |  v0.102.1-eksbuild.2 及更高版本  | 
|  CloudWatch 可观测性代理  |  v2.2.1-eksbuild.1 及更高版本  | 
|  EKS 容器组身份代理  |  [\[See the AWS documentation website for more details\]](http://docs.aws.amazon.com/zh_cn/eks/latest/userguide/hybrid-nodes-add-ons.html)  | 
|  节点监控代理  |  v1.2.0-eksbuild.1 及更高版本  | 
|  CSI 快照控制器  |  v8.1.0-eksbuild.1 及更高版本  | 
|   适用于 Kubernetes 的 AWS Private CA Connector  |  v1.6.0-eksbuild.1 及更高版本  | 
|  Amazon FSx CSI 驱动程序  |  v1.7.0-eksbuild.1 及更高版本  | 
|   AWS Secrets Store CSI Driver 提供程序  |  v2.1.1-eksbuild.1 及更高版本  | 

下列社区附加组件与 Amazon EKS 混合节点功能兼容。要了解有关社区组件的更多信息，请参阅[社区附加组件](community-addons.md)。


| 社区附加组件 | 兼容的附加组件版本 | 
| --- | --- | 
|  Kubernetes Metrics Server  |  v0.7.2-eksbuild.1 及更高版本  | 
|  cert-manager  |  v1.17.2-eksbuild.1 及更高版本  | 
|  Prometheus Node Exporter  |  v1.9.1-eksbuild.2 及更高版本  | 
|  kube-state-metrics  |  v2.15.0-eksbuild.4 及更高版本  | 
|  External DNS  |  v0.19.0-eksbuild.1 及更高版本  | 

除以上表格所列的 Amazon EKS 附加组件外，[Amazon Managed Service for Prometheus Collector](prometheus.md)，以及用于[应用程序入口](alb-ingress.md)（HTTP）和[负载均衡](network-load-balancing.md)（TCP/UDP）的 [AWS 负载均衡器控制器](aws-load-balancer-controller.md)也与混合节点功能兼容。

有些 AWS 附加组件和社区附加组件与 Amazon EKS 混合节点功能不兼容。这些附加组件的最新版本存在针对混合节点所应用默认 `eks.amazonaws.com/compute-type: hybrid` 标签的反亲和性规则。这会在集群中部署有混合节点时阻止这些附加组件在混合节点上运行。如果集群既有混合节点又有在 AWS 云端运行的节点，则可以在集群中将这些附加组件部署到在 AWS 云端运行的节点。Amazon VPC CNI 与混合节点功能不兼容，Amazon EKS 混合节点功能支持将 Cilium 和 Calico 作为容器网络接口（CNI）。请参阅[为混合节点配置 CNI](hybrid-nodes-cni.md)了解更多信息。

## AWS 附加组件
<a name="hybrid-nodes-add-ons-aws-add-ons"></a>

后续章节介绍了与其他 Amazon EKS 计算类型相比，在混合节点上运行兼容的 AWS 附加组件的区别。

## kube-proxy 和 CoreDNS
<a name="hybrid-nodes-add-ons-core"></a>

使用 AWS API 和 AWS SDK（包括通过 AWS CLI）创建 EKS 集群时，EKS 会默认将 kube-proxy 和 CoreDNS 安装为自主管理型附加组件。您可以在集群创建后使用 Amazon EKS 附加组件覆盖这些附加组件。有关[在 Amazon EKS 集群中管理 `kube-proxy`](managing-kube-proxy.md)和[在 Amazon EKS 集群中管理 DNS 的 CoreDNS](managing-coredns.md)的详细信息，请参阅 EKS 文档。如果您运行混合模式集群，既有混合节点，也有位于 AWS 云的节点，则 AWS 建议混合节点上至少有一个 CoreDNS 副本，在 AWS 云的节点上也至少有一个 CoreDNS 副本。有关配置步骤，请参阅[配置 CoreDNS 副本](hybrid-nodes-webhooks.md#hybrid-nodes-mixed-coredns)。

## CloudWatch 可观测性代理
<a name="hybrid-nodes-add-ons-cw"></a>

CloudWatch 可观测性代理操作符使用 [Webhook](https://kubernetes.io/docs/reference/access-authn-authz/webhook/)。如果在混合节点上运行此操作符，则本地容器组 CIDR 必须可在本地网络上路由，并且必须为您的 EKS 集群配置远程容器组网络。有关更多信息，请参阅[为混合节点配置 Webhook](hybrid-nodes-webhooks.md)。

混合节点不提供节点级别指标，因为 [CloudWatch Container Insights](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/ContainerInsights.html) 仅在[实例元数据服务](https://docs.aws.amazon.com/AWSEC2/latest/UserGuide/configuring-instance-metadata-service.html)（IMDS）可用的情况下才能提供节点级别指标。混合节点提供集群、工作负载、容器组和容器级别的指标。

按照[使用 Amazon CloudWatch Observability 安装 CloudWatch 代理](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/install-CloudWatch-Observability-EKS-addon.html)中描述的步骤安装附加组件后，必须先更新附加组件清单，然后才能在混合节点上成功运行代理。编辑集群上的 `amazoncloudwatchagents` 资源以添加 `RUN_WITH_IRSA` 环境变量，如下所示。

```
kubectl edit amazoncloudwatchagents -n amazon-cloudwatch cloudwatch-agent
```

```
apiVersion: v1
items:
- apiVersion: cloudwatch.aws.amazon.com/v1alpha1
  kind: AmazonCloudWatchAgent
  metadata:
    ...
    name: cloudwatch-agent
    namespace: amazon-cloudwatch
    ...
  spec:
    ...
    env:
    - name: RUN_WITH_IRSA # <-- Add this
      value: "True" # <-- Add this
    - name: K8S_NODE_NAME
      valueFrom:
        fieldRef:
          fieldPath: spec.nodeName
          ...
```

## 适用于混合节点的 Amazon Managed Prometheus 托管式收集器
<a name="hybrid-nodes-add-ons-amp"></a>

Amazon Managed Service for Prometheus（AMP）托管式收集器由一个抓取程序组成，用于发现和收集 Amazon EKS 集群中资源的指标。AMP 负责为您管理抓取程序，无需您自行管理任何实例、代理或抓取程序。

您可以在不提供任何混合节点特定附加配置的情况下使用 AMP 托管式收集器。不过对于混合节点上的应用程序，指标端点必须可以从 VPC 访问，包括从 VPC 到远程容器组网络 CIDR 的路由以及本地防火墙中打开的端口。此外，集群必须具有[私有集群端点访问权限](cluster-endpoint.md)。

按照《Amazon Managed Service for Prometheus 用户指南》中 [Using an AWS managed collector](https://docs.aws.amazon.com/prometheus/latest/userguide/AMP-collector-how-to.html) 部分说明的步骤进行操作。

## AWS Distro for OpenTelemetry (ADOT)
<a name="hybrid-nodes-add-ons-adot"></a>

您可以使用 AWS Distro for OpenTelemetry（ADOT）附加组件，来收集在混合节点上运行的应用程序的指标、日志和跟踪数据。ADOT 使用准入 [Webhook](https://kubernetes.io/docs/reference/access-authn-authz/webhook/) 更改和验证收集器自定义资源请求。如果在混合节点上运行 ADOT 操作符，则本地容器组 CIDR 必须可在本地网络上路由，并且必须为您的 EKS 集群配置远程容器组网络。有关更多信息，请参阅[为混合节点配置 Webhook](hybrid-nodes-webhooks.md)。

按照《AWS Distro for OpenTelemetry》文档中 [Getting Started with AWS Distro for OpenTelemetry using EKS Add-Ons](https://aws-otel.github.io/docs/getting-started/adot-eks-add-on) **部分说明的步骤进行操作。

## AWS Load Balancer Controller
<a name="hybrid-nodes-add-ons-lbc"></a>

您可以将 [AWS 负载均衡器控制器](aws-load-balancer-controller.md)和应用程序负载均衡器（ALB）或目标类型为 `ip` 的网络负载均衡器（NLB）用于混合节点上的工作负载。与 ALB 或 NLB 一起使用的 IP 目标必须可从 AWS 路由。AWS 负载均衡器控制器也使用 [Webhook](https://kubernetes.io/docs/reference/access-authn-authz/webhook/)。如果在混合节点上运行 AWS 负载均衡器控制器操作符，则本地容器组 CIDR 必须可在本地网络上路由，并且必须为您的 EKS 集群配置远程容器组网络。有关更多信息，请参阅[为混合节点配置 Webhook](hybrid-nodes-webhooks.md)。

要安装 AWS 负载均衡器控制器，请按照[AWS 应用程序负载均衡器](hybrid-nodes-ingress.md#hybrid-nodes-ingress-alb)或[AWS 网络负载均衡器](hybrid-nodes-load-balancing.md#hybrid-nodes-service-lb-nlb)部分说明的步骤操作。

对于使用 ALB 的 Ingress，您必须指定下面的注释。请参阅[使用应用程序负载均衡器路由应用程序和 HTTP 流量](alb-ingress.md)了解更多信息。

```
alb.ingress.kubernetes.io/target-type: ip
```

对于使用 NLB 的负载均衡，您必须指定下面的注释。请参阅[使用网络负载均衡器路由 TCP 和 UDP 流量](network-load-balancing.md)了解更多信息。

```
service.beta.kubernetes.io/aws-load-balancer-type: "external"
service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: "ip"
```

## EKS 容器组身份代理
<a name="hybrid-nodes-add-ons-pod-id"></a>

**注意**  
要在运行 Bottlerocket 的混合节点上成功部署 EKS 容器组身份代理附加组件，请确保您的 Bottlerocket 版本至少为 v1.39.0。混合节点环境中较早的 Bottlerocket 版本不支持容器组身份代理。

原始 Amazon EKS 容器组身份代理 DaemonSet 仅在节点上的 EC2 IMDS 可用时才能获取必需的 AWS 凭证。由于 IMDS 在混合节点上不可用，因此从版本 1.3.3-eksbuild.1 开始，容器组身份代理附加组件可以选择部署挂载所需凭证的 DaemonSet。运行 Bottlerocket 的混合节点需要不同的方法来挂载凭证，从 1.3.7-eksbuild.2 版本开始，容器组身份代理附加组件可以选择部署特别以 Bottlerocket 混合节点为目标的 DaemonSet。以下各节介绍启用可选 DaemonSet 的过程。

### Ubuntu/RHEL/AL2023
<a name="_ubunturhelal2023"></a>

1. 要在 Ubuntu/RHEL/Al2023 混合节点上使用容器组身份代理，请按如下所示，在 `nodeadm` 配置的混合部分设置 `enableCredentialsFile: true`：

   ```
   apiVersion: node.eks.aws/v1alpha1
   kind: NodeConfig
   spec:
       hybrid:
           enableCredentialsFile: true # <-- Add this
   ```

   这将配置 `nodeadm` 以创建一个将在 `/eks-hybrid/.aws/credentials` 下的节点上配置的凭证文件，以供 `eks-pod-identity-agent` 容器组使用。此凭证文件包含将会定期刷新的临时 AWS 凭证。

1. 在*每个*节点上更新 `nodeadm` 配置后，使用您的 `nodeConfig.yaml` 运行以下 `nodeadm init` 命令，从而将混合节点加入 Amazon EKS 集群。如果节点之前已经加入集群，仍可再次运行 `nodeadm init` 命令。

   ```
   nodeadm init -c file://nodeConfig.yaml
   ```

1. 使用 AWS CLI 或 AWS 管理控制台安装 `eks-pod-identity-agent`，并启用混合节点支持。

   1.  AWS CLI：在您用于管理集群的计算机上，运行以下命令安装 `eks-pod-identity-agent` 并启用混合节点支持。将 `my-cluster` 替换为您的集群名称。

      ```
      aws eks create-addon \
          --cluster-name my-cluster \
          --addon-name eks-pod-identity-agent \
          --configuration-values '{"daemonsets":{"hybrid":{"create": true}}}'
      ```

   1.  AWS 管理控制台：如果您要通过 AWS 控制台安装容器组身份代理附加组件，请在可选配置中添加以下内容，以部署将混合节点作为目标的 DaemonSet。

      ```
      {"daemonsets":{"hybrid":{"create": true}}}
      ```

### Bottlerocket
<a name="_bottlerocket"></a>

1. 要在 Bottlerocket 混合节点上使用容器组身份代理，请在用于 Bottlerocket 引导容器用户数据的命令中添加 `--enable-credentials-file=true` 标志，如 [连接使用 Bottlerocket 的混合节点](hybrid-nodes-bottlerocket.md) 中所述。

   1. 如果您使用的是 SSM 凭证提供程序，则命令应如下所示：

      ```
      eks-hybrid-ssm-setup --activation-id=<activation-id> --activation-code=<activation-code> --region=<region> --enable-credentials-file=true
      ```

   1. 如果您使用的是 IAM Roles Anywhere 凭证提供商，则命令应如下所示：

      ```
      eks-hybrid-iam-ra-setup --certificate=<certificate> --key=<private-key> --enable-credentials-file=true
      ```

      这将配置引导脚本，以便在 `/var/eks-hybrid/.aws/credentials` 下在节点上创建凭证文件，以供 `eks-pod-identity-agent` 容器组（pod）使用。此凭证文件包含将会定期刷新的临时 AWS 凭证。

1. 使用 AWS CLI 或 AWS 管理控制台安装 `eks-pod-identity-agent` 并启用 Bottlerocket 混合节点支持。

   1.  AWS CLI：在您用于管理集群的计算机上，运行以下命令安装 `eks-pod-identity-agent` 并启用 Bottlerocket 混合节点支持。将 `my-cluster` 替换为您的集群名称。

      ```
      aws eks create-addon \
          --cluster-name my-cluster \
          --addon-name eks-pod-identity-agent \
          --configuration-values '{"daemonsets":{"hybrid-bottlerocket":{"create": true}}}'
      ```

   1.  AWS 管理控制台：如果您要通过 AWS 控制台安装容器组身份代理附加组件，请在可选配置中添加以下内容，以部署将 Bottlerocket 混合节点作为目标的 DaemonSet。

      ```
      {"daemonsets":{"hybrid-bottlerocket":{"create": true}}}
      ```

## CSI 快照控制器
<a name="hybrid-nodes-add-ons-csi-snapshotter"></a>

从版本 `v8.1.0-eksbuild.2` 起，[CSI 快照控制器附加组件](csi-snapshot-controller.md)执行针对混合节点的软反亲和性规则，偏向让控制器 `deployment` 在与 Amazon EKS 控制面板相同的 AWS 区域中的 EC2 上运行。将 `deployment` 与 Amazon EKS 控制面板托管在同一 AWS 区域有助于减少延迟。

## 社区附加组件
<a name="hybrid-nodes-add-ons-community"></a>

后续章节介绍了与其他 Amazon EKS 计算类型相比，在混合节点上运行兼容的社区附加组件的区别。

## Kubernetes Metrics Server
<a name="hybrid-nodes-add-ons-metrics-server"></a>

控制面板需要能够连接到 Metrics Server 的容器组 IP（如果启用了 hostNetwork，则需要能够连接到节点 IP）。因此，除非在 hostNetwork 模式下运行 Metrics Server，否则在创建 Amazon EKS 集群时必须配置远程容器组网络，并且必须确保您的容器 IP 地址可路由。要使容器组 IP 地址可路由，一种常用的方法是使用 CNI 实现边界网关协议（BGP）。

## cert-manager
<a name="hybrid-nodes-add-ons-cert-manager"></a>

 `cert-manager` 可使用 [Webhook](https://kubernetes.io/docs/reference/access-authn-authz/webhook/)。如果在混合节点上运行 `cert-manager`，则本地容器组 CIDR 必须可在本地网络上路由，并且必须为您的 EKS 集群配置远程容器组网络。有关更多信息，请参阅[为混合节点配置 Webhook](hybrid-nodes-webhooks.md)。

# 为混合节点配置 Webhook
<a name="hybrid-nodes-webhooks"></a>

本页详细介绍了使用混合节点运行 Webhook 的注意事项。在 Kubernetes 应用程序和开源项目（例如 AWS 负载均衡器控制器和 CloudWatch 可观测性代理）中，Webhook 用于执行运行时更改和验证功能。

 **可路由的容器组网络** 

如果您能够在本地网络上路由本地容器组 CIDR，则可以在混合节点上运行 Webhook。您可以通过多种方法来使本地容器组 CIDR 可在本地网络上路由，包括边界网关协议（BGP）、静态路由或其他自定义路由解决方案。我们推荐使用 BGP 解决方案，因为与需要自定义或手动路由配置的备选解决方案相比，此方案具有更好的可扩展性并且更易于管理。AWS 支持使用 Cilium 和 Calico 的 BGP 功能来公开容器组 CIDR，有关更多信息，请参阅[为混合节点配置 CNI](hybrid-nodes-cni.md)和[可路由的远程容器组（pod）CIDR](hybrid-nodes-concepts-kubernetes.md#hybrid-nodes-concepts-k8s-pod-cidrs)。

 **不可路由的容器组网络** 

如果*无法*在本地网络上路由本地容器组 CIDR，但又需要运行 Webhook，我们建议您在与混合节点位于同一 EKS 集群中的云节点上运行所有 Webhook。

## 混合模式集群的注意事项
<a name="hybrid-nodes-considerations-mixed-mode"></a>

 *混合模式集群*是指为既有混合节点又有在 AWS 云端运行的节点的 EKS 集群。运行混合模式集群时应注意以下建议：
+ 在 AWS 云端节点上运行 VPC CNI，在混合节点上运行 Cilium 或 Calico。在 AWS 云端节点上运行时，AWS 不支持 Cilium 和 Calico。
+ 配置要在 AWS 云端节点上运行的 Webhook。请参阅[为附加组件配置 Webhook](#hybrid-nodes-webhooks-add-ons)，了解如何为 AWS 和社区附加组件配置 webhook。
+ 如果应用程序要求在 AWS Cloud 节点上运行的容器组直接与在混合节点上运行的容器组通信（“东西向通信”），并且您在 AWS Cloud 节点上使用 VPC CNI，在混合节点上使用 Cilium 或 Calico，则必须使本地容器组 CIDR 可在本地网络上路由。
+ 在 AWS Cloud 中的节点上运行至少一个 CoreDNS 副本，在混合节点上运行至少一个 CoreDNS 副本。
+ 配置服务流量分布，使服务流量保持在其源区域的本地。有关服务流量分布的更多信息，请参阅[配置服务流量分布](#hybrid-nodes-mixed-service-traffic-distribution)。
+ 如果使用 AWS 应用程序负载均衡器（ALB）或网络负载均衡器（NLB）来处理在混合节点上运行的工作负载流量，则用于 ALB 或 NLB 的 IP 目标必须可以从 AWS 路由。
+ Metrics Server 附加组件需要能够从 EKS 控制面板连接到 Metrics Server 容器组 IP 地址。如果在混合节点上运行 Metrics Server 附加组件，则本地容器组 CIDR 必须可在本地网络上路由。
+ 要使用 Amazon Managed Service for Prometheus（AMP）托管式收集器来收集混合节点的指标，本地容器组 CIDR 必须可在本地网络上路由。您也可以将 AMP 托管式收集器用于 EKS 控制面板指标和在 AWS Cloud 中运行的资源，以及使用 AWS Distro for OpenTelemetry（ADOT）附加组件来收集混合节点的指标。

## 配置混合模式集群
<a name="hybrid-nodes-mixed-mode"></a>

要查看集群上运行的更改和验证 Webhook，可以通过集群的 EKS 控制台的**资源**面板查看**扩展**资源类型，也可以使用以下命令。EKS 还会在集群可观测性控制面板中报告 Webhook 指标，有关更多信息，请参阅[使用可观测性仪表板监控您的集群](observability-dashboard.md)。

```
kubectl get mutatingwebhookconfigurations
```

```
kubectl get validatingwebhookconfigurations
```

### 配置服务流量分布
<a name="hybrid-nodes-mixed-service-traffic-distribution"></a>

运行混合模式集群时，我们建议您使用[https://kubernetes.io/docs/reference/networking/virtual-ips/#traffic-distribution](https://kubernetes.io/docs/reference/networking/virtual-ips/#traffic-distribution)将服务流量保持在其源区域的本地。推荐解决方案是服务流量分配功能（在 Kubernetes 1.31 及更高版本的 EKS 中提供此功能），而不建议使用[拓扑感知路由](https://kubernetes.io/docs/concepts/services-networking/topology-aware-routing/)功能，因为前者的可预测性更好。使用服务流量分配功能时，分区中运行正常的端点将会接收指向该分区的所有流量。使用拓扑感知路由功能时，每项服务必须满足该分区中的多个条件才能应用自定义路由，否则会将流量平均路由到所有端点。

如果将 Cilium 作为 CNI，则必须在运行该 CNI 时将 `enable-service-topology` 设置为 `true`，才能启用服务流量分配功能。您可以使用 Helm 安装标志 `--set loadBalancer.serviceTopology=true` 传递此配置，也可以使用 Cilium CLI 命令 `cilium config set enable-service-topology true` 更新现有安装。更新现有安装的配置后，必须重新启动在每个节点上运行的 Cilium 代理。

以下部分显示如何为 CoreDNS 服务配置服务流量分布的示例，我们建议您为集群中的所有服务启用相同的配置，以避免意外的跨环境流量。

### 配置 CoreDNS 副本
<a name="hybrid-nodes-mixed-coredns"></a>

如果运行混合模式集群，既有混合节点，也有位于 AWS 云端的节点，则建议混合节点上至少有一个 CoreDNS 副本，在 AWS 云端的节点上也至少有一个 CoreDNS 副本。为防止混合模式集群设置中的延迟和网络问题，可以使用[服务流量分配](https://kubernetes.io/docs/reference/networking/virtual-ips/#traffic-distribution)功能，将 CoreDNS 服务配置为首选距离最近的 CoreDNS 副本。

 推荐解决方案是*服务流量分配*功能（在 Kubernetes 1.31 及更高版本的 EKS 中提供此功能），而不建议使用[拓扑感知路由](https://kubernetes.io/docs/concepts/services-networking/topology-aware-routing/)功能，因为前者的可预测性更好。使用服务流量分配功能时，分区中运行正常的端点将会接收指向该分区的所有流量。而使用拓扑感知路由功能时，每项服务必须满足该分区中的多个条件才能应用自定义路由，否则会将流量平均路由到所有端点。以下是配置服务流量分配功能的步骤。

如果将 Cilium 作为 CNI，则必须在运行该 CNI 时将 `enable-service-topology` 设置为 `true`，才能启用服务流量分配功能。您可以使用 Helm 安装标志 `--set loadBalancer.serviceTopology=true` 传递此配置，也可以使用 Cilium CLI 命令 `cilium config set enable-service-topology true` 更新现有安装。更新现有安装的配置后，必须重新启动在每个节点上运行的 Cilium 代理。

1. 为每个混合节点添加一个拓扑分区标签，例如 `topology.kubernetes.io/zone: onprem`。您也可以通过在 `nodeadm` 配置中指定标签，从而在 `nodeadm init` 阶段设置该标签，具体请参阅[自定义 kubelet 的节点配置（可选）](hybrid-nodes-nodeadm.md#hybrid-nodes-nodeadm-kubelet)。请注意，在 AWS 云端运行的节点会自动应用一个拓扑分区标签，与节点的可用区（AZ）相对应。

   ```
   kubectl label node hybrid-node-name topology.kubernetes.io/zone=zone
   ```

1. 使用拓扑分区键将 `podAntiAffinity` 添加到 CoreDNS 部署。您也可以在安装过程中使用 EKS 附加组件配置 CoreDNS 部署。

   ```
   kubectl edit deployment coredns -n kube-system
   ```

   ```
   spec:
     template:
       spec:
         affinity:
          ...
           podAntiAffinity:
             preferredDuringSchedulingIgnoredDuringExecution:
             - podAffinityTerm:
                 labelSelector:
                   matchExpressions:
                   - key: k8s-app
                     operator: In
                     values:
                     - kube-dns
                 topologyKey: kubernetes.io/hostname
               weight: 100
             - podAffinityTerm:
                 labelSelector:
                   matchExpressions:
                   - key: k8s-app
                     operator: In
                     values:
                     - kube-dns
                 topologyKey: topology.kubernetes.io/zone
               weight: 50
         ...
   ```

1. 将设置 `trafficDistribution: PreferClose` 添加到 `kube-dns` 服务配置以启用服务流量分布。

   ```
   kubectl patch svc kube-dns -n kube-system --type=merge -p '{
     "spec": {
       "trafficDistribution": "PreferClose"
     }
   }'
   ```

1. 您可以通过查看 `kube-dns` 服务的端点切片来确认已启用服务流量功能。端点切片必须显示拓扑分区标签为 `hints`，从而确认服务流量分配功能已启用。如果没有看到每个端点地址为 `hints`，则说明服务流量分配功能尚未启用。

   ```
   kubectl get endpointslice -A | grep "kube-dns"
   ```

   ```
   kubectl get endpointslice [.replaceable]`kube-dns-<id>`  -n kube-system -o yaml
   ```

   ```
   addressType: IPv4
   apiVersion: discovery.k8s.io/v1
   endpoints:
   - addresses:
     - <your-hybrid-node-pod-ip>
     hints:
       forZones:
       - name: onprem
     nodeName: <your-hybrid-node-name>
     zone: onprem
   - addresses:
     - <your-cloud-node-pod-ip>
     hints:
       forZones:
       - name: us-west-2a
     nodeName: <your-cloud-node-name>
     zone: us-west-2a
   ```

### 为附加组件配置 Webhook
<a name="hybrid-nodes-webhooks-add-ons"></a>

以下附加组件使用 Webhook，并支持将 Webhook 用于混合节点。
+  AWS Load Balancer Controller
+ CloudWatch 可观测性代理
+  AWS Distro for OpenTelemetry (ADOT)
+  `cert-manager` 

请参阅以下章节，了解如何配置这些附加组件使用的 Webhook，使其在 AWS 云端的节点上运行。

#### AWS Load Balancer Controller
<a name="hybrid-nodes-mixed-lbc"></a>

要在混合模式集群设置中使用 AWS 负载均衡器控制器，您必须在 AWS 云端的节点上运行控制器。为此，请将以下内容添加到 Helm 值配置中，或者使用 EKS 附加组件配置来指定值。

```
affinity:
  nodeAffinity:
    requiredDuringSchedulingIgnoredDuringExecution:
      nodeSelectorTerms:
      - matchExpressions:
        - key: eks.amazonaws.com/compute-type
          operator: NotIn
          values:
          - hybrid
```

#### CloudWatch 可观测性代理
<a name="hybrid-nodes-mixed-cwagent"></a>

CloudWatch 可观测性代理附加组件有一个使用 Webhook 的 Kubernetes 操作符。要在混合模式集群设置下在 AWS 云端节点上运行此操作符，请编辑 CloudWatch 可观测性代理操作符配置。无法在安装过程中使用 Helm 和 EKS 附加组件配置操作符亲和性（请参阅 [containers-roadmap 问题 \$12431](https://github.com/aws/containers-roadmap/issues/2431)）。

```
kubectl edit -n amazon-cloudwatch deployment amazon-cloudwatch-observability-controller-manager
```

```
spec:
  ...
  template:
    ...
    spec:
      affinity:
        nodeAffinity:
          requiredDuringSchedulingIgnoredDuringExecution:
            nodeSelectorTerms:
            - matchExpressions:
              - key: eks.amazonaws.com/compute-type
                operator: NotIn
                values:
                - hybrid
```

#### AWS Distro for OpenTelemetry (ADOT)
<a name="hybrid-nodes-mixed-adot"></a>

AWS Distro for OpenTelemetry（ADOT）附加组件有一个使用 Webhook 的 Kubernetes 操作符。要在混合模式集群设置中的 AWS 云端节点上运行此操作符，请将以下内容添加到 Helm 值配置中，或者使用 EKS 附加组件配置来指定值。

```
affinity:
  nodeAffinity:
    requiredDuringSchedulingIgnoredDuringExecution:
      nodeSelectorTerms:
      - matchExpressions:
        - key: eks.amazonaws.com/compute-type
          operator: NotIn
          values:
          - hybrid
```

如果容器组 CIDR 无法在本地网络上路由，则 ADOT 收集器必须在混合节点上运行，以便可以从混合节点以及在其上运行的工作负载中抓取指标。为此，请编辑自定义资源定义（CRD）。

```
kubectl -n opentelemetry-operator-system edit opentelemetrycollectors.opentelemetry.io adot-col-prom-metrics
```

```
spec:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: eks.amazonaws.com/compute-type
            operator: In
            values:
            - hybrid
```

您可以通过在 ADOT 收集器 CRD 配置中将以下 `relabel_configs` 添加到每个 `scrape_configs` 中，从而将 ADOT 收集器配置为仅从混合节点以及在混合节点上运行的资源中抓取指标。

```
relabel_configs:
  - action: keep
    regex: hybrid
    source_labels:
    - __meta_kubernetes_node_label_eks_amazonaws_com_compute_type
```

ADOT 附加组件的一个先决条件是为 ADOT 操作符使用的 TLS 证书安装 `cert-manager`。`cert-manager` 也会运行 Webhook，并且您可以使用以下 Helm 值配置将其配置为在 AWS 云端的节点上运行。

```
affinity:
  nodeAffinity:
    requiredDuringSchedulingIgnoredDuringExecution:
      nodeSelectorTerms:
      - matchExpressions:
        - key: eks.amazonaws.com/compute-type
          operator: NotIn
          values:
          - hybrid
webhook:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: eks.amazonaws.com/compute-type
            operator: NotIn
            values:
            - hybrid
cainjector:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: eks.amazonaws.com/compute-type
            operator: NotIn
            values:
            - hybrid
startupapicheck:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: eks.amazonaws.com/compute-type
            operator: NotIn
            values:
            - hybrid
```

#### `cert-manager`
<a name="hybrid-nodes-mixed-cert-manager"></a>

`cert-manager` 附加组件会运行 Webhook，并且您可以使用以下 Helm 值配置将其配置为在 AWS 云端的节点上运行。

```
affinity:
  nodeAffinity:
    requiredDuringSchedulingIgnoredDuringExecution:
      nodeSelectorTerms:
      - matchExpressions:
        - key: eks.amazonaws.com/compute-type
          operator: NotIn
          values:
          - hybrid
webhook:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: eks.amazonaws.com/compute-type
            operator: NotIn
            values:
            - hybrid
cainjector:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: eks.amazonaws.com/compute-type
            operator: NotIn
            values:
            - hybrid
startupapicheck:
  affinity:
    nodeAffinity:
      requiredDuringSchedulingIgnoredDuringExecution:
        nodeSelectorTerms:
        - matchExpressions:
          - key: eks.amazonaws.com/compute-type
            operator: NotIn
            values:
            - hybrid
```

# 为混合节点功能配置代理
<a name="hybrid-nodes-proxy"></a>

如果在本地环境中使用代理服务器来处理离开数据中心或边缘环境的流量，则需要单独将节点和集群配置为使用您的代理服务器。

集群  
在集群上，您需要将 `kube-proxy` 配置为使用您的代理服务器。创建 Amazon EKS 集群后，您必须配置 `kube-proxy`。

Nodes  
在节点上，您必须将操作系统、`containerd`、`kubelet` 和 Amazon SSM Agent 配置为使用您的代理服务器。您可以在操作系统映像构建过程中进行这些更改，也可在每个混合节点上运行 `nodeadm init` 之前进行这些更改。

## 节点级别配置
<a name="_node_level_configuration"></a>

您必须在操作系统映像中或在每个混合节点上运行 `nodeadm init` 之前应用以下配置。

### `containerd` 代理配置
<a name="_containerd_proxy_configuration"></a>

 `containerd` 是 Kubernetes 的默认容器管理运行时。如果使用代理来访问互联网，则必须配置 `containerd`，以确保其能够提取 Kubernetes 和 Amazon EKS 所需的容器镜像。

在每个混合节点的 `/etc/systemd/system/containerd.service.d` 目录中，创建一个名为 `http-proxy.conf` 的文件，其中应包含以下内容。请将 `proxy-domain` 和 `port` 替换为环境的相应值。

```
[Service]
Environment="HTTP_PROXY=http://proxy-domain:port"
Environment="HTTPS_PROXY=http://proxy-domain:port"
Environment="NO_PROXY=localhost"
```

#### 来自用户数据的 `containerd` 配置
<a name="_containerd_configuration_from_user_data"></a>

需要为此文件创建 `containerd.service.d` 目录。您要重新加载 systemd，才能在不重新启动的情况下获取配置文件。在 AL2023 中，该服务在脚本执行时可能已经在运行，因此还需要重新启动服务。

```
mkdir -p /etc/systemd/system/containerd.service.d
echo '[Service]' > /etc/systemd/system/containerd.service.d/http-proxy.conf
echo 'Environment="HTTP_PROXY=http://proxy-domain:port"' >> /etc/systemd/system/containerd.service.d/http-proxy.conf
echo 'Environment="HTTPS_PROXY=http://proxy-domain:port"' >> /etc/systemd/system/containerd.service.d/http-proxy.conf
echo 'Environment="NO_PROXY=localhost"' >> /etc/systemd/system/containerd.service.d/http-proxy.conf
systemctl daemon-reload
systemctl restart containerd
```

### `kubelet` 代理配置
<a name="_kubelet_proxy_configuration"></a>

 `kubelet` 是在每个 Kubernetes 节点上运行的 Kubernetes 节点代理，负责管理该节点以及在该节点上运行的容器组（pod）。如果在本地环境中使用代理，则必须配置 `kubelet`，以确保其能够与 Amazon EKS 集群的公共或私有端点通信。

在每个混合节点的 `/etc/systemd/system/kubelet.service.d/` 目录中，创建一个名为 `http-proxy.conf` 的文件，其中应包含以下内容。请将 `proxy-domain` 和 `port` 替换为环境的相应值。

```
[Service]
Environment="HTTP_PROXY=http://proxy-domain:port"
Environment="HTTPS_PROXY=http://proxy-domain:port"
Environment="NO_PROXY=localhost"
```

#### 来自用户数据的 `kubelet` 配置
<a name="_kubelet_configuration_from_user_data"></a>

必须为此文件创建 `kubelet.service.d` 目录。您要重新加载 systemd，才能在不重新启动的情况下获取配置文件。在 AL2023 中，该服务在脚本执行时可能已经在运行，因此还需要重新启动服务。

```
mkdir -p /etc/systemd/system/kubelet.service.d
echo '[Service]' > /etc/systemd/system/kubelet.service.d/http-proxy.conf
echo 'Environment="HTTP_PROXY=http://proxy-domain:port"' >> /etc/systemd/system/kubelet.service.d/http-proxy.conf
echo 'Environment="HTTPS_PROXY=http://proxy-domain:port"' >> /etc/systemd/system/kubelet.service.d/http-proxy.conf
echo 'Environment="NO_PROXY=localhost"' >> /etc/systemd/system/kubelet.service.d/http-proxy.conf
systemctl daemon-reload
systemctl restart kubelet
```

### `ssm` 代理配置
<a name="_ssm_proxy_configuration"></a>

 `ssm` 是可用于初始化混合节点的凭证提供程序之一。`ssm` 负责完成 AWS 身份验证并生成将由 `kubelet` 使用的临时凭证。如果在本地环境中使用代理，并在节点上将 `ssm` 作为凭证提供程序，则必须配置 `ssm`，以确保其能够与 Amazon SSM 服务端点通信。

在每个混合节点的以下路径中创建一个名为 `http-proxy.conf` 文件，具体取决于操作系统
+ Ubuntu - `/etc/systemd/system/snap.amazon-ssm-agent.amazon-ssm-agent.service.d/http-proxy.conf` 
+ Amazon Linux 2023 和 Red Hat Enterprise Linux – `/etc/systemd/system/amazon-ssm-agent.service.d/http-proxy.conf` 

使用以下内容填充该文件。请将 `proxy-domain` 和 `port` 替换为环境的相应值。

```
[Service]
Environment="HTTP_PROXY=http://proxy-domain:port"
Environment="HTTPS_PROXY=http://proxy-domain:port"
Environment="NO_PROXY=localhost"
```

#### 来自用户数据的 `ssm` 配置
<a name="_ssm_configuration_from_user_data"></a>

必须为该文件创建 `ssm` systemd 服务文件目录。目录路径取决于节点上使用的操作系统。
+ Ubuntu - `/etc/systemd/system/snap.amazon-ssm-agent.amazon-ssm-agent.service.d` 
+ Amazon Linux 2023 和 Red Hat Enterprise Linux – `/etc/systemd/system/amazon-ssm-agent.service.d` 

请替换以下重启命令中的 systemd 服务名称，具体取决于节点上使用的操作系统
+ Ubuntu - `snap.amazon-ssm-agent.amazon-ssm-agent` 
+ Amazon Linux 2023 和 Red Hat Enterprise Linux – `amazon-ssm-agent` 

```
mkdir -p systemd-service-file-directory
echo '[Service]' > [.replaceable]#systemd-service-file-directory/http-proxy.conf
echo 'Environment="HTTP_PROXY=http://[.replaceable]#proxy-domain:port"' >> systemd-service-file-directory/http-proxy.conf
echo 'Environment="HTTPS_PROXY=http://[.replaceable]#proxy-domain:port"' >> [.replaceable]#systemd-service-file-directory/http-proxy.conf
echo 'Environment="NO_PROXY=localhost"' >> [.replaceable]#systemd-service-file-directory/http-proxy.conf
systemctl daemon-reload
systemctl restart [.replaceable]#systemd-service-name
```

### 操作系统代理配置
<a name="_operating_system_proxy_configuration"></a>

如果使用代理来访问互联网，则必须对操作系统进行配置，以确保能够从操作系统的软件包管理器中提取混合节点依赖项。

 **Ubuntu** 

1. 通过以下命令配置 `snap` 以使用代理：

   ```
   sudo snap set system proxy.https=http://proxy-domain:port
   sudo snap set system proxy.http=http://proxy-domain:port
   ```

1. 要为 `apt` 启用代理，请在 `/etc/apt/` 目录中创建一个名为 `apt.conf` 的文件。请将代理域和端口替换为环境的相应值。

   ```
   Acquire::http::Proxy "http://proxy-domain:port";
   Acquire::https::Proxy "http://proxy-domain:port";
   ```

 **Amazon Linux 2023** 

1. 配置 `dnf` 以使用代理。创建一个具有环境的代理域和端口值的文件 `/etc/dnf/dnf.conf`。

   ```
   proxy=http://proxy-domain:port
   ```

 **Red Hat Enterprise Linux** 

1. 配置 `yum` 以使用代理。创建一个具有环境的代理域和端口值的文件 `/etc/yum.conf`。

   ```
   proxy=http://proxy-domain:port
   ```

### IAM Roles Anywhere 代理配置
<a name="_iam_roles_anywhere_proxy_configuration"></a>

在使用带有 `enableCredentialsFile` 标志的 IAM Roles Anywhere 时，IAM Roles Anywhere 凭证提供商服务负责刷新凭证（请参阅[EKS 容器组身份代理](hybrid-nodes-add-ons.md#hybrid-nodes-add-ons-pod-id)）。如果在本地环境中使用代理，则必须配置该服务，以确保其能够与 IAM Roles Anywhere 端点通信。

在 `/etc/systemd/system/aws_signing_helper_update.service.d/` 目录中，创建一个名为 `http-proxy.conf` 的包含以下内容的文件。请将 `proxy-domain` 和 `port` 替换为环境的相应值。

```
[Service]
Environment="HTTP_PROXY=http://proxy-domain:port"
Environment="HTTPS_PROXY=http://proxy-domain:port"
Environment="NO_PROXY=localhost"
```

## 集群范围配置
<a name="_cluster_wide_configuration"></a>

本节中的配置必须在创建 Amazon EKS 集群之后并且在每个混合节点上运行 `nodeadm init` 之前应用。

### kube-proxy 代理配置
<a name="_kube_proxy_proxy_configuration"></a>

当混合节点加入集群时，Amazon EKS 会自动在每个混合节点上将 `kube-proxy` 作为 DaemonSet 安装。`kube-proxy` 支持在 Amazon EKS 集群上跨容器组支持的服务进行路由。要配置每台主机，`kube-proxy` 需要对 Amazon EKS 集群端点进行 DNS 解析。

1. 使用以下命令编辑 `kube-proxy` DaemonSet

   ```
   kubectl -n kube-system edit ds kube-proxy
   ```

   这将在您配置的编辑器中打开 `kube-proxy` DaemonSet 定义。

1. 添加 `HTTP_PROXY` 和 `HTTPS_PROXY` 的环境变量。请注意，您的配置中应该已经存在 `NODE_NAME` 环境变量。请将 `proxy-domain` 和 `port` 替换为环境的相应值。

   ```
   containers:
     - command:
       - kube-proxy
       - --v=2
       - --config=/var/lib/kube-proxy-config/config - --hostname-override=$(NODE_NAME)
       env:
       - name: HTTP_PROXY
         value: http://proxy-domain:port
       - name: HTTPS_PROXY
         value: http://proxy-domain:port
       - name: NODE_NAME
         valueFrom:
           fieldRef:
             apiVersion: v1
             fieldPath: spec.nodeName
   ```

# 为混合节点配置 Cilium BGP
<a name="hybrid-nodes-cilium-bgp"></a>

本主题介绍如何为 Amazon EKS 混合节点功能配置 Cilium 边界网关协议（BGP）。Cilium 的 BGP 功能称为 [Cilium BGP 控制面板](https://docs.cilium.io/en/stable/network/bgp-control-plane/bgp-control-plane/)，可用于向本地网络通告容器组（pod）和服务地址。有关将容器组（pod）CIDR 设置为可在本地网络上路由的替代方法，请参阅[可路由的远程容器组（pod）CIDR](hybrid-nodes-concepts-kubernetes.md#hybrid-nodes-concepts-k8s-pod-cidrs)。

## 配置 Cilium BGP
<a name="hybrid-nodes-cilium-bgp-configure"></a>

### 先决条件
<a name="_prerequisites"></a>
+ 按照[为混合节点配置 CNI](hybrid-nodes-cni.md)中的说明安装 Cilium。

### 过程
<a name="_procedure"></a>

1. 要将 BGP 与 Cilium 结合使用，以向本地网络通告容器组（pod）或服务地址，必须已经安装了 Cilium 并配置了 `bgpControlPlane.enabled: true`。如果要为现有 Cilium 部署启用 BGP，则如果之前未启用 BGP，则必须重新启动 Cilium 管理器才能应用 BGP 配置。可以在 Helm 值中将 `operator.rollOutPods` 设置为 `true`，以便在 Helm 安装/升级过程中重新启动 Cilium 管理器。

   ```
   helm upgrade cilium oci://public.ecr.aws/eks/cilium/cilium \
     --namespace kube-system \
     --reuse-values \
     --set operator.rollOutPods=true \
     --set bgpControlPlane.enabled=true
   ```

1. 确认 Cilium 管理器和代理已重启并正在运行。

   ```
   kubectl -n kube-system get pods --selector=app.kubernetes.io/part-of=cilium
   ```

   ```
   NAME                               READY   STATUS    RESTARTS   AGE
   cilium-grwlc                       1/1     Running   0          4m12s
   cilium-operator-68f7766967-5nnbl   1/1     Running   0          4m20s
   cilium-operator-68f7766967-7spfz   1/1     Running   0          4m20s
   cilium-pnxcv                       1/1     Running   0          6m29s
   cilium-r7qkj                       1/1     Running   0          4m12s
   cilium-wxhfn                       1/1     Running   0          4m1s
   cilium-z7hlb                       1/1     Running   0          6m30s
   ```

1. 创建带有 `CiliumBGPClusterConfig` 定义的名为 `cilium-bgp-cluster.yaml` 的文件。您可能需要从网络管理员获取以下信息：
   + 使用 ASN 为运行 Cilium 的节点配置 `localASN`。
   + 使用 ASN 为本地路由器配置 `peerASN`。
   + 使用运行 Cilium 的每个节点将与之对等的本地路由器 IP 对 `peerAddress` 进行配置。

     ```
     apiVersion: cilium.io/v2alpha1
     kind: CiliumBGPClusterConfig
     metadata:
       name: cilium-bgp
     spec:
       nodeSelector:
         matchExpressions:
         - key: eks.amazonaws.com/compute-type
           operator: In
           values:
           - hybrid
       bgpInstances:
       - name: "rack0"
         localASN: NODES_ASN
         peers:
         - name: "onprem-router"
           peerASN: ONPREM_ROUTER_ASN
           peerAddress: ONPREM_ROUTER_IP
           peerConfigRef:
             name: "cilium-peer"
     ```

1. 将 Cilium BGP 集群配置应用于集群。

   ```
   kubectl apply -f cilium-bgp-cluster.yaml
   ```

1. 使用定义 BGP 对等配置的 `CiliumBGPPeerConfig` 资源创建名为 `cilium-bgp-peer.yaml` 的文件。多个对等体可以共享相同的配置并引用共同的 `CiliumBGPPeerConfig` 资源。有关配置选项的完整列表，请参阅 Cilium 文档中的 [BGP Peer Configuration](https://docs.cilium.io/en/latest/network/bgp-control-plane/bgp-control-plane-v2/#bgp-peer-configuration)。

   以下 Cilium 对等设置的值必须与您正在与之对等的本地路由器的值相匹配。
   + 配置 `holdTimeSeconds`，其决定了 BGP 对等体在宣布会话关闭之前等待保持连接或更新消息的时间。默认值为 90 秒。
   + 配置 `keepAliveTimeSeconds`，其决定了 BGP 对等体是否仍可访问以及 BGP 会话是否处于活动状态。默认值为 30 秒。
   + 配置 `restartTimeSeconds`，其决定了 Cilium 的 BGP 控制面板在重启后预计重新建立 BGP 会话的时间。默认值为 120 秒。

     ```
     apiVersion: cilium.io/v2alpha1
     kind: CiliumBGPPeerConfig
     metadata:
       name: cilium-peer
     spec:
       timers:
         holdTimeSeconds: 90
         keepAliveTimeSeconds: 30
       gracefulRestart:
         enabled: true
         restartTimeSeconds: 120
       families:
         - afi: ipv4
           safi: unicast
           advertisements:
             matchLabels:
               advertise: "bgp"
     ```

1. 将 Cilium BGP 对等体配置应用于集群。

   ```
   kubectl apply -f cilium-bgp-peer.yaml
   ```

1. 使用 `CiliumBGPAdvertisement` 资源创建名为 `cilium-bgp-advertisement-pods.yaml` 的文件，用于向本地网络通告容器组（pod）CIDR。
   + `CiliumBGPAdvertisement` 资源用于定义各种通告类型以及与之相关的属性。以下示例将 Cilium 配置为仅通告容器组（pod）CIDR。有关配置 Cilium 以通告服务地址的更多信息，请参阅[服务类型 LoadBalancer](hybrid-nodes-ingress.md#hybrid-nodes-ingress-cilium-loadbalancer)和[Cilium 集群内负载均衡](hybrid-nodes-load-balancing.md#hybrid-nodes-service-lb-cilium)中的示例。
   + 每个运行 Cilium 代理的混合节点都与启用了 BGP 的上游路由器对等。如下方示例所示，当 Cilium 的 `advertisementType` 设置为 `PodCIDR` 时，每个节点都会通告其拥有的容器组（pod）CIDR 范围。有关更多信息，请参阅 Cilium 文档中的 [BGP Advertisements configuration](https://docs.cilium.io/en/stable/network/bgp-control-plane/bgp-control-plane-v2/#bgp-advertisements)。

     ```
     apiVersion: cilium.io/v2alpha1
     kind: CiliumBGPAdvertisement
     metadata:
       name: bgp-advertisement-pods
       labels:
         advertise: bgp
     spec:
       advertisements:
         - advertisementType: "PodCIDR"
     ```

1. 将 Cilium BGP 广播配置应用到集群。

   ```
   kubectl apply -f cilium-bgp-advertisement-pods.yaml
   ```

1. 您可以通过 [Cilium CLI](https://docs.cilium.io/en/stable/gettingstarted/k8s-install-default/#install-the-cilium-cli)，使用 `cilium bgp peers` 命令来确认 BGP 对等连接是否有效。您应会在输出中看到您环境的正确值，会话状态为 `established`。有关故障排除的更多信息，请参阅 Cilium 文档中的 [Troubleshooting and Operations Guide](https://docs.cilium.io/en/latest/network/bgp-control-plane/bgp-control-plane/#troubleshooting-and-operation-guide)。

   在下面的示例中，有五个混合节点在运行 Cilium 代理，每个节点都会通告其拥有的容器组（pod）CIDR 范围。

   ```
   cilium bgp peers
   ```

   ```
   Node                   Local AS    Peer AS               Peer Address        Session State   Uptime     Family         Received   Advertised
   mi-026d6a261e355fba7   NODES_ASN
                     ONPREM_ROUTER_ASN
                     ONPREM_ROUTER_IP    established     1h18m58s   ipv4/unicast   1          2
   mi-082f73826a163626e   NODES_ASN
                     ONPREM_ROUTER_ASN
                     ONPREM_ROUTER_IP    established     1h19m12s   ipv4/unicast   1          2
   mi-09183e8a3d755abf6   NODES_ASN
                     ONPREM_ROUTER_ASN
                     ONPREM_ROUTER_IP    established     1h18m47s   ipv4/unicast   1          2
   mi-0d78d815980ed202d   NODES_ASN
                     ONPREM_ROUTER_ASN
                     ONPREM_ROUTER_IP    established     1h19m12s   ipv4/unicast   1          2
   mi-0daa253999fe92daa   NODES_ASN
                     ONPREM_ROUTER_ASN
                     ONPREM_ROUTER_IP    established     1h18m58s   ipv4/unicast   1          2
   ```

   ```
   cilium bgp routes
   ```

   ```
   Node                   VRouter       Prefix           NextHop   Age         Attrs
   mi-026d6a261e355fba7   NODES_ASN     10.86.2.0/26     0.0.0.0   1h16m46s   [{Origin: i} {Nexthop: 0.0.0.0}]
   mi-082f73826a163626e   NODES_ASN     10.86.2.192/26   0.0.0.0   1h16m46s   [{Origin: i} {Nexthop: 0.0.0.0}]
   mi-09183e8a3d755abf6   NODES_ASN     10.86.2.64/26    0.0.0.0   1h16m46s   [{Origin: i} {Nexthop: 0.0.0.0}]
   mi-0d78d815980ed202d   NODES_ASN     10.86.2.128/26   0.0.0.0   1h16m46s   [{Origin: i} {Nexthop: 0.0.0.0}]
   mi-0daa253999fe92daa   NODES_ASN     10.86.3.0/26     0.0.0.0   1h16m46s   [{Origin: i} {Nexthop: 0.0.0.0}]
   ```

# 为混合节点配置 Kubernetes 入口
<a name="hybrid-nodes-ingress"></a>

本主题介绍如何为在 Amazon EKS 混合节点上运行的工作负载配置 Kubernetes 入口。[Kubernetes 入口](https://kubernetes.io/docs/concepts/services-networking/ingress/)向集群内的服务公开来自集群外部的 HTTP 和 HTTPS 路由。要使用入口资源，需要使用 Kubernetes 入口控制器来设置联网基础设施以及为网络流量提供服务的组件。

 AWS 支持 AWS 应用程序负载均衡器（ALB）和适用于 Kubernetes 入口的 Cilium，可用于在 EKS 混合节点上运行的工作负载。使用 ALB 还是适用于入口的 Cilium，取决于应用程序流量的来源。如果应用程序流量来自某个 AWS 区域，AWS 建议使用 AWS ALB 和 AWS 负载均衡器控制器。如果应用程序流量来自本地或边缘环境，AWS 建议使用 Cilium 的内置入口功能，无论是否在环境中使用负载均衡器基础设施，均可使用该功能。

![\[EKS 混合节点入口\]](http://docs.aws.amazon.com/zh_cn/eks/latest/userguide/images/hybrid-nodes-ingress.png)


## AWS 应用程序负载均衡器
<a name="hybrid-nodes-ingress-alb"></a>

您可以将 [AWS 负载均衡器控制器](aws-load-balancer-controller.md)和目标类型为 `ip` 的应用程序负载均衡器（ALB）用于在混合节点上运行的工作负载。使用目标类型 `ip` 时，ALB 会绕过服务层网络路径，直接将流量转发到容器组（pod）。为了让 ALB 到达混合节点上的容器组（pod）IP 目标，本地容器组（pod）CIDR 必须可在本地网络中路由。此外，AWS 负载均衡器控制器使用 Webhook，需要来自 EKS 控制面板的直接通信。有关更多信息，请参阅 [为混合节点配置 Webhook](hybrid-nodes-webhooks.md)。

### 注意事项
<a name="_considerations"></a>
+ 有关 AWS 应用程序负载均衡器和 AWS 负载均衡器控制器的更多信息，请参阅[使用应用程序负载均衡器路由应用程序和 HTTP 流量](alb-ingress.md)和[使用 Helm 安装 AWS 负载均衡器控制器](lbc-helm.md)。
+ 有关如何在 AWS 应用程序负载均衡器和 AWS 网络负载均衡器之间做出选择的信息，请参阅 [Best Practices for Load Balancing](https://docs.aws.amazon.com/eks/latest/best-practices/load-balacing.html)。
+ 有关可以使用 AWS 应用程序负载均衡器为入口资源配置的注释列表，请参阅 [AWS Load Balancer Controller Ingress annotations](https://kubernetes-sigs.github.io/aws-load-balancer-controller/latest/guide/ingress/annotations/)。

### 先决条件
<a name="_prerequisites"></a>
+ 按照[为混合节点配置 CNI](hybrid-nodes-cni.md)中的说明安装 Cilium。
+ 按照[为混合节点配置 Cilium BGP](hybrid-nodes-cilium-bgp.md) 中的说明启用 Cilium BGP 控制面板。如果您不想使用 BGP，则必须使用其他方法，使本地容器组（pod）CIDR 可在本地网络中路由。如果您不将本地容器组（pod）CIDR 设置为可路由，ALB 将无法注册或联系您的容器组（pod）IP 目标。
+ 在命令行环境中安装 Helm，有关更多信息，请参阅[安装 Helm 说明](helm.md)。
+ 在命令行环境中安装 eksctl，有关更多信息，请参阅 [eksctl 安装说明](install-kubectl.md#eksctl-install-update)。

### 过程
<a name="_procedure"></a>

1. 下载AWS负载均衡器控制器的 IAM 策略，该策略允许负载均衡器代表您调用 AWS API。

   ```
   curl -O https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/refs/heads/main/docs/install/iam_policy.json
   ```

1. 使用上一步中下载的策略创建一个 IAM 策略。

   ```
   aws iam create-policy \
       --policy-name AWSLoadBalancerControllerIAMPolicy \
       --policy-document file://iam_policy.json
   ```

1. 将集群名称 (`CLUSTER_NAME`)、AWS 区域 (`AWS_REGION`) 和 AWS 账户 ID (`AWS_ACCOUNT_ID`) 的值替换为您的设置，然后运行以下命令。

   ```
   eksctl create iamserviceaccount \
       --cluster=CLUSTER_NAME \
       --namespace=kube-system \
       --name=aws-load-balancer-controller \
       --attach-policy-arn=arn:aws:iam::AWS_ACCOUNT_ID:policy/AWSLoadBalancerControllerIAMPolicy \
       --override-existing-serviceaccounts \
       --region AWS_REGION \
       --approve
   ```

1. 添加 eks-charts Helm 图表存储库并更新您的本地 Helm 存储库，确保您拥有最新的图表。

   ```
   helm repo add eks https://aws.github.io/eks-charts
   ```

   ```
   helm repo update eks
   ```

1. 安装AWS负载均衡器控制器。将集群名称 (`CLUSTER_NAME`)、AWS 区域 (`AWS_REGION`)、VPC ID (`VPC_ID`) 和 AWS 负载均衡器控制器 Helm 图表版本 (`AWS_LBC_HELM_VERSION`) 的值替换为您的设置，并运行下列命令。如果您运行的混合模式集群同时包含混合节点和 AWS 云中的节点，则可以按照[AWS Load Balancer Controller](hybrid-nodes-webhooks.md#hybrid-nodes-mixed-lbc) 中的说明，在云端节点上运行 AWS 负载均衡器控制器。
   + 您可以通过运行 `helm search repo eks/aws-load-balancer-controller --versions` 找到最新版本的 Helm 图表。

     ```
     helm install aws-load-balancer-controller eks/aws-load-balancer-controller \
       -n kube-system \
       --version AWS_LBC_HELM_VERSION \
       --set clusterName=CLUSTER_NAME \
       --set region=AWS_REGION \
       --set vpcId=VPC_ID \
       --set serviceAccount.create=false \
       --set serviceAccount.name=aws-load-balancer-controller
     ```

1. 验证 AWS 负载均衡器控制器是否成功安装。

   ```
   kubectl get -n kube-system deployment aws-load-balancer-controller
   ```

   ```
   NAME                           READY   UP-TO-DATE   AVAILABLE   AGE
   aws-load-balancer-controller   2/2     2            2           84s
   ```

1. 创建示例应用程序。以下示例使用 [Istio Bookinfo](https://istio.io/latest/docs/examples/bookinfo/) 示例微服务应用程序。

   ```
   kubectl apply -f https://raw.githubusercontent.com/istio/istio/refs/heads/master/samples/bookinfo/platform/kube/bookinfo.yaml
   ```

1. 使用以下内容创建名为 `my-ingress-alb.yaml` 的文件。

   ```
   apiVersion: networking.k8s.io/v1
   kind: Ingress
   metadata:
     name: my-ingress
     namespace: default
     annotations:
       alb.ingress.kubernetes.io/load-balancer-name: "my-ingress-alb"
       alb.ingress.kubernetes.io/target-type: "ip"
       alb.ingress.kubernetes.io/scheme: "internet-facing"
       alb.ingress.kubernetes.io/healthcheck-path: "/details/1"
   spec:
     ingressClassName: alb
     rules:
     - http:
         paths:
         - backend:
             service:
               name: details
               port:
                 number: 9080
           path: /details
           pathType: Prefix
   ```

1. 将入口配置应用于集群。

   ```
   kubectl apply -f my-ingress-alb.yaml
   ```

1. 为您的入口资源预置 ALB 可能需要几分钟时间。预置 NLB 后，将为您的入口资源分配一个与 ALB 部署的 DNS 名称相对应的地址。该地址将采用以下格式：`<alb-name>-<random-string>.<region>.elb.amazonaws.com`。

   ```
   kubectl get ingress my-ingress
   ```

   ```
   NAME         CLASS   HOSTS   ADDRESS                                                     PORTS   AGE
   my-ingress   alb     *       my-ingress-alb-<random-string>.<region>.elb.amazonaws.com   80      23m
   ```

1. 使用 ALB 的地址访问服务。

   ```
   curl -s http//my-ingress-alb-<random-string>.<region>.elb.amazonaws.com:80/details/1 | jq
   ```

   ```
   {
     "id": 1,
     "author": "William Shakespeare",
     "year": 1595,
     "type": "paperback",
     "pages": 200,
     "publisher": "PublisherA",
     "language": "English",
     "ISBN-10": "1234567890",
     "ISBN-13": "123-1234567890"
     "details": "This is the details page"
   }
   ```

## Cilium 入口和 Cilium 网关概述
<a name="hybrid-nodes-ingress-cilium"></a>

Cilium 的入口功能内置在 Cilium 的架构中，可以使用 Kubernetes 入口 API 或网关 API 进行管理。如果您没有现有的入口资源，AWS 建议您从网关 API 开始，因为它是定义和管理 Kubernetes 联网资源的一种更具表现力和灵活性的方式。[Kubernetes 网关 API](https://gateway-api.sigs.k8s.io/) 旨在标准化在 Kubernetes 集群中定义和管理入口、负载均衡和服务网格的联网资源的方式。

启用 Cilium 的入口或网关功能时，Cilium 管理器会协调集群中的入口/网关对象，每个节点上的 Envoy 代理负责处理第 7 层（L7）网络流量。Cilium 不直接预置入口/网关基础设施，例如负载均衡器。如果您计划将 Cilium 入口/网关与负载均衡器一起使用，则必须使用负载均衡器的工具（通常是入口或网关控制器）来部署和管理负载均衡器的基础设施。

对于入口/网关流量，Cilium 会处理核心网络流量和 L3/L4 策略执行，集成的 Envoy 代理负责处理第 7 层网络流量。借助 Cilium 入口/网关，Envoy 负责应用 L7 路由规则、策略和请求操作、高级流量管理（例如流量拆分和镜像）以及 TLS 终止和发起。默认情况下，Cilium 的 Envoy 代理作为单独的 DaemonSet (`cilium-envoy`) 部署，这使得可以单独对 Envoy 和 Cilium 代理进行更新、扩展和管理。

有关 Cilium 入口和 Cilium 网关如何工作的更多信息，请参阅 Cilium 文档中的 [Cilium Ingress](https://docs.cilium.io/en/stable/network/servicemesh/ingress/) 和 [Cilium Gateway](https://docs.cilium.io/en/stable/network/servicemesh/gateway-api/gateway-api/) 页面。

## Cilium 入口和网关比较
<a name="hybrid-nodes-ingress-cilium-comparison"></a>

下表汇总了截至 **Cilium 1.17.x 版本**的 Cilium 入口和 Cilium 网关功能。


| 功能 | 入口 | Gateway | 
| --- | --- | --- | 
|  服务类型 LoadBalancer  |  支持  |  是  | 
|  服务类型 NodePort  |  是  |  否1   | 
|  主机网络  |  支持  |  是  | 
|  共享负载均衡器  |  支持  |  是  | 
|  专用负载均衡器  |  是  |  否2   | 
|  网络策略  |  支持  |  是  | 
|  协议  |  第 7 层 [HTTP（S）、gRPC]  |  第 7 层 [HTTP（S）、gRPC]3   | 
|  TLS 传递  |  支持  |  是  | 
|  流量管理  |  路径和主机路由  |  路径和主机路由、URL 重定向和重写、流量拆分、标头修改  | 

 1 Cilium 1.18.x 版本计划提供 NodePort 服务的 Cilium 网关支持（[\$127273](https://github.com/cilium/cilium/pull/27273)）

 2 针对专用负载均衡器的 Cilium 网关支持（[\$125567](https://github.com/cilium/cilium/issues/25567)）

 3 针对 TCP/UDP 的 Cilium 网关支持（[\$121929](https://github.com/cilium/cilium/issues/21929)）

## 安装 Cilim 网关
<a name="hybrid-nodes-ingress-cilium-gateway-install"></a>

### 注意事项
<a name="_considerations_2"></a>
+ 配置 Cilium 时，必须将 `nodePort.enabled` 设置为 `true`，如下列示例所示。如果您使用的是 Cilium 的 kube-proxy 替换功能，则无需将 `nodePort.enabled` 设置为 `true`。
+ 配置 Cilium 时，必须将 `envoy.enabled` 设置为 `true`，如下列示例所示。
+ Cilium 网关可以在负载均衡器（默认）或主机网络模式下部署。
+ 在负载均衡器模式下使用 Cilium 网关时，必须在网关资源上设置 `service.beta.kubernetes.io/aws-load-balancer-type: "external"` 注释，以防止传统 AWS 云提供商为 Cilium 为网关资源创建的 LoadBalancer 类型服务创建经典负载均衡器。
+ 在主机网络模式下使用 Cilium 网关时，将禁用 LoadBalancer 模式类型的服务。主机网络模式对于没有负载均衡器基础设施的环境非常有用，有关更多信息，请参阅[主机网络](#hybrid-nodes-ingress-cilium-host-network)。

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

1. 在命令行环境中安装 Helm，请参阅[安装 Helm 说明](helm.md)。

1. 按照[为混合节点配置 CNI](hybrid-nodes-cni.md)中的说明安装 Cilium。

### 过程
<a name="_procedure_2"></a>

1. 安装 Kubernetes 网关 API 自定义资源定义（CRD）。

   ```
   kubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/gateway-api/v1.2.1/config/crd/standard/gateway.networking.k8s.io_gatewayclasses.yaml
   kubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/gateway-api/v1.2.1/config/crd/standard/gateway.networking.k8s.io_gateways.yaml
   kubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/gateway-api/v1.2.1/config/crd/standard/gateway.networking.k8s.io_httproutes.yaml
   kubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/gateway-api/v1.2.1/config/crd/standard/gateway.networking.k8s.io_referencegrants.yaml
   kubectl apply -f https://raw.githubusercontent.com/kubernetes-sigs/gateway-api/v1.2.1/config/crd/standard/gateway.networking.k8s.io_grpcroutes.yaml
   ```

1. 创建以下内容的名为 `cilium-gateway-values.yaml` 的文件。以下示例将 Cilium 网关配置为使用默认负载均衡器模式，并为配置为仅在混合节点上运行的 Envoy 代理使用单独的 `cilium-envoy` DaemonSet。

   ```
   gatewayAPI:
     enabled: true
     # uncomment to use host network mode
     # hostNetwork:
     #   enabled: true
   nodePort:
     enabled: true
   envoy:
     enabled: true
     affinity:
       nodeAffinity:
         requiredDuringSchedulingIgnoredDuringExecution:
           nodeSelectorTerms:
           - matchExpressions:
             - key: eks.amazonaws.com/compute-type
               operator: In
               values:
               - hybrid
   ```

1. 将 Helm 值文件应用于集群。

   ```
   helm upgrade cilium oci://public.ecr.aws/eks/cilium/cilium \
     --namespace kube-system \
     --reuse-values \
     --set operator.rollOutPods=true \
     --values cilium-gateway-values.yaml
   ```

1. 确认 Cilium 管理器、代理和 Envoy 容器组（pod）正在运行。

   ```
   kubectl -n kube-system get pods --selector=app.kubernetes.io/part-of=cilium
   ```

   ```
   NAME                               READY   STATUS    RESTARTS   AGE
   cilium-envoy-5pgnd                 1/1     Running   0          6m31s
   cilium-envoy-6fhg4                 1/1     Running   0          6m30s
   cilium-envoy-jskrk                 1/1     Running   0          6m30s
   cilium-envoy-k2xtb                 1/1     Running   0          6m31s
   cilium-envoy-w5s9j                 1/1     Running   0          6m31s
   cilium-grwlc                       1/1     Running   0          4m12s
   cilium-operator-68f7766967-5nnbl   1/1     Running   0          4m20s
   cilium-operator-68f7766967-7spfz   1/1     Running   0          4m20s
   cilium-pnxcv                       1/1     Running   0          6m29s
   cilium-r7qkj                       1/1     Running   0          4m12s
   cilium-wxhfn                       1/1     Running   0          4m1s
   cilium-z7hlb                       1/1     Running   0          6m30s
   ```

## 配置 Cilim 网关
<a name="hybrid-nodes-ingress-cilium-gateway-configure"></a>

通过将 `gatewayClassName` 设置为 `cilium`，可以在网关对象上启用 Cilium 网关。Cilium 为网关资源创建的服务可以使用网关对象上的字段进行配置。可以使用网关对象的 `infrastructure` 字段，配置网关控制器用于配置负载均衡器基础设施的常用注释。使用 Cilium 的 LoadBalancer IPAM（请参阅[服务类型 LoadBalancer](#hybrid-nodes-ingress-cilium-loadbalancer)中的示例）时，可以在网关对象的 `addresses` 字段上配置用于 LoadBalancer 类型服务的 IP 地址。有关网关配置的更多信息，请参阅 [Kubernetes Gateway API specification](https://gateway-api.sigs.k8s.io/reference/spec/#gateway)。

```
apiVersion: gateway.networking.k8s.io/v1
kind: Gateway
metadata:
  name: my-gateway
spec:
  gatewayClassName: cilium
  infrastructure:
    annotations:
      service.beta.kubernetes.io/...
      service.kuberentes.io/...
  addresses:
  - type: IPAddress
    value: <LoadBalancer IP address>
  listeners:
  ...
```

Cilium 和 Kubernetes 网关规范支持 GatewayClass、网关、httpRoute、grpcRoute 和 ReferenceGrant 资源。
+ 有关可用字段的列表，请参阅 [HTTPRoute](https://gateway-api.sigs.k8s.io/api-types/httproute/HTTPRoute) 和 [GRPCRoute](https://gateway-api.sigs.k8s.io/api-types/grpcroute/GRPCRoute) 规范。
+ 有关如何使用和配置这些资源，请参阅以下[部署 Cilium 网关](#hybrid-nodes-ingress-cilium-gateway-deploy)部分中的示例和 [Cilium 文档](https://docs.cilium.io/en/stable/network/servicemesh/gateway-api/gateway-api/#examples)中的示例。

## 部署 Cilium 网关
<a name="hybrid-nodes-ingress-cilium-gateway-deploy"></a>

1. 创建示例应用程序。以下示例使用 [Istio Bookinfo](https://istio.io/latest/docs/examples/bookinfo/) 示例微服务应用程序。

   ```
   kubectl apply -f https://raw.githubusercontent.com/istio/istio/refs/heads/master/samples/bookinfo/platform/kube/bookinfo.yaml
   ```

1. 确认应用程序在成功运行。

   ```
   kubectl get pods
   ```

   ```
   NAME                              READY   STATUS    RESTARTS   AGE
   details-v1-766844796b-9965p       1/1     Running   0          81s
   productpage-v1-54bb874995-jmc8j   1/1     Running   0          80s
   ratings-v1-5dc79b6bcd-smzxz       1/1     Running   0          80s
   reviews-v1-598b896c9d-vj7gb       1/1     Running   0          80s
   reviews-v2-556d6457d-xbt8v        1/1     Running   0          80s
   reviews-v3-564544b4d6-cpmvq       1/1     Running   0          80s
   ```

1. 使用以下内容创建名为 `my-gateway.yaml` 的文件。以下示例使用 `service.beta.kubernetes.io/aws-load-balancer-type: "external"` 注释，防止传统 AWS 云提供商为 Cilium 为网关资源创建的 LoadBalancer 类型服务创建经典负载均衡器。

   ```
   ---
   apiVersion: gateway.networking.k8s.io/v1
   kind: Gateway
   metadata:
     name: my-gateway
   spec:
     gatewayClassName: cilium
     infrastructure:
       annotations:
         service.beta.kubernetes.io/aws-load-balancer-type: "external"
     listeners:
     - protocol: HTTP
       port: 80
       name: web-gw
       allowedRoutes:
         namespaces:
           from: Same
   ---
   apiVersion: gateway.networking.k8s.io/v1
   kind: HTTPRoute
   metadata:
     name: http-app-1
   spec:
     parentRefs:
     - name: my-gateway
       namespace: default
     rules:
     - matches:
       - path:
           type: PathPrefix
           value: /details
       backendRefs:
       - name: details
         port: 9080
   ```

1. 将网关资源应用于集群。

   ```
   kubectl apply -f my-gateway.yaml
   ```

1. 确认网关资源和相应的服务已创建。在此阶段，预计网关资源的 `ADDRESS` 字段中没有填充 IP 地址或主机名，网关资源的 LoadBalancer 类型服务同样没有分配 IP 地址或主机名。

   ```
   kubectl get gateway my-gateway
   ```

   ```
   NAME         CLASS    ADDRESS   PROGRAMMED   AGE
   my-gateway   cilium             True         10s
   ```

   ```
   kubectl get svc cilium-gateway-my-gateway
   ```

   ```
   NAME                        TYPE           CLUSTER-IP       EXTERNAL-IP   PORT(S)        AGE
   cilium-gateway-my-gateway   LoadBalancer   172.16.227.247   <pending>     80:30912/TCP   24s
   ```

1. 继续执行[服务类型 LoadBalancer](#hybrid-nodes-ingress-cilium-loadbalancer)，将网关资源配置为使用 Cilium 负载均衡器 IPAM 分配的 IP 地址，并执行[服务类型 NodePort](#hybrid-nodes-ingress-cilium-nodeport)或[主机网络](#hybrid-nodes-ingress-cilium-host-network)，将网关资源配置为使用 NodePort 或主机网络地址。

## 安装 Cilium 入口
<a name="hybrid-nodes-ingress-cilium-ingress-install"></a>

### 注意事项
<a name="_considerations_3"></a>
+ 配置 Cilium 时，必须将 `nodePort.enabled` 设置为 `true`，如下列示例所示。如果您使用的是 Cilium 的 kube-proxy 替换功能，则无需将 `nodePort.enabled` 设置为 `true`。
+ 配置 Cilium 时，必须将 `envoy.enabled` 设置为 `true`，如下列示例所示。
+ 将 `ingressController.loadbalancerMode` 设置为 `dedicated` 后，Cilium 会为每个入口资源创建专用服务。将 `ingressController.loadbalancerMode` 设置为 `shared` 后，Cilium 会为集群中的所有入口资源创建 LoadBalancer 类型的共享服务。使用 `shared` 负载均衡器模式时，共享服务的设置（例如 `labels`、`annotations`、`type` 和 `loadBalancerIP`）在 Helm 值的 `ingressController.service` 部分中进行配置。有关更多信息，请参阅 [Cilium Helm values reference](https://github.com/cilium/cilium/blob/v1.17.6/install/kubernetes/cilium/values.yaml#L887)。
+ 将 `ingressController.default` 设置为 `true` 后，Cilium 将被配置为集群的默认入口控制器并会创建入口条目（即使未在入口资源上指定 `ingressClassName`，也是如此）。
+ Cilium 入口可以在负载均衡器（默认）、节点端口或主机网络模式下部署。在主机网络模式下安装 Cilium 时，将禁用 LoadBalancer 类型服务和 NodePort 类型服务的模式。请参阅[主机网络](#hybrid-nodes-ingress-cilium-host-network)了解更多信息。
+ 在 Helm 值中，始终将 `ingressController.service.annotations` 设置为 `service.beta.kubernetes.io/aws-load-balancer-type: "external"`，以防止传统 AWS 云提供商为 [Cilium Helm 图表](https://github.com/cilium/cilium/blob/main/install/kubernetes/cilium/templates/cilium-ingress-service.yaml)创建的默认 `cilium-ingress` 服务创建经典负载均衡器。

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

1. 在命令行环境中安装 Helm，请参阅[安装 Helm 说明](helm.md)。

1. 按照[为混合节点配置 CNI](hybrid-nodes-cni.md)中的说明安装 Cilium。

### 过程
<a name="_procedure_3"></a>

1. 创建以下内容的名为 `cilium-ingress-values.yaml` 的文件。以下示例将 Cilium 入口配置为使用默认负载均衡器 `dedicated` 模式，并对配置为仅在混合节点上运行的 Envoy 代理使用单独的 `cilium-envoy` DaemonSet。

   ```
   ingressController:
     enabled: true
     loadbalancerMode: dedicated
     service:
       annotations:
         service.beta.kubernetes.io/aws-load-balancer-type: "external"
   nodePort:
     enabled: true
   envoy:
     enabled: true
     affinity:
       nodeAffinity:
         requiredDuringSchedulingIgnoredDuringExecution:
           nodeSelectorTerms:
           - matchExpressions:
             - key: eks.amazonaws.com/compute-type
               operator: In
               values:
               - hybrid
   ```

1. 将 Helm 值文件应用于集群。

   ```
   helm upgrade cilium oci://public.ecr.aws/eks/cilium/cilium \
     --namespace kube-system \
     --reuse-values \
     --set operator.rollOutPods=true \
     --values cilium-ingress-values.yaml
   ```

1. 确认 Cilium 管理器、代理和 Envoy 容器组（pod）正在运行。

   ```
   kubectl -n kube-system get pods --selector=app.kubernetes.io/part-of=cilium
   ```

   ```
   NAME                               READY   STATUS    RESTARTS   AGE
   cilium-envoy-5pgnd                 1/1     Running   0          6m31s
   cilium-envoy-6fhg4                 1/1     Running   0          6m30s
   cilium-envoy-jskrk                 1/1     Running   0          6m30s
   cilium-envoy-k2xtb                 1/1     Running   0          6m31s
   cilium-envoy-w5s9j                 1/1     Running   0          6m31s
   cilium-grwlc                       1/1     Running   0          4m12s
   cilium-operator-68f7766967-5nnbl   1/1     Running   0          4m20s
   cilium-operator-68f7766967-7spfz   1/1     Running   0          4m20s
   cilium-pnxcv                       1/1     Running   0          6m29s
   cilium-r7qkj                       1/1     Running   0          4m12s
   cilium-wxhfn                       1/1     Running   0          4m1s
   cilium-z7hlb                       1/1     Running   0          6m30s
   ```

## 配置 Cilium 入口
<a name="hybrid-nodes-ingress-cilium-ingress-configure"></a>

通过将 `ingressClassName` 设置为 `cilium`，可以在入口对象上启用 Cilium 入口。Cilium 为入口资源创建的服务在使用 `dedicated` 负载均衡器模式时可以在入口对象上使用注释进行配置，在使用 `shared` 负载均衡器模式时可以在 Cilium/Helm 配置中进行配置。入口控制器通常使用这些注释来配置负载均衡器基础设施或服务的其他属性，例如服务类型、负载均衡器模式、端口和 TLS 传递。下面介绍了关键注释。有关支持的注释的完整列表，请参阅 Cilium 文档中的 [Cilium Ingress annotations](https://docs.cilium.io/en/stable/network/servicemesh/ingress/#supported-ingress-annotations)。


| 注释 | 描述 | 
| --- | --- | 
|   `ingress.cilium.io/loadbalancer-mode`   |   `dedicated`：每个入口资源的 LoadBalancer 类型的专用服务（默认）。  `shared`：所有入口资源的 LoadBalancer 类型的单一服务。  | 
|   `ingress.cilium.io/service-type`   |   `LoadBalancer`：该服务将为 LoadBalancer 类型（默认）  `NodePort`：该服务将为 NodePort 类型。  | 
|   `service.beta.kubernetes.io/aws-load-balancer-type`   |   `"external"`：防止传统 AWS 云提供商为 LoadBalancer 类型服务预置经典负载均衡器。  | 
|   `lbipam.cilium.io/ips`   |  要从 Cilium LoadBalancer IPAM 分配的 IP 地址列表  | 

Cilium 和 Kubernetes 入口规范支持入口路径的精确、前缀和特定于实现的匹配规则。Cilium 支持正则表达式作为其特定于实现的匹配规则。有关更多信息，请参阅 Cilium 文档中的 [Ingress path types and precedence](https://docs.cilium.io/en/stable/network/servicemesh/ingress/#ingress-path-types-and-precedence) 和 [Path types examples](https://docs.cilium.io/en/stable/network/servicemesh/path-types/)，以及本页[部署 Cilium 入口](#hybrid-nodes-ingress-cilium-ingress-deploy)部分中的示例。

以下显示了示例 Cilium 入口对象。

```
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-ingress
  annotations:
    service.beta.kuberentes.io/...
    service.kuberentes.io/...
spec:
  ingressClassName: cilium
  rules:
  ...
```

## 部署 Cilium 入口
<a name="hybrid-nodes-ingress-cilium-ingress-deploy"></a>

1. 创建示例应用程序。以下示例使用 [Istio Bookinfo](https://istio.io/latest/docs/examples/bookinfo/) 示例微服务应用程序。

   ```
   kubectl apply -f https://raw.githubusercontent.com/istio/istio/refs/heads/master/samples/bookinfo/platform/kube/bookinfo.yaml
   ```

1. 确认应用程序在成功运行。

   ```
   kubectl get pods
   ```

   ```
   NAME                              READY   STATUS    RESTARTS   AGE
   details-v1-766844796b-9965p       1/1     Running   0          81s
   productpage-v1-54bb874995-jmc8j   1/1     Running   0          80s
   ratings-v1-5dc79b6bcd-smzxz       1/1     Running   0          80s
   reviews-v1-598b896c9d-vj7gb       1/1     Running   0          80s
   reviews-v2-556d6457d-xbt8v        1/1     Running   0          80s
   reviews-v3-564544b4d6-cpmvq       1/1     Running   0          80s
   ```

1. 使用以下内容创建名为 `my-ingress.yaml` 的文件。以下示例使用 `service.beta.kubernetes.io/aws-load-balancer-type: "external"` 注释，防止传统 AWS 云提供商为 Cilium 为入口资源创建的 LoadBalancer 类型服务创建经典负载均衡器。

   ```
   apiVersion: networking.k8s.io/v1
   kind: Ingress
   metadata:
     name: my-ingress
     namespace: default
     annotations:
       service.beta.kubernetes.io/aws-load-balancer-type: "external"
   spec:
     ingressClassName: cilium
     rules:
     - http:
         paths:
         - backend:
             service:
               name: details
               port:
                 number: 9080
           path: /details
           pathType: Prefix
   ```

1. 将入口资源应用于集群。

   ```
   kubectl apply -f my-ingress.yaml
   ```

1. 确认入口资源和相应的服务已创建。在此阶段，预计入口资源的 `ADDRESS` 字段中没有填充 IP 地址或主机名，同样，入口资源的 LoadBalancer 类型的共享或专用服务也没有分配 IP 地址或主机名。

   ```
   kubectl get ingress my-ingress
   ```

   ```
   NAME         CLASS    HOSTS   ADDRESS   PORTS   AGE
   my-ingress   cilium   *                 80      8s
   ```

   适用于负载均衡器模式 `shared` 

   ```
   kubectl -n kube-system get svc cilium-ingress
   ```

   ```
   NAME             TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)                      AGE
   cilium-ingress   LoadBalancer   172.16.217.48   <pending>     80:32359/TCP,443:31090/TCP   10m
   ```

   适用于负载均衡器模式 `dedicated` 

   ```
   kubectl -n default get svc cilium-ingress-my-ingress
   ```

   ```
   NAME                        TYPE           CLUSTER-IP      EXTERNAL-IP   PORT(S)                      AGE
   cilium-ingress-my-ingress   LoadBalancer   172.16.193.15   <pending>     80:32088/TCP,443:30332/TCP   25s
   ```

1. 继续执行[服务类型 LoadBalancer](#hybrid-nodes-ingress-cilium-loadbalancer)，将入口资源配置为使用 Cilium 负载均衡器 IPAM 分配的 IP 地址，并执行[服务类型 NodePort](#hybrid-nodes-ingress-cilium-nodeport)或[主机网络](#hybrid-nodes-ingress-cilium-host-network)，将入口资源配置为使用 NodePort 或主机网络地址。

## 服务类型 LoadBalancer
<a name="hybrid-nodes-ingress-cilium-loadbalancer"></a>

### 现有的负载均衡器基础设施
<a name="_existing_load_balancer_infrastructure"></a>

默认情况下，对于 Cilium 入口和 Cilium 网关，Cilium 会为入口/网关资源创建 LoadBalancer 类型的 Kubernetes 服务。Cilium 创建的服务的属性可以通过入口和网关资源进行配置。在创建入口或网关资源时，入口或网关的对外部公开的 IP 地址或主机名是从负载均衡器基础设施进行分配，而负载均衡器基础设施通常由入口或网关控制器预置。

许多入口和网关控制器都使用注释来检测和配置负载均衡器基础设施。这些入口和网关控制器的注释是在入口或网关资源上配置，如上面的示例所示。请参阅入口或网关控制器的文档，了解其支持的注释，并参阅 [Kubernetes 入口文档](https://kubernetes.io/docs/concepts/services-networking/ingress-controllers/)和 [Kubernetes 网关文档](https://gateway-api.sigs.k8s.io/implementations/)，获取常用控制器列表。

**重要**  
在具有 EKS 混合节点的情况下，Cilium 入口和网关不能与 AWS 负载均衡器控制器和 AWS 网络负载均衡器（NLB）一起使用。尝试将它们一起使用会导致目标未注册，因为当 NLB 的 `target-type` 设置为 `ip` 时（在 EKS 混合节点上运行工作负载时使用 NLB 的要求），NLB 会尝试直接连接到支持 LoadBalancer 类型服务的容器组（pod）IP。

### 没有负载均衡器基础设施
<a name="_no_load_balancer_infrastructure"></a>

如果您的环境中没有负载均衡器基础设施和相应的入口/网关控制器，则可以将入口/网关资源和相应的 LoadBalancer 类型服务配置为使用 Cilium 的 [负载均衡器 IP 地址管理](https://docs.cilium.io/en/stable/network/lb-ipam/)（LB IPAM）分配的 IP 地址。Cilium LB IPAM 可以使用本地环境中的已知 IP 地址范围进行配置，并且可以使用 Cilium 的内置边界网关协议（BGP）支持或 L2 通告向您的本地网络通告 LoadBalancer IP 地址。

以下示例说明如何使用用于入口/网关资源的 IP 地址配置 Cilium 的 LB IPAM，以及如何配置 Cilium BGP 控制面板以向本地网络通告 LoadBalancer IP 地址。默认情况下，Cilium 的 LB IPAM 功能处于启用状态，但在创建 `CiliumLoadBalancerIPPool` 资源后才会激活。

#### 先决条件
<a name="_prerequisites_4"></a>
+ 按照[安装 Cilium 入口](#hybrid-nodes-ingress-cilium-ingress-install)或[安装 Cilim 网关](#hybrid-nodes-ingress-cilium-gateway-install)中的说明安装 Cilium 入口或网关。
+ 按照[部署 Cilium 入口](#hybrid-nodes-ingress-cilium-ingress-deploy)或[部署 Cilium 网关](#hybrid-nodes-ingress-cilium-gateway-deploy)中的说明部署带有示例应用程序的 Cilium 入口或网关资源。
+ 按照[为混合节点配置 Cilium BGP](hybrid-nodes-cilium-bgp.md) 中的说明启用 Cilium BGP 控制面板。如果您不想使用 BGP，则可以跳过此先决条件，但是在 Cilium LB IPAM 分配的 LoadBalancer IP 地址可在本地网络上路由之前，您无法访问您的入口或网关资源。

#### 过程
<a name="_procedure_4"></a>

1. 可选择修补入口或网关资源，以请求用于 LoadBalancer 类型服务的特定 IP 地址。如果您不请求特定 IP 地址，Cilium 将在后续步骤中从 `CiliumLoadBalancerIPPool` 资源中配置的 IP 地址范围分配一个 IP 地址。在下面的命令中，将 `LB_IP_ADDRESS` 替换为请求 LoadBalancer 类型服务的 IP 地址。

    **网关** 

   ```
   kubectl patch gateway -n default my-gateway --type=merge -p '{
     "spec": {
       "addresses": [{"type": "IPAddress", "value": "LB_IP_ADDRESS"}]
     }
   }'
   ```

    **入口** 

   ```
   kubectl patch ingress my-ingress --type=merge -p '{
     "metadata": {"annotations": {"lbipam.cilium.io/ips": "LB_IP_ADDRESS"}}
   }'
   ```

1. 使用 `CiliumLoadBalancerIPPool` 资源创建一个名为 `cilium-lbip-pool-ingress.yaml` 的文件，用于为您的入口/网关资源配置负载均衡器 IP 地址范围。
   + 如果使用的是 Cilium 入口，Cilium 会自动将 `cilium.io/ingress: "true"` 标签应用于它为入口资源创建的服务。您可以在 `CiliumLoadBalancerIPPool` 资源定义的 `serviceSelector` 字段中使用此标签来选择符合 LB IPAM 条件的服务。
   + 如果您使用的是 Cilium 网关，则可以使用 `CiliumLoadBalancerIPPool` 资源定义 `serviceSelector` 字段中的 `gateway.networking.k8s.io/gateway-name` 标签来选择符合 LB IPAM 条件的网关资源。
   + 将 `LB_IP_CIDR` 替换为用于负载均衡器 IP 地址的 IP 地址范围。要选择单个 IP 地址，请使用 `/32` CIDR。有关更多信息，请参阅 Cilium 文档中的 [LoadBalancer IP Address Management](https://docs.cilium.io/en/stable/network/lb-ipam/)。

     ```
     apiVersion: cilium.io/v2alpha1
     kind: CiliumLoadBalancerIPPool
     metadata:
       name: bookinfo-pool
     spec:
       blocks:
       - cidr: "LB_IP_CIDR"
       serviceSelector:
         # if using Cilium Gateway
         matchExpressions:
           - { key: gateway.networking.k8s.io/gateway-name, operator: In, values: [ my-gateway ] }
         # if using Cilium Ingress
         matchLabels:
           cilium.io/ingress: "true"
     ```

1. 将 `CiliumLoadBalancerIPPool` 资源应用于集群。

   ```
   kubectl apply -f cilium-lbip-pool-ingress.yaml
   ```

1. 确认已从 Cilium LB IPAM 为入口/网关资源分配了 IP 地址。

    **网关** 

   ```
   kubectl get gateway my-gateway
   ```

   ```
   NAME         CLASS    ADDRESS        PROGRAMMED   AGE
   my-gateway   cilium   LB_IP_ADDRESS    True         6m41s
   ```

    **入口** 

   ```
   kubectl get ingress my-ingress
   ```

   ```
   NAME         CLASS    HOSTS   ADDRESS        PORTS   AGE
   my-ingress   cilium   *       LB_IP_ADDRESS   80      10m
   ```

1. 使用 `CiliumBGPAdvertisement` 资源创建一个名为 `cilium-bgp-advertisement-ingress.yaml` 的文件，用于通告入口/网关资源的 LoadBalancer IP 地址。如果您不使用 Cilium BGP，则可跳过此步骤。用于入口/网关资源的 LoadBalancer IP 地址必须可在本地网络上路由，这样您才能在下一步中查询该服务。

   ```
   apiVersion: cilium.io/v2alpha1
   kind: CiliumBGPAdvertisement
   metadata:
     name: bgp-advertisement-lb-ip
     labels:
       advertise: bgp
   spec:
     advertisements:
       - advertisementType: "Service"
         service:
           addresses:
             - LoadBalancerIP
         selector:
           # if using Cilium Gateway
           matchExpressions:
             - { key: gateway.networking.k8s.io/gateway-name, operator: In, values: [ my-gateway ] }
           # if using Cilium Ingress
           matchLabels:
             cilium.io/ingress: "true"
   ```

1. 将 `CiliumBGPAdvertisement` 资源应用于集群。

   ```
   kubectl apply -f cilium-bgp-advertisement-ingress.yaml
   ```

1. 使用从 Cilium LB IPAM 分配的 IP 地址访问该服务。

   ```
   curl -s http://LB_IP_ADDRESS:80/details/1 | jq
   ```

   ```
   {
     "id": 1,
     "author": "William Shakespeare",
     "year": 1595,
     "type": "paperback",
     "pages": 200,
     "publisher": "PublisherA",
     "language": "English",
     "ISBN-10": "1234567890",
     "ISBN-13": "123-1234567890"
   }
   ```

## 服务类型 NodePort
<a name="hybrid-nodes-ingress-cilium-nodeport"></a>

如果您的环境中没有负载均衡器基础设施和相应的入口控制器，或者您要自行管理负载均衡器基础设施或使用基于 DNS 的负载均衡，则可以将 Cilium 入口配置成为入口资源创建 NodePort 类型服务。将 NodePort 与 Cilium 入口配合使用时，NodePort 类型服务会在端口范围为 30000-32767 的每个节点的端口上公开。在此模式下，当流量到达 NodePort 上集群中的任何节点时，它会被转发到支持该服务的容器组（pod），而该容器组可能位于同一节点或不同节点上。

**注意**  
Cilium 1.18.x 版本计划提供 NodePort 服务的 Cilium 网关支持（[\$127273](https://github.com/cilium/cilium/pull/27273)）

### 先决条件
<a name="_prerequisites_5"></a>
+ 按照[安装 Cilium 入口](#hybrid-nodes-ingress-cilium-ingress-install)中的说明安装Cilium 入口。
+ 按照[部署 Cilium 入口](#hybrid-nodes-ingress-cilium-ingress-deploy)中的说明部署带有示例应用程序的 Cilium 入口资源。

### 过程
<a name="_procedure_5"></a>

1. 修补现有入口资源 `my-ingress`，将其从 LoadBalancer 类型服务更改为 NodePort 类型服务。

   ```
   kubectl patch ingress my-ingress --type=merge -p '{
       "metadata": {"annotations": {"ingress.cilium.io/service-type": "NodePort"}}
   }'
   ```

   如果您尚未创建入口资源，则可以通过将以下入口定义应用于集群来创建它。请注意，下面的入口定义使用了[部署 Cilium 入口](#hybrid-nodes-ingress-cilium-ingress-deploy)中所述的 Istio Bookinfo 示例应用程序。

   ```
   apiVersion: networking.k8s.io/v1
   kind: Ingress
   metadata:
     name: my-ingress
     namespace: default
     annotations:
       service.beta.kubernetes.io/aws-load-balancer-type: "external"
       "ingress.cilium.io/service-type": "NodePort"
   spec:
     ingressClassName: cilium
     rules:
     - http:
         paths:
         - backend:
             service:
               name: details
               port:
                 number: 9080
           path: /details
           pathType: Prefix
   ```

1. 确认入口资源的服务已更新为使用 NodePort 类型服务。记下输出中 HTTP 协议的端口。在下面的示例中，此 HTTP 端口为 `32353`，将在后续步骤中使用它来查询服务。将 Cilium 入口与 NodePort 类型服务配合使用的好处是，您可以为入口流量应用基于路径和主机的路由，以及网络策略，而对于没有入口的 NodePort 类型的标准服务，则无法做到这一点。

   ```
   kubectl -n default get svc cilium-ingress-my-ingress
   ```

   ```
   NAME                        TYPE       CLUSTER-IP      EXTERNAL-IP   PORT(S)                      AGE
   cilium-ingress-my-ingress   NodePort   172.16.47.153   <none>        80:32353/TCP,443:30253/TCP   27m
   ```

1. 获取集群节点的 IP 地址。

   ```
   kubectl get nodes -o wide
   ```

   ```
   NAME                   STATUS   ROLES    AGE   VERSION               INTERNAL-IP     EXTERNAL-IP   OS-IMAGE             KERNEL-VERSION       CONTAINER-RUNTIME
   mi-026d6a261e355fba7   Ready    <none>   23h   v1.32.3-eks-473151a   10.80.146.150   <none>        Ubuntu 22.04.5 LTS   5.15.0-142-generic   containerd://1.7.27
   mi-082f73826a163626e   Ready    <none>   23h   v1.32.3-eks-473151a   10.80.146.32    <none>        Ubuntu 22.04.4 LTS   5.15.0-142-generic   containerd://1.7.27
   mi-09183e8a3d755abf6   Ready    <none>   23h   v1.32.3-eks-473151a   10.80.146.33    <none>        Ubuntu 22.04.4 LTS   5.15.0-142-generic   containerd://1.7.27
   mi-0d78d815980ed202d   Ready    <none>   23h   v1.32.3-eks-473151a   10.80.146.97    <none>        Ubuntu 22.04.4 LTS   5.15.0-142-generic   containerd://1.7.27
   mi-0daa253999fe92daa   Ready    <none>   23h   v1.32.3-eks-473151a   10.80.146.100   <none>        Ubuntu 22.04.4 LTS   5.15.0-142-generic   containerd://1.7.27
   ```

1. 使用您的节点的 IP 地址和上面捕获的 NodePort 访问 NodePort 类型服务。在下面的示例中，使用的节点 IP 地址是 `10.80.146.32`，NodePort 是 `32353`。请将这些值替换为您环境的相应值。

   ```
   curl -s http://10.80.146.32:32353/details/1 | jq
   ```

   ```
   {
     "id": 1,
     "author": "William Shakespeare",
     "year": 1595,
     "type": "paperback",
     "pages": 200,
     "publisher": "PublisherA",
     "language": "English",
     "ISBN-10": "1234567890",
     "ISBN-13": "123-1234567890"
   }
   ```

## 主机网络
<a name="hybrid-nodes-ingress-cilium-host-network"></a>

与 NodePort 类型服务类似，如果您没有负载均衡器基础设施和入口或网关控制器，或者您要使用外部负载均衡器自行管理负载均衡，则可以将 Cilium 入口和 Cilium 网关配置为直接在主机网络上公开入口和网关资源。当为入口或网关资源启用主机网络模式时，会自动禁用 LoadBalancer 类型服务和 NodePort 类型服务的模式，主机网络模式与每个入口或网关资源的这些替代模式相互排斥。与 NodePort 类型服务模式相比，主机网络模式为可使用的端口范围提供了更大灵活性（不限于 30000-32767 NodePort 范围），您可以配置 Envoy 代理在主机网络上运行的节点子集。

### 先决条件
<a name="_prerequisites_6"></a>
+ 按照[安装 Cilium 入口](#hybrid-nodes-ingress-cilium-ingress-install)或[安装 Cilim 网关](#hybrid-nodes-ingress-cilium-gateway-install)中的说明安装 Cilium 入口或网关。

### 过程
<a name="_procedure_6"></a>

#### Gateway
<a name="_gateway"></a>

1. 使用以下内容创建名为 `cilium-gateway-host-network.yaml` 的文件。

   ```
   gatewayAPI:
     enabled: true
     hostNetwork:
       enabled: true
       # uncomment to restrict nodes where Envoy proxies run on the host network
       # nodes:
       #   matchLabels:
       #     role: gateway
   ```

1. 将主机网络 Cilium 网关配置应用于集群。

   ```
   helm upgrade cilium oci://public.ecr.aws/eks/cilium/cilium \
     --namespace kube-system \
     --reuse-values \
     --set operator.rollOutPods=true \
     -f cilium-gateway-host-network.yaml
   ```

   如果您尚未创建网关资源，则可以通过将以下网关定义应用于集群来创建它。下面的网关定义使用了[部署 Cilium 网关](#hybrid-nodes-ingress-cilium-gateway-deploy)中所述的 Istio Bookinfo 示例应用程序。在下面的示例中，网关资源配置为使用 HTTP 侦听器的 `8111` 端口，该端口是在主机网络上运行的 Envoy 代理的共享侦听器端口。如果您将特权端口（低于 1023）用于网关资源，请参阅 [Cilium 文档](https://docs.cilium.io/en/stable/network/servicemesh/gateway-api/gateway-api/#bind-to-privileged-port)获取相关说明。

   ```
   ---
   apiVersion: gateway.networking.k8s.io/v1
   kind: Gateway
   metadata:
     name: my-gateway
   spec:
     gatewayClassName: cilium
     listeners:
     - protocol: HTTP
       port: 8111
       name: web-gw
       allowedRoutes:
         namespaces:
           from: Same
   ---
   apiVersion: gateway.networking.k8s.io/v1
   kind: HTTPRoute
   metadata:
     name: http-app-1
   spec:
     parentRefs:
     - name: my-gateway
       namespace: default
     rules:
     - matches:
       - path:
           type: PathPrefix
           value: /details
       backendRefs:
       - name: details
         port: 9080
   ```

   您可以使用以下命令观察应用的 Cilium Envoy 配置。

   ```
   kubectl get cec cilium-gateway-my-gateway -o yaml
   ```

   您可以使用以下命令获取 `cilium-gateway-my-gateway` 服务的 Envoy 侦听器端口。在此示例中，共享侦听器端口为 `8111`。

   ```
   kubectl get cec cilium-gateway-my-gateway -o jsonpath={.spec.services[0].ports[0]}
   ```

1. 获取集群节点的 IP 地址。

   ```
   kubectl get nodes -o wide
   ```

   ```
   NAME                   STATUS   ROLES    AGE   VERSION               INTERNAL-IP     EXTERNAL-IP   OS-IMAGE             KERNEL-VERSION       CONTAINER-RUNTIME
   mi-026d6a261e355fba7   Ready    <none>   23h   v1.32.3-eks-473151a   10.80.146.150   <none>        Ubuntu 22.04.5 LTS   5.15.0-142-generic   containerd://1.7.27
   mi-082f73826a163626e   Ready    <none>   23h   v1.32.3-eks-473151a   10.80.146.32    <none>        Ubuntu 22.04.4 LTS   5.15.0-142-generic   containerd://1.7.27
   mi-09183e8a3d755abf6   Ready    <none>   23h   v1.32.3-eks-473151a   10.80.146.33    <none>        Ubuntu 22.04.4 LTS   5.15.0-142-generic   containerd://1.7.27
   mi-0d78d815980ed202d   Ready    <none>   23h   v1.32.3-eks-473151a   10.80.146.97    <none>        Ubuntu 22.04.4 LTS   5.15.0-142-generic   containerd://1.7.27
   mi-0daa253999fe92daa   Ready    <none>   23h   v1.32.3-eks-473151a   10.80.146.100   <none>        Ubuntu 22.04.4 LTS   5.15.0-142-generic   containerd://1.7.27
   ```

1. 使用节点的 IP 地址和 `cilium-gateway-my-gateway` 资源的侦听器端口访问服务。在下面的示例中，使用的节点 IP 地址是 `10.80.146.32`，侦听器端口是 `8111`。请将这些值替换为您环境的相应值。

   ```
   curl -s http://10.80.146.32:8111/details/1 | jq
   ```

   ```
   {
     "id": 1,
     "author": "William Shakespeare",
     "year": 1595,
     "type": "paperback",
     "pages": 200,
     "publisher": "PublisherA",
     "language": "English",
     "ISBN-10": "1234567890",
     "ISBN-13": "123-1234567890"
   }
   ```

#### 入口
<a name="_ingress"></a>

由于上游 Cilium 问题（[\$134028](https://github.com/cilium/cilium/issues/34028)），主机网络模式下的 Cilium 入口需要使用 `loadbalancerMode: shared`，这会为集群中的所有入口资源创建 ClusterIP 类型的单一服务。如果您将特权端口（低于 1023）用于入口资源，请参阅 [Cilium 文档](https://docs.cilium.io/en/stable/network/servicemesh/ingress/#bind-to-privileged-port)获取相关说明。

1. 使用以下内容创建名为 `cilium-ingress-host-network.yaml` 的文件。

   ```
   ingressController:
     enabled: true
     loadbalancerMode: shared
     # This is a workaround for the upstream Cilium issue
     service:
       externalTrafficPolicy: null
       type: ClusterIP
     hostNetwork:
       enabled: true
       # ensure the port does not conflict with other services on the node
       sharedListenerPort: 8111
       # uncomment to restrict nodes where Envoy proxies run on the host network
       # nodes:
       #   matchLabels:
       #     role: ingress
   ```

1. 将主机网络 Cilium 入口配置应用于集群。

   ```
   helm upgrade cilium oci://public.ecr.aws/eks/cilium/cilium \
     --namespace kube-system \
     --reuse-values \
     --set operator.rollOutPods=true \
     -f cilium-ingress-host-network.yaml
   ```

   如果您尚未创建入口资源，则可以通过将以下入口定义应用于集群来创建它。下面的入口定义使用了[部署 Cilium 入口](#hybrid-nodes-ingress-cilium-ingress-deploy)中所述的 Istio Bookinfo 示例应用程序。

   ```
   apiVersion: networking.k8s.io/v1
   kind: Ingress
   metadata:
     name: my-ingress
     namespace: default
   spec:
     ingressClassName: cilium
     rules:
     - http:
         paths:
         - backend:
             service:
               name: details
               port:
                 number: 9080
           path: /details
           pathType: Prefix
   ```

   您可以使用以下命令观察应用的 Cilium Envoy 配置。

   ```
   kubectl get cec -n kube-system cilium-ingress -o yaml
   ```

   您可以使用以下命令获取 `cilium-ingress` 服务的 Envoy 侦听器端口。在此示例中，共享侦听器端口为 `8111`。

   ```
   kubectl get cec -n kube-system cilium-ingress -o jsonpath={.spec.services[0].ports[0]}
   ```

1. 获取集群节点的 IP 地址。

   ```
   kubectl get nodes -o wide
   ```

   ```
   NAME                   STATUS   ROLES    AGE   VERSION               INTERNAL-IP     EXTERNAL-IP   OS-IMAGE             KERNEL-VERSION       CONTAINER-RUNTIME
   mi-026d6a261e355fba7   Ready    <none>   23h   v1.32.3-eks-473151a   10.80.146.150   <none>        Ubuntu 22.04.5 LTS   5.15.0-142-generic   containerd://1.7.27
   mi-082f73826a163626e   Ready    <none>   23h   v1.32.3-eks-473151a   10.80.146.32    <none>        Ubuntu 22.04.4 LTS   5.15.0-142-generic   containerd://1.7.27
   mi-09183e8a3d755abf6   Ready    <none>   23h   v1.32.3-eks-473151a   10.80.146.33    <none>        Ubuntu 22.04.4 LTS   5.15.0-142-generic   containerd://1.7.27
   mi-0d78d815980ed202d   Ready    <none>   23h   v1.32.3-eks-473151a   10.80.146.97    <none>        Ubuntu 22.04.4 LTS   5.15.0-142-generic   containerd://1.7.27
   mi-0daa253999fe92daa   Ready    <none>   23h   v1.32.3-eks-473151a   10.80.146.100   <none>        Ubuntu 22.04.4 LTS   5.15.0-142-generic   containerd://1.7.27
   ```

1. 使用节点的 IP 地址和 `cilium-ingress` 资源的 `sharedListenerPort` 访问服务。在下面的示例中，使用的节点 IP 地址是 `10.80.146.32`，侦听器端口是 `8111`。请将这些值替换为您环境的相应值。

   ```
   curl -s http://10.80.146.32:8111/details/1 | jq
   ```

   ```
   {
     "id": 1,
     "author": "William Shakespeare",
     "year": 1595,
     "type": "paperback",
     "pages": 200,
     "publisher": "PublisherA",
     "language": "English",
     "ISBN-10": "1234567890",
     "ISBN-13": "123-1234567890"
   }
   ```

# 为混合节点配置 LoadBalancer 类型服务
<a name="hybrid-nodes-load-balancing"></a>

本主题介绍了如何为在 Amazon EKS 混合节点上运行的应用程序配置第 4 层（L4）负载均衡。LoadBalancer 类型的 Kubernetes 服务用于向集群外部公开 Kubernetes 应用程序。LoadBalancer 类型服务通常与云或本地环境中的物理负载均衡器基础设施结合使用，以处理工作负载的流量。这种负载均衡器基础设施通常通过特定于环境的控制器进行预置。

 对于在 EKS 混合节点上运行的 LoadBalancer 类型服务，AWS 支持使用 AWS 网络负载均衡器（NLB）和 Cilium。使用 NLB 还是 Cilium 取决于应用程序流量的来源。如果应用程序流量来自某个 AWS 区域，AWS 建议使用 AWS NLB 和 AWS 负载均衡器控制器。如果应用程序流量来自本地或边缘环境，AWS 建议使用 Cilium 的内置负载均衡功能，无论是否在环境中使用负载均衡器基础设施，均可使用该功能。

有关第 7 层（L7）应用程序流量负载均衡的信息，请参阅[为混合节点配置 Kubernetes 入口](hybrid-nodes-ingress.md)。有关使用 EKS 实现负载均衡的一般信息，请参阅 [Best Practices for Load Balancing](https://docs.aws.amazon.com/eks/latest/best-practices/load-balancing.html)。

## AWS 网络负载均衡器
<a name="hybrid-nodes-service-lb-nlb"></a>

您可以将 [AWS 负载均衡器控制器](aws-load-balancer-controller.md)和目标类型为 `ip` 的 NLB 用于在混合节点上运行的工作负载。使用目标类型 `ip` 时，NLB 会绕过服务层网络路径，直接将流量转发到容器组（pod）。为了让 NLB 到达混合节点上的容器组（pod）IP 目标，本地容器组（pod）CIDR 必须可在本地网络中路由。此外，AWS 负载均衡器控制器使用 Webhook，需要来自 EKS 控制面板的直接通信。有关更多信息，请参阅 [为混合节点配置 Webhook](hybrid-nodes-webhooks.md)。
+ 有关子网配置要求，请参阅[使用网络负载均衡器路由 TCP 和 UDP 流量](network-load-balancing.md)；有关 AWS 网络负载均衡器及 AWS 负载均衡器控制器的其他信息，请参阅[使用 Helm 安装 AWS 负载均衡器控制器](lbc-helm.md) 和 [Best Practices for Load Balancing](https://docs.aws.amazon.com/eks/latest/best-practices/load-balancing.html)。
+ 有关可应用于使用 AWS 网络负载均衡器的 `LoadBalancer` 类型服务的配置，请参阅 [AWS Load Balancer Controller NLB configurations](https://kubernetes-sigs.github.io/aws-load-balancer-controller/latest/guide/service/nlb/)。

### 先决条件
<a name="_prerequisites"></a>
+ 按照[为混合节点配置 CNI](hybrid-nodes-cni.md)中的说明安装 Cilium。
+ 按照[为混合节点配置 Cilium BGP](hybrid-nodes-cilium-bgp.md) 中的说明启用 Cilium BGP 控制面板。如果您不想使用 BGP，则必须使用其他方法，使本地容器组（pod）CIDR 可在本地网络中路由，有关更多信息，请参阅[可路由的远程容器组（pod）CIDR](hybrid-nodes-concepts-kubernetes.md#hybrid-nodes-concepts-k8s-pod-cidrs)。
+ 在命令行环境中安装 Helm，请参阅[安装 Helm 说明](helm.md)。
+ 在命令行环境中安装 eksctl，请参阅[安装 eksctl 说明](install-kubectl.md#eksctl-install-update)。

### 过程
<a name="_procedure"></a>

1. 下载AWS负载均衡器控制器的 IAM 策略，该策略允许负载均衡器代表您调用 AWS API。

   ```
   curl -O https://raw.githubusercontent.com/kubernetes-sigs/aws-load-balancer-controller/refs/heads/main/docs/install/iam_policy.json
   ```

1. 使用上一步中下载的策略创建一个 IAM 策略。

   ```
   aws iam create-policy \
       --policy-name AWSLoadBalancerControllerIAMPolicy \
       --policy-document file://iam_policy.json
   ```

1. 将集群名称 (`CLUSTER_NAME`)、AWS 区域 (`AWS_REGION`) 和 AWS 账户 ID (`AWS_ACCOUNT_ID`) 的值替换为您的设置，然后运行以下命令。

   ```
   eksctl create iamserviceaccount \
       --cluster=CLUSTER_NAME \
       --namespace=kube-system \
       --name=aws-load-balancer-controller \
       --attach-policy-arn=arn:aws:iam::AWS_ACCOUNT_ID:policy/AWSLoadBalancerControllerIAMPolicy \
       --override-existing-serviceaccounts \
       --region AWS_REGION \
       --approve
   ```

1. 添加 eks-charts Helm 图表存储库。AWS 会在 GitHub 上维护此存储库。

   ```
   helm repo add eks https://aws.github.io/eks-charts
   ```

1. 更新本地 Helm 存储库，确保拥有最新的图表。

   ```
   helm repo update eks
   ```

1. 安装AWS负载均衡器控制器。将集群名称 (`CLUSTER_NAME`)、AWS 区域 (`AWS_REGION`)、VPC ID (`VPC_ID`) 和 AWS 负载均衡器控制器 Helm 图表版本 (`AWS_LBC_HELM_VERSION`) 的值替换为您的设置。您可以通过运行 `helm search repo eks/aws-load-balancer-controller --versions` 找到最新版本的 Helm 图表。如果您运行的混合模式集群同时包含混合节点和 AWS 云中的节点，则可以按照[AWS Load Balancer Controller](hybrid-nodes-webhooks.md#hybrid-nodes-mixed-lbc) 中的说明，在云端节点上运行 AWS 负载均衡器控制器。

   ```
   helm install aws-load-balancer-controller eks/aws-load-balancer-controller \
     -n kube-system \
     --version AWS_LBC_HELM_VERSION \
     --set clusterName=CLUSTER_NAME \
     --set region=AWS_REGION \
     --set vpcId=VPC_ID \
     --set serviceAccount.create=false \
     --set serviceAccount.name=aws-load-balancer-controller
   ```

1. 验证 AWS 负载均衡器控制器是否成功安装。

   ```
   kubectl get -n kube-system deployment aws-load-balancer-controller
   ```

   ```
   NAME                           READY   UP-TO-DATE   AVAILABLE   AGE
   aws-load-balancer-controller   2/2     2            2           84s
   ```

1. 在名为 `tcp-sample-app.yaml` 的文件中定义示例应用程序。以下示例使用带有 TCP 端口的简单 NGINX 部署。

   ```
   apiVersion: apps/v1
   kind: Deployment
   metadata:
     name: tcp-sample-app
     namespace: default
   spec:
     replicas: 3
     selector:
       matchLabels:
         app: nginx
     template:
       metadata:
         labels:
           app: nginx
       spec:
         containers:
           - name: nginx
             image: public.ecr.aws/nginx/nginx:1.23
             ports:
               - name: tcp
                 containerPort: 80
   ```

1. 将部署应用于集群。

   ```
   kubectl apply -f tcp-sample-app.yaml
   ```

1. 在名为 `tcp-sample-service.yaml` 的文件中为部署定义 LoadBalancer 类型服务。

   ```
   apiVersion: v1
   kind: Service
   metadata:
     name: tcp-sample-service
     namespace: default
     annotations:
       service.beta.kubernetes.io/aws-load-balancer-type: external
       service.beta.kubernetes.io/aws-load-balancer-nlb-target-type: ip
       service.beta.kubernetes.io/aws-load-balancer-scheme: internet-facing
   spec:
     ports:
       - port: 80
         targetPort: 80
         protocol: TCP
     type: LoadBalancer
     selector:
       app: nginx
   ```

1. 将服务配置应用于集群。

   ```
   kubectl apply -f tcp-sample-service.yaml
   ```

1. 为服务预置 NLB 可能需要几分钟时间。预置 NLB 后，将为服务分配一个与 NLB 部署的 DNS 名称相对应的地址。

   ```
   kubectl get svc tcp-sample-service
   ```

   ```
   NAME                 TYPE           CLUSTER-IP       EXTERNAL-IP                                                                    PORT(S)        AGE
   tcp-sample-service   LoadBalancer   172.16.115.212   k8s-default-tcpsampl-xxxxxxxxxx-xxxxxxxxxxxxxxxx.elb.<region>.amazonaws.com   80:30396/TCP   8s
   ```

1. 使用 NLB 的地址访问服务。

   ```
   curl k8s-default-tcpsampl-xxxxxxxxxx-xxxxxxxxxxxxxxxx.elb.<region>.amazonaws.com
   ```

   输出示例如下。

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

1. 清理您创建的 资源。

   ```
   kubectl delete -f tcp-sample-service.yaml
   kubectl delete -f tcp-sample-app.yaml
   ```

## Cilium 集群内负载均衡
<a name="hybrid-nodes-service-lb-cilium"></a>

Cilium 可用作在 EKS 混合节点上运行的工作负载的集群内负载均衡器，这对于没有负载均衡器基础设施的环境非常有用。Cilium 的负载均衡功能基于多种 Cilium 功能构建而成，包括 kube-proxy 替换、负载均衡器 IP 地址管理（IPAM）和 BGP 控制面板。这些功能的职责详述如下：
+  **Cilium kube-proxy 替换**：负责将服务流量路由到后端容器组（pod）。
+  **Cilium 负载均衡器 IPAM**：管理可分配给 `LoadBalancer` 类型服务的 IP 地址。
+  **Cilium BGP 控制面板**：向本地网络通告负载均衡器 IPAM 分配的 IP 地址。

如果不使用 Cilium 的 kube-proxy 替换，您仍然可以使用 Cilium 负载均衡器 IPAM 和 BGP 控制面板为 LoadBalancer 类型服务分配和指定 IP 地址。如果不使用 Cilium 的 kube-proxy 替换，则在默认情况下，服务到后端容器组（pod）的负载均衡将由 EKS 中的 kube-proxy 和 iptables 规则处理。

### 先决条件
<a name="_prerequisites_2"></a>
+ 无论是否启用 kube-proxy 替换，都已按照[为混合节点配置 CNI](hybrid-nodes-cni.md) 中的说明安装 Cilium。Cilium 的 kube-proxy 替换需要运行 Linux 内核至少为 v4.19.57、v5.1.16 或 v5.2.0 的最新操作系统。除 Red Hat Enterprise Linux（RHEL）8.x 外，所有支持用于混合节点的操作系统的最新版本都符合此标准。
+ 按照[为混合节点配置 Cilium BGP](hybrid-nodes-cilium-bgp.md) 中的说明启用 Cilium BGP 控制面板。如果您不想使用 BGP，则必须使用其他方法，使本地容器组（pod）CIDR 可在本地网络中路由，有关更多信息，请参阅[可路由的远程容器组（pod）CIDR](hybrid-nodes-concepts-kubernetes.md#hybrid-nodes-concepts-k8s-pod-cidrs)。
+ 在命令行环境中安装 Helm，请参阅[安装 Helm 说明](helm.md)。

### 过程
<a name="_procedure_2"></a>

1. 创建一个名为 `cilium-lbip-pool-loadbalancer.yaml` 的文件，其中包含 `CiliumLoadBalancerIPPool` 资源，用于为 LoadBalancer 类型服务配置负载均衡器 IP 地址范围。
   + 将 `LB_IP_CIDR` 替换为用于负载均衡器 IP 地址的 IP 地址范围。要选择单个 IP 地址，请使用 `/32` CIDR。有关更多信息，请参阅 Cilium 文档中的 [LoadBalancer IP Address Management](https://docs.cilium.io/en/stable/network/lb-ipam/)。
   + 配置 `serviceSelector` 字段，使其与将在后续步骤中创建的服务名称相匹配。此配置完成后，此池中的 IP 将仅分配给名为 `tcp-sample-service` 的服务。

     ```
     apiVersion: cilium.io/v2alpha1
     kind: CiliumLoadBalancerIPPool
     metadata:
       name: tcp-service-pool
     spec:
       blocks:
       - cidr: "LB_IP_CIDR"
       serviceSelector:
         matchLabels:
           io.kubernetes.service.name: tcp-sample-service
     ```

1. 将 `CiliumLoadBalancerIPPool` 资源应用于集群。

   ```
   kubectl apply -f cilium-lbip-pool-loadbalancer.yaml
   ```

1. 确认池中至少有一个可用的 IP 地址。

   ```
   kubectl get ciliumloadbalancerippools.cilium.io
   ```

   ```
   NAME               DISABLED   CONFLICTING   IPS AVAILABLE   AGE
   tcp-service-pool   false      False         1               24m
   ```

1. 创建一个名为 `cilium-bgp-advertisement-loadbalancer.yaml` 的文件，其中包含 `CiliumBGPAdvertisement` 资源，用于通告将在下一步中创建的服务的负载均衡器 IP 地址。如果您不使用 Cilium BGP，则可跳过此步骤。用于服务的负载均衡器 IP 地址必须可在本地网络中路由，以便您可以在最后一步中查询服务。
   + 将 `advertisementType` 字段设置为 `Service`，`service.addresses` 设置为 `LoadBalancerIP`，以仅通告 `LoadBalancer` 类型服务的 `LoadBalancerIP`。
   + 配置 `selector` 字段，使其与将在后续步骤中创建的服务名称相匹配。此配置完成后，仅会通告名为 `tcp-sample-service` 的服务的 `LoadBalancerIP`。

     ```
     apiVersion: cilium.io/v2alpha1
     kind: CiliumBGPAdvertisement
     metadata:
       name: bgp-advertisement-tcp-service
       labels:
         advertise: bgp
     spec:
       advertisements:
         - advertisementType: "Service"
           service:
             addresses:
               - LoadBalancerIP
           selector:
             matchLabels:
               io.kubernetes.service.name: tcp-sample-service
     ```

1. 将 `CiliumBGPAdvertisement` 资源应用于集群。如果您不使用 Cilium BGP，则可跳过此步骤。

   ```
   kubectl apply -f cilium-bgp-advertisement-loadbalancer.yaml
   ```

1. 在名为 `tcp-sample-app.yaml` 的文件中定义示例应用程序。以下示例使用带有 TCP 端口的简单 NGINX 部署。

   ```
   apiVersion: apps/v1
   kind: Deployment
   metadata:
     name: tcp-sample-app
     namespace: default
   spec:
     replicas: 3
     selector:
       matchLabels:
         app: nginx
     template:
       metadata:
         labels:
           app: nginx
       spec:
         containers:
           - name: nginx
             image: public.ecr.aws/nginx/nginx:1.23
             ports:
               - name: tcp
                 containerPort: 80
   ```

1. 将部署应用于集群。

   ```
   kubectl apply -f tcp-sample-app.yaml
   ```

1. 在名为 `tcp-sample-service.yaml` 的文件中为部署定义 LoadBalancer 类型服务。
   + 您可以使用服务对象上的 `lbipam.cilium.io/ips` 注释，从负载均衡器 IP 池请求特定 IP 地址。如果您不想为服务请求特定 IP 地址，可以删除此注释。
   + `loadBalancerClass` 规范字段为必填字段，用于防止传统 AWS 云提供商为服务创建经典负载均衡器。在以下示例中，将此字段配置为 `io.cilium/bgp-control-plane`，以将 Cilium 的 BGP 控制面板用作负载均衡器类。也可将此字段配置为 `io.cilium/l2-announcer`，以使用 Cilium 的 [L2 通告功能](https://docs.cilium.io/en/latest/network/l2-announcements/)（目前处于测试阶段，尚未得到 AWS 正式支持）。

     ```
     apiVersion: v1
     kind: Service
     metadata:
       name: tcp-sample-service
       namespace: default
       annotations:
         lbipam.cilium.io/ips: "LB_IP_ADDRESS"
     spec:
       loadBalancerClass: io.cilium/bgp-control-plane
       ports:
         - port: 80
           targetPort: 80
           protocol: TCP
       type: LoadBalancer
       selector:
         app: nginx
     ```

1. 将服务应用于集群。服务将使用外部 IP 地址创建，您可以使用该地址访问应用程序。

   ```
   kubectl apply -f tcp-sample-service.yaml
   ```

1. 确认服务是否已成功创建，是否为其分配了来自上一步创建的 `CiliumLoadBalancerIPPool` 的 IP。

   ```
   kubectl get svc tcp-sample-service
   ```

   ```
   NAME                 TYPE           CLUSTER-IP      EXTERNAL-IP     PORT(S)        AGE
   tcp-sample-service   LoadBalancer   172.16.117.76   LB_IP_ADDRESS   80:31129/TCP   14m
   ```

1. 如果您在 kube-proxy 替换模式下使用 Cilium，则可通过运行以下命令来确认 Cilium 是否正在处理服务的负载均衡。在以下输出中，`10.86.2.x` 地址是服务后端容器组（pod）的容器组（pod）IP 地址。

   ```
   kubectl -n kube-system exec ds/cilium -- cilium-dbg service list
   ```

   ```
   ID   Frontend               Service Type   Backend
   ...
   41   LB_IP_ADDRESS:80/TCP   LoadBalancer   1 => 10.86.2.76:80/TCP (active)
                                              2 => 10.86.2.130:80/TCP (active)
                                              3 => 10.86.2.141:80/TCP (active)
   ```

1. 确认 Cilium 正在通过 BGP 向本地网络通告 IP 地址。在以下示例中，有五个混合节点，每个节点都将向本地网络通告 `tcp-sample-service` 服务的 `LB_IP_ADDRESS`。

   ```
   Node                   VRouter      Prefix             NextHop   Age     Attrs
   mi-026d6a261e355fba7   NODES_ASN
                     LB_IP_ADDRESS/32   0.0.0.0   12m3s   [{Origin: i} {Nexthop: 0.0.0.0}]
   mi-082f73826a163626e   NODES_ASN
                     LB_IP_ADDRESS/32   0.0.0.0   12m3s   [{Origin: i} {Nexthop: 0.0.0.0}]
   mi-09183e8a3d755abf6   NODES_ASN
                     LB_IP_ADDRESS/32   0.0.0.0   12m3s   [{Origin: i} {Nexthop: 0.0.0.0}]
   mi-0d78d815980ed202d   NODES_ASN
                     LB_IP_ADDRESS/32   0.0.0.0   12m3s   [{Origin: i} {Nexthop: 0.0.0.0}]
   mi-0daa253999fe92daa   NODES_ASN
                     LB_IP_ADDRESS/32   0.0.0.0   12m3s   [{Origin: i} {Nexthop: 0.0.0.0}]
   ```

1. 使用分配的负载均衡器 IP 地址访问服务。

   ```
   curl LB_IP_ADDRESS
   ```

   输出示例如下。

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

1. 清理您创建的 资源。

   ```
   kubectl delete -f tcp-sample-service.yaml
   kubectl delete -f tcp-sample-app.yaml
   kubectl delete -f cilium-lb-ip-pool.yaml
   kubectl delete -f cilium-bgp-advertisement.yaml
   ```

# 为混合节点配置 Kubernetes 网络策略
<a name="hybrid-nodes-network-policies"></a>

 如果将 Cilium 用作 EKS 混合节点的 CNI，则 AWS 支持通过 Kubernetes 网络策略（第 3 层/第 4 层）来控制容器组（pod）的入口和出口流量。如果运行的 EKS 集群包含 AWS 云中的节点，则 AWS 支持[使用 Amazon VPC CNI 来实现 Kubernetes 网络策略](cni-network-policy.md)。

本主题介绍如何通过 EKS 混合节点配置 Cilium 和 Kubernetes 网络策略。有关 Kubernetes 网络策略的详细信息，请参阅 Kubernetes 文档中的 [Kubernetes Network Policies](https://kubernetes.io/docs/concepts/services-networking/network-policies/)。

## 配置网络策略
<a name="hybrid-nodes-configure-network-policies"></a>

### 注意事项
<a name="_considerations"></a>
+  AWS 支持通过上游 Kubernetes 网络策略及其规范，控制容器组（pod）的入口和出口流量，但 AWS 目前不支持 `CiliumNetworkPolicy` 或 `CiliumClusterwideNetworkPolicy`。
+ `policyEnforcementMode` Helm 可用于控制 Cilium 的默认策略执行行为。默认行为允许所有出口和入口流量。如果一个端点被某个网络策略选中，则会转换为默认拒绝状态，仅允许明确允许的流量。有关[默认策略模式](https://docs.cilium.io/en/stable/security/policy/intro/#policy-mode-default)和[策略执行模式](https://docs.cilium.io/en/stable/security/policy/intro/#policy-enforcement-modes)的更多信息，请参阅 Cilium 文档。
+ 如果要为现有的 Cilium 安装更改 `policyEnforcementMode`，则必须重启 Cilium 代理 DaemonSet，这样才能应用新的策略执行模式。
+ 使用 `namespaceSelector` 和 `podSelector` 以允许或拒绝进出带有匹配标签的命名空间和容器组（pod）的流量。`namespaceSelector` 和 `podSelector` 可与 `matchLabels` 或 `matchExpressions` 结合使用，以根据标签选择命名空间和容器组（pod）。
+ 使用 `ingress.ports` 和 `egress.ports` 以允许或拒绝进出端口和协议的流量。
+ `ipBlock` 字段不能用于选择性地允许或拒绝进出容器组（pod）IP 地址的流量（[\$19209](https://github.com/cilium/cilium/issues/9209)）。对节点 IP 使用 `ipBlock` 选择器是 Cilium 中的一项测试功能，不受 AWS 支持。
+ 有关 Kubernetes 网络策略可用字段的信息，请参阅 Kubernetes 文档中的 [NetworkPolicy resource](https://kubernetes.io/docs/concepts/services-networking/network-policies/#networkpolicy-resource)。

### 先决条件
<a name="_prerequisites"></a>
+ 按照[为混合节点配置 CNI](hybrid-nodes-cni.md)中的说明安装 Cilium。
+ 在命令行环境中安装 Helm，请参阅[安装 Helm 说明](helm.md)。

### 过程
<a name="_procedure"></a>

以下过程为示例微服务应用程序设置了网络策略，使得各个组件只能与应用程序正常运行所需的其他组件通信。该过程使用 [Istio Bookinfo](https://istio.io/latest/docs/examples/bookinfo/) 示例微服务应用程序。

Bookinfo 应用程序由四项独立的微服务组成，它们具有以下关系：
+  **productpage**。productpage 微服务会调用 details 和 reviews 微服务来填充页面。
+  **details**。details 微服务包含包含书籍信息。
+  **reviews**。reviews 微服务包含书评，还会调用 ratings 微服务。
+  **ratings**。ratings 微服务包含随书评附带的书籍排名信息。

  1. 创建示例应用程序。

     ```
     kubectl apply -f https://raw.githubusercontent.com/istio/istio/refs/heads/master/samples/bookinfo/platform/kube/bookinfo.yaml
     ```

  1. 确认应用程序成功运行，并记下 productpage 微服务的容器组（pod）IP 地址。您将在后续步骤中使用此容器组（pod）IP 地址查询每项微服务。

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

     ```
     NAME                              READY   STATUS    RESTARTS   AGE   IP            NODE
     details-v1-766844796b-9wff2       1/1     Running   0          7s    10.86.3.7     mi-0daa253999fe92daa
     productpage-v1-54bb874995-lwfgg   1/1     Running   0          7s    10.86.2.193   mi-082f73826a163626e
     ratings-v1-5dc79b6bcd-59njm       1/1     Running   0          7s    10.86.2.232   mi-082f73826a163626e
     reviews-v1-598b896c9d-p2289       1/1     Running   0          7s    10.86.2.47    mi-026d6a261e355fba7
     reviews-v2-556d6457d-djktc        1/1     Running   0          7s    10.86.3.58    mi-0daa253999fe92daa
     reviews-v3-564544b4d6-g8hh4       1/1     Running   0          7s    10.86.2.69    mi-09183e8a3d755abf6
     ```

  1. 创建一个容器组（pod），用于全程测试网络策略。请注意，该容器组（pod）是在 `default` 命名空间中创建，带有 `access: true` 标签。

     ```
     kubectl run curl-pod --image=curlimages/curl -i --tty --labels=access=true --namespace=default --overrides='{"spec": { "nodeSelector": {"eks.amazonaws.com/compute-type": "hybrid"}}}' -- /bin/sh
     ```

  1. 测试对 productpage 微服务的访问权限。在以下示例中，我们使用 productpage 容器组（pod）的容器组（pod）IP 地址 (`10.86.2.193`) 查询该微服务。请将其替换为环境中 productpage 容器组（pod）的容器组（pod）IP 地址。

     ```
     curl -s http://10.86.2.193:9080/productpage | grep -o "<title>.*</title>"
     ```

     ```
     <title>Simple Bookstore App</title>
     ```

  1. 您可以通过输入 `exit` 来退出测试 curl 容器组（pod），也可以通过运行以下命令重新附加到该容器组（pod）。

     ```
     kubectl attach curl-pod -c curl-pod -i -t
     ```

  1. 为演示后续步骤中网络策略的效果，我们首先创建了一个拒绝所有流向 BookInfo 微服务之流量的网络策略。创建一个名为 `network-policy-deny-bookinfo.yaml` 的文件，用于定义拒绝网络策略。

     ```
     apiVersion: networking.k8s.io/v1
     kind: NetworkPolicy
     metadata:
       name: deny-bookinfo
       namespace: default
     spec:
       podSelector:
         matchExpressions:
         - key: app
           operator: In
           values: ["productpage", "details", "reviews", "ratings"]
       policyTypes:
       - Ingress
       - Egress
     ```

  1. 将拒绝网络策略应用于集群。

     ```
     kubectl apply -f network-policy-default-deny-bookinfo.yaml
     ```

  1. 测试对 BookInfo 应用程序的访问权限。在以下示例中，我们使用 productpage 容器组（pod）的容器组（pod）IP 地址 (`10.86.2.193`) 查询该微服务。请将其替换为环境中 productpage 容器组（pod）的容器组（pod）IP 地址。

     ```
     curl http://10.86.2.193:9080/productpage --max-time 10
     ```

     ```
     curl: (28) Connection timed out after 10001 milliseconds
     ```

  1. 创建一个名为 `network-policy-productpage.yaml` 的文件，用于定义 productpage 网络策略。该策略具有以下规则：
     + 允许来自带有 `access: true` 标签的容器组（pod）[即上一步中创建的 curl 容器组（pod）] 的入口流量
     + 允许端口 `9080` 上的出口 TCP 流量流向 details、reviews 和 ratings 微服务
     + 允许端口 `53` 上的出口 TCP/UDP 流量流向在 `kube-system` 命名空间中运行的 CoreDNS

       ```
       apiVersion: networking.k8s.io/v1
       kind: NetworkPolicy
       metadata:
         name: productpage-policy
         namespace: default
       spec:
         podSelector:
           matchLabels:
             app: productpage
         policyTypes:
         - Ingress
         - Egress
         ingress:
         - from:
           - podSelector:
               matchLabels:
                 access: "true"
         egress:
         - to:
           - podSelector:
               matchExpressions:
               - key: app
                 operator: In
                 values: ["details", "reviews", "ratings"]
           ports:
           - port: 9080
             protocol: TCP
         - to:
           - namespaceSelector:
               matchLabels:
                 kubernetes.io/metadata.name: kube-system
             podSelector:
               matchLabels:
                 k8s-app: kube-dns
           ports:
           - port: 53
             protocol: UDP
           - port: 53
             protocol: TCP
       ```

  1. 将 productpage 网络策略应用于集群。

     ```
     kubectl apply -f network-policy-productpage.yaml
     ```

  1. 连接到 curl 容器组（pod）并测试对 Bookinfo 应用程序的访问权限。现在允许访问 productpage 微服务，但其他微服务仍被拒绝，因为它们仍然受到拒绝网络策略的约束。在以下示例中，我们使用 productpage 容器组（pod）的容器组（pod）IP 地址 (`10.86.2.193`) 查询该微服务。请将其替换为环境中 productpage 容器组（pod）的容器组（pod）IP 地址。

     ```
     kubectl attach curl-pod -c curl-pod -i -t
     ```

     ```
     curl -s http://10.86.2.193:9080/productpage | grep -o "<title>.*</title>"
     <title>Simple Bookstore App</title>
     ```

     ```
     curl -s http://10.86.2.193:9080/api/v1/products/1
     {"error": "Sorry, product details are currently unavailable for this book."}
     ```

     ```
     curl -s http://10.86.2.193:9080/api/v1/products/1/reviews
     {"error": "Sorry, product reviews are currently unavailable for this book."}
     ```

     ```
     curl -s http://10.86.2.193:9080/api/v1/products/1/ratings
     {"error": "Sorry, product ratings are currently unavailable for this book."}
     ```

  1. 创建一个名为 `network-policy-details.yaml` 的文件，用于定义 details 网络策略。该策略仅允许来自 productpage 微服务的入口流量。

     ```
     apiVersion: networking.k8s.io/v1
     kind: NetworkPolicy
     metadata:
       name: details-policy
       namespace: default
     spec:
       podSelector:
         matchLabels:
           app: details
       policyTypes:
       - Ingress
       ingress:
       - from:
         - podSelector:
             matchLabels:
               app: productpage
     ```

  1. 创建一个名为 `network-policy-reviews.yaml` 的文件，用于定义 reviews 网络策略。该策略仅允许来自 productpage 微服务的入口流量，并且仅允许流向 ratings 微服务和 CoreDNS 的出口流量。

     ```
     apiVersion: networking.k8s.io/v1
     kind: NetworkPolicy
     metadata:
       name: reviews-policy
       namespace: default
     spec:
       podSelector:
         matchLabels:
           app: reviews
       policyTypes:
       - Ingress
       - Egress
       ingress:
       - from:
         - podSelector:
             matchLabels:
               app: productpage
       egress:
       - to:
         - podSelector:
             matchLabels:
               app: ratings
       - to:
         - namespaceSelector:
             matchLabels:
               kubernetes.io/metadata.name: kube-system
           podSelector:
             matchLabels:
               k8s-app: kube-dns
         ports:
         - port: 53
           protocol: UDP
         - port: 53
           protocol: TCP
     ```

  1. 创建一个名为 `network-policy-ratings.yaml` 的文件，用于定义 ratings 网络策略。该策略仅允许来自 productpage 和 reviews 微服务的入口流量。

     ```
     apiVersion: networking.k8s.io/v1
     kind: NetworkPolicy
     metadata:
       name: ratings-policy
       namespace: default
     spec:
       podSelector:
         matchLabels:
           app: ratings
       policyTypes:
       - Ingress
       ingress:
       - from:
         - podSelector:
             matchExpressions:
             - key: app
               operator: In
               values: ["productpage", "reviews"]
     ```

  1. 将 details、reviews 和 ratings 网络策略应用于集群。

     ```
     kubectl apply -f network-policy-details.yaml
     kubectl apply -f network-policy-reviews.yaml
     kubectl apply -f network-policy-ratings.yaml
     ```

  1. 连接到 curl 容器组（pod）并测试对 Bookinfo 应用程序的访问权限。在以下示例中，我们使用 productpage 容器组（pod）的容器组（pod）IP 地址 (`10.86.2.193`) 查询该微服务。请将其替换为环境中 productpage 容器组（pod）的容器组（pod）IP 地址。

     ```
     kubectl attach curl-pod -c curl-pod -i -t
     ```

     测试 details 微服务。

     ```
     curl -s http://10.86.2.193:9080/api/v1/products/1
     ```

     ```
     {"id": 1, "author": "William Shakespeare", "year": 1595, "type": "paperback", "pages": 200, "publisher": "PublisherA", "language": "English", "ISBN-10": "1234567890", "ISBN-13": "123-1234567890"}
     ```

     测试 reviews 微服务。

     ```
     curl -s http://10.86.2.193:9080/api/v1/products/1/reviews
     ```

     ```
     {"id": "1", "podname": "reviews-v1-598b896c9d-p2289", "clustername": "null", "reviews": [{"reviewer": "Reviewer1", "text": "An extremely entertaining play by Shakespeare. The slapstick humour is refreshing!"}, {"reviewer": "Reviewer2", "text": "Absolutely fun and entertaining. The play lacks thematic depth when compared to other plays by Shakespeare."}]}
     ```

     测试 ratings 微服务。

     ```
     curl -s http://10.86.2.193:9080/api/v1/products/1/ratings
     ```

     ```
     {"id": 1, "ratings": {"Reviewer1": 5, "Reviewer2": 4}}
     ```

  1. 清理您在此过程中创建的资源。

     ```
     kubectl delete -f network-policy-deny-bookinfo.yaml
     kubectl delete -f network-policy-productpage.yaml
     kubectl delete -f network-policy-details.yaml
     kubectl delete -f network-policy-reviews.yaml
     kubectl delete -f network-policy-ratings.yaml
     kubectl delete -f https://raw.githubusercontent.com/istio/istio/refs/heads/master/samples/bookinfo/platform/kube/bookinfo.yaml
     kubectl delete pod curl-pod
     ```

# 混合节点的概念
<a name="hybrid-nodes-concepts"></a>

借助 *Amazon EKS 混合节点功能*，您可以将在本地或边缘环境中运行的物理计算机或虚拟机加入到在 AWS Cloud 中运行的 Amazon EKS 集群。这种方法提供了诸多优势，同时也为熟悉在单一网络环境中运行 Kubernetes 集群的用户引入了新的网络概念和架构。

以下各节将深入探讨 Kubernetes 和 EKS 混合节点的网络概念，并详细介绍流量如何流经混合架构。这些章节要求您熟悉基本的 Kubernetes 网络知识，例如容器组（pod）、节点、服务、Kubernetes 控制面板、kubelet 以及 kube-proxy 的概念。

建议按顺序阅读这些页面，从 [混合节点的联网概念](hybrid-nodes-concepts-networking.md) 开始，然后是 [混合节点的 Kubernetes 概念](hybrid-nodes-concepts-kubernetes.md)，最后是 [混合节点的网络流量](hybrid-nodes-concepts-traffic-flows.md)。

**Topics**
+ [

# 混合节点的联网概念
](hybrid-nodes-concepts-networking.md)
+ [

# 混合节点的 Kubernetes 概念
](hybrid-nodes-concepts-kubernetes.md)
+ [

# 混合节点的网络流量
](hybrid-nodes-concepts-traffic-flows.md)

# 混合节点的联网概念
<a name="hybrid-nodes-concepts-networking"></a>

本节详细介绍了核心联网概念以及在为 EKS 混合节点设计网络拓扑时必须考虑的限制。

## EKS 混合节点的联网概念
<a name="_networking_concepts_for_eks_hybrid_nodes"></a>

![\[高级混合节点网络图\]](http://docs.aws.amazon.com/zh_cn/eks/latest/userguide/images/hybrid-nodes-highlevel-network.png)


 **作为网络中心的 VPC** 

所有穿过云边界的流量都会通过您的 VPC 进行路由。这包括从 EKS 控制面板或 AWS 中运行的容器组（pod）流向混合节点或这些节点上运行的容器组（pod）的流量。您可以将集群的 VPC 视为混合节点和集群其余部分之间的网络中心。此架构让您可以完全控制流量及其路由，但您因此也有责任为 VPC 正确配置路由、安全组和防火墙。

 **EKS 控制面板到 VPC** 

EKS 控制面板将**弹性网络接口（ENI）**附加到您的 VPC 中。这些 ENI 处理流入和流出 EKS API 服务器的流量。在配置集群时，您可以控制 EKS 控制面板 ENI 的位置，因为 EKS 会将 ENI 附加到您在集群创建期间传递的子网。

EKS 将安全组与 EKS 附加到子网的 ENI 相关联。这些安全组允许通过 ENI 流入和流出 EKS 控制面板的流量。这对 EKS 混合节点很重要，因为您必须允许混合节点及其上运行的容器组（pod）的流量流向 EKS 控制面板 ENI。

 **远程节点网络** 

远程节点网络，特别是远程节点 CIDR，是分配给作为混合节点使用的计算机的 IP 范围。您预置混合节点时，它们位于您的本地数据中心或边缘站点，这与 EKS 控制面板和 VPC 属于不同的网络域。每个混合节点都有一个或多个来自远程节点 CIDR 的 IP 地址，该地址与 VPC 中的子网不同。

您可以使用这些远程节点 CIDR 配置 EKS 集群，这样 EKS 就会通过集群 VPC 路由所有发往混合节点 IP 的流量，例如对 kubelet API 的请求。与 `kubelet` API 的连接用于 `kubectl attach`、`kubectl cp`、`kubectl exec`、`kubectl logs` 和 `kubectl port-forward` 命令中。

 **远程容器组（pod）网络** 

远程容器组（pod）网络是分配给在混合节点上运行的容器组（pod）的 IP 范围。通常，您可以使用这些范围来配置 CNI，而 CNI 的 IP 地址管理（IPAM）功能负责将这些范围的切片分配给每个混合节点。您创建容器组（pod）时，CNI 会从分配给节点 [容器组（pod）在其中计划] 的切片中为该容器组分配 IP。

您可以使用这些远程容器组（pod）CIDR 配置 EKS 集群，这样 EKS 控制面板就会通过集群的 VPC 来路由所有发往混合节点上运行的容器组（pod）的流量，例如与 Webhook 的通信。

![\[远程容器组（pod）网络\]](http://docs.aws.amazon.com/zh_cn/eks/latest/userguide/images/hybrid-nodes-remote-pod-cidrs.png)


 **本地到 VPC** 

用于混合节点的本地网络必须路由到用于 EKS 集群的 VPC。有多种[网络到 Amazon VPC 的连接选项](https://docs.aws.amazon.com/whitepapers/latest/aws-vpc-connectivity-options/network-to-amazon-vpc-connectivity-options.html)可用来将本地网络连接到 VPC。您还可以使用自己的 VPN 解决方案。

务必在 VPC 和本地网络中的 AWS 云端正确配置路由，这样两个网络便会通过各自的连接路由正确的流量。

在 VPC 中，所有流向远程节点和远程容器组（pod）网络的流量都必须通过连接路由到本地网络（称为“网关”）。如果您的某些子网具有不同的路由表，则必须使用混合节点的路由和在这些节点上运行的容器组（pod）来配置每个路由表。这适用于 ENI 附加到 EKS 控制面板的子网，以及包含必须与混合节点通信的 EC2 节点或容器组（pod）的子网。

在您的本地网络中，您必须将网络配置为允许流入和流出 EKS 集群 VPC 以及混合节点所需的其他 AWS 服务的流量。EKS 集群的流量会双向穿过网关。

## 网络限制
<a name="_networking_constraints"></a>

 **完全路由的网络** 

主要限制在于 EKS 控制面板和所有节点，无论是云节点还是混合节点，都需要形成一个**完全路由的**网络。这意味着所有节点都必须能够通过 IP 地址在第三层相互访问。

EKS 控制面板和云节点已经可以相互访问，因为它们位于扁平化网络（VPC）中。但是，混合节点位于不同的网络域中。因此，您需要在 VPC 和本地网络中配置其他路由，以便在混合节点和集群的其余部分之间路由流量。如果混合节点可以相互访问并可从 VPC 访问，则您的混合节点可以位于一个扁平化网络中，也可以位于多个分段网络中。

 **可路由的远程容器组（pod）CIDR** 

为了让 EKS 控制面板与在混合节点（例如 Webhook 或 Metrics Server）上运行的容器组（pod）通信，或者让在云节点上运行的容器组（pod）与在混合节点上运行的容器组（pod）通信（工作负载东西向通信），远程容器组（pod）CIDR 必须可以从 VPC 路由。这意味着 VPC 必须能够通过网关将流量路由到容器组（pod）CIDR 再到本地网络，并且本地网络必须能够将容器组（pod）的流量路由到正确的节点。

请务必注意 VPC 和本地容器组（pod）路由要求之间的区别。VPC 只需要知道任何流向远程容器组（pod）的流量都应通过网关即可。如果您只有一个远程容器组（pod）CIDR，则只需要一条路由。

此要求适用于本地网络中的所有跃点，包括与混合节点位于同一子网中的本地路由器。这是唯一需要知道分配给每个节点的 pod CIDR 切片的路由器，这能确保特定容器组（pod）的流量传送到计划了容器组（pod）的节点。

您可以选择将本地容器组（pod）CIDR 的这些路由从本地路由器传播到 VPC 路由表，但这不是必需的。如果您的本地容器组（pod）CIDR 频繁更改，并且需要更新 VPC 路由表以反映不断变化的容器组（pod）CIDR，我们建议您将本地容器组（pod）CIDR 传播到 VPC 路由表，但这种情况并不常见。

注意，本地容器组（pod）CIDR 可路由的限制条件是可选的。如果您不需要在混合节点上运行 Webhook，也不需要让云节点上的容器组（pod）与混合节点上的容器组（pod）通信，则无需在本地网络上为容器组（pod）CIDR 配置路由。

 *为何本地容器组（pod）CIDR 需要可通过混合节点进行路由？* 

在云节点上使用 EKS 和 VPC CNI 时，VPC CNI 会直接从 VPC 向容器组（pod）分配 IP。这意味着无需任何特殊路由，因为云容器组（pod）和 EKS 控制面板都可以直接访问 Pod IP。

在本地运行（以及使用云中的其他 CNI 运行）时，容器组（pod）通常在隔离的覆盖网络中运行，CNI 负责在容器组之间传送流量。这通常通过封装来完成：CNI 将容器组（pod）到容器组（pod）的流量转换为节点到节点的流量，同时负责两端的封装和解封工作。这样一来，就无需在节点和路由器上进行额外配置。

与混合节点的联网是独一无二的，因为它结合了两种拓扑：EKS 控制面板和云节点（使用 VPC CNI）需要一个包含节点和容器组（pod）的扁平化网络，而在混合节点上运行的容器组（pod）则使用 VXLAN 进行封装（默认情况下在 Cilium 中），以处于叠加网络中。假设本地网络可以路由到 VPC，则在混合节点上运行的容器组（pod）可以访问 EKS 控制面板以及在云节点上运行的容器组（pod）。但是，如果本地网络上的容器组（pod）CIDR 没有路由，若网络不知道如何访问叠加网络并路由到正确的节点，则返回本地容器组（pod）IP 的任何流量最终都将被丢弃。

# 混合节点的 Kubernetes 概念
<a name="hybrid-nodes-concepts-kubernetes"></a>

本页面详细介绍了支持 EKS 混合节点系统架构的关键 Kubernetes 概念。

## VPC 中的 EKS 控制面板
<a name="hybrid-nodes-concepts-k8s-api"></a>

EKS 控制面板 ENI 的 IP 存储在 `default` 命名空间的 `kubernetes` `Endpoints` 对象中。EKS 创建新的 ENI 或移除较旧的 ENI 时，EKS 会更新此对象，因此 IP 列表始终是最新的。

您可以通过 `kubernetes` 服务使用这些端点，也可以在 `default` 命名空间中使用。`ClusterIP` 类型的这种服务总是会获分配集群服务 CIDR 的第一个 IP。例如，对于服务 CIDR `172.16.0.0/16`，服务 IP 将为 `172.16.0.1`。

通常，这就是容器组（pod）（无论是在云端还是混合节点中运行）访问 EKS Kubernetes API 服务器的方式。容器组（pod）使用服务 IP 作为目标 IP，然后将其转换为其中一个 EKS 控制面板 ENI 的实际 IP。主要例外是 `kube-proxy`，因为它设置了转换。

## EKS API 服务器端点
<a name="hybrid-nodes-concepts-k8s-eks-api"></a>

`kubernetes` 服务 IP 并不是访问 EKS API 服务器的唯一途径。您创建集群时，EKS 还会创建一个 Route53 DNS 名称。这是调用 EKS `DescribeCluster` API 操作时您的 EKS 集群的 `endpoint` 字段。

```
{
    "cluster": {
        "endpoint": "https://xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.gr7.us-west-2.eks.amazonaws.com",
        "name": "my-cluster",
        "status": "ACTIVE"
    }
}
```

在公有端点访问或公有和私有端点访问集群中，您的混合节点默认会将此 DNS 名称解析为可通过互联网路由的公有 IP。在私有端点访问集群中，DNS 名称解析为 EKS 控制面板 ENI 的私有 IP。

这就是 `kubelet` 和 `kube-proxy` 访问 Kubernetes API 服务器的方式。如果您希望所有 Kubernetes 集群流量都通过 VPC，则需要在私有访问模式下配置集群，或者修改本地 DNS 服务器，将 EKS 集群端点解析为 EKS 控制面板 ENI 的私有 IP。

## `kubelet` 端点
<a name="hybrid-nodes-concepts-k8s-kubelet-api"></a>

`kubelet` 公开了多个 REST 端点，允许系统的其他部分与每个节点交互并从每个节点收集信息。在大多数集群中，流向 `kubelet` 服务器的大部分流量来自控制面板，但某些监控代理也可能与该服务器交互。

通过此接口，`kubelet` 可以处理各种请求：获取日志 (`kubectl logs`)、在容器内执行命令 (`kubectl exec`) 以及端口转发流量 (`kubectl port-forward`)。这些请求中的每一个都通过 `kubelet` 与底层容器运行时进行交互，在集群管理员和开发人员看来，这是一个无缝的过程。

此 API 最常见的使用器是 Kubernetes API 服务器。您使用前面提到的任何 `kubectl` 命令时，`kubectl` 会向 API 服务器发出 API 请求，然后服务器调用运行容器组（pod）的节点的 `kubelet` API。这就是需要从 EKS 控制面板访问节点 IP 的主要原因，也解释了为什么即使您的容器组（pod）正在运行，但如果节点路由配置错误，您也无法访问它们的日志或 `exec`。

 **节点 IP** 

EKS 控制面板与节点通信时，它会使用 `Node` 对象状态 (`status.addresses`) 中报告的地址之一。

对于 EKS 云节点，kubelet 通常会在节点注册期间将 EC2 实例的私有 IP 报告为 `InternalIP`。然后，云控制器管理器（CCM）会验证此 IP，确保它属于 EC2 实例。此外，CCM 通常会将实例的公有 IP（作为 `ExternalIP`）和 DNS 名称（`InternalDNS` 和 `ExternalDNS`）添加到节点状态。

但是，没有适用于混合节点的 CCM。您向 EKS 混合节点 CLI (`nodeadm`) 注册混合节点时，它会将 kubelet 配置为直接以节点状态报告计算机的 IP，而不使用 CCM。

```
apiVersion: v1
kind: Node
metadata:
  name: my-node-1
spec:
  providerID: eks-hybrid:///us-west-2/my-cluster/my-node-1
status:
  addresses:
  - address: 10.1.1.236
    type: InternalIP
  - address: my-node-1
    type: Hostname
```

如果您的计算机有多个 IP，kubelet 会按照自己的逻辑选择其中一个 IP。您可以使用 `--node-ip` 标志控制选定的 IP，并且可以在 `spec.kubelet.flags` 的 `nodeadm` 配置中传入该标志。只有 `Node` 对象中报告的 IP 需要来自 VPC 的路由。您的计算机可能有无法从云端访问的其他 IP。

## `kube-proxy`
<a name="hybrid-nodes-concepts-k8s-kube-proxy"></a>

 `kube-proxy` 负责在每个节点的网络层实现服务抽象。它充当流向 Kubernetes 服务的流量的网络代理和负载均衡器。通过持续监控 Kubernetes API 服务器中与服务和端点相关的更改，`kube-proxy` 会动态更新底层主机的网络规则，确保流量得到正确引导。

在 `iptables` 模式下，`kube-proxy` 会对多个 `netfilter` 链进行编程以处理服务流量。这些规则构成以下层次结构：

1.  **KUBE-SERVICES 链**：所有服务流量的入口点。它具有与每项 `ClusterIP` 服务和端口匹配的规则。

1.  **KUBE-SVC-XXX 链**：特定于服务的链对每项服务都有负载均衡规则。

1.  **KUBE-SEP-XXX 链**：特定于端点的链具有实际的 `DNAT` 规则。

让我们来看看 `default` 命名空间中的 `test-server` 服务会发生什么：\$1 服务 ClusterIP：`172.16.31.14` \$1 服务端口：`80` \$1 支持性容器组（pod）：`10.2.0.110`、`10.2.1.39` 和 `10.2.2.254` 

检查 `iptables` 规则（使用 `iptables-save 0 grep -A10 KUBE-SERVICES`）时：

1. 在 **KUBE-SERVICES** 链中，我们找到了一条与该服务匹配的规则：

   ```
   -A KUBE-SERVICES -d 172.16.31.14/32 -p tcp -m comment --comment "default/test-server cluster IP" -m tcp --dport 80 -j KUBE-SVC-XYZABC123456
   ```
   + 此规则与发往 172.16.31.14:80 的数据包匹配
   + 注释指出了此规则的用途：`default/test-server cluster IP`
   + 匹配的数据包跳转到 `KUBE-SVC-XYZABC123456` 链

1. **KUBE-SVC-XYZABC123456** 链具有基于概率的负载均衡规则：

   ```
   -A KUBE-SVC-XYZABC123456 -m statistic --mode random --probability 0.33333333349 -j KUBE-SEP-POD1XYZABC
   -A KUBE-SVC-XYZABC123456 -m statistic --mode random --probability 0.50000000000 -j KUBE-SEP-POD2XYZABC
   -A KUBE-SVC-XYZABC123456 -j KUBE-SEP-POD3XYZABC
   ```
   + 第一条规则：有 33.3% 的概率跳转到 `KUBE-SEP-POD1XYZABC` 
   + 第二条规则：剩余流量（占总流量的 33.3%）有 50% 的概率跳转到 `KUBE-SEP-POD2XYZABC` 
   + 最后一条规则：所有剩余流量（占总流量的 33.3%）都将跳转到 `KUBE-SEP-POD3XYZABC` 

1. 各个 **KUBE-SEP-XXX** 链都执行 DNAT（目标 NAT）：

   ```
   -A KUBE-SEP-POD1XYZABC -p tcp -m tcp -j DNAT --to-destination 10.2.0.110:80
   -A KUBE-SEP-POD2XYZABC -p tcp -m tcp -j DNAT --to-destination 10.2.1.39:80
   -A KUBE-SEP-POD3XYZABC -p tcp -m tcp -j DNAT --to-destination 10.2.2.254:80
   ```
   + 这些 DNAT 规则会重写目标 IP 和端口，将流量引导至特定容器组（pod）。
   + 每条规则处理大约 33.3% 的流量，从而在 `10.2.0.110`、`10.2.1.39` 和 `10.2.2.254` 之间提供均衡的负载均衡。

这种多级链结构让 `kube-proxy` 能够通过内核级别的数据包操作高效地实现服务负载均衡和重定向，而无需在数据路径中使用代理进程。

### 对 Kubernetes 操作的影响
<a name="hybrid-nodes-concepts-k8s-operations"></a>

节点上损坏的 `kube-proxy` 会阻止该节点正确路由服务流量，导致依赖集群服务的容器组（pod）超时或连接失败。首次注册节点时，这可能会造成特别大的干扰。CNI 需要先与 Kubernetes API 服务器通信以获取信息，例如节点的容器组（pod）CIDR，然后才能配置任何容器组（pod）网络。为此，它使用 `kubernetes` 服务 IP。但是，如果 `kube-proxy` 无法启动或未能设置正确的 `iptables` 规则，则发往 `kubernetes` 服务 IP 的请求不会转换为 EKS 控制面板 ENI 的实际 IP。因此，CNI 将进入崩溃循环，所有的容器组（pod）都无法正常运行。

我们知道容器组（pod）使用 `kubernetes` 服务 IP 与 Kubernetes API 服务器通信，但 `kube-proxy` 需要先设置 `iptables` 规则才能使其正常工作。

`kube-proxy` 如何与 API 服务器通信？

`kube-proxy` 必须配置为使用 Kubernetes API 服务器的实际 IP 或解析为它们的 DNS 名称。对于 EKS，EKS 将默认 `kube-proxy` 配置为指向您在创建集群时 EKS 创建的 Route53 DNS 名称。您可以在 `kube-system` 命名空间的 `kube-proxy` ConfigMap 中看到此值。此 ConfigMap 的内容是注入到 `kube-proxy` 容器组（pod）中的 `kubeconfig`，因此请寻找 `clusters0.cluster.server` 字段。此值将与 EKS 集群的 `endpoint` 字段匹配（在调用 EKS `DescribeCluster` API 时）。

```
apiVersion: v1
data:
  kubeconfig: |-
    kind: Config
    apiVersion: v1
    clusters:
    - cluster:
        certificate-authority: /var/run/secrets/kubernetes.io/serviceaccount/ca.crt
        server: https://xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.gr7.us-west-2.eks.amazonaws.com
      name: default
    contexts:
    - context:
        cluster: default
        namespace: default
        user: default
      name: default
    current-context: default
    users:
    - name: default
      user:
        tokenFile: /var/run/secrets/kubernetes.io/serviceaccount/token
kind: ConfigMap
metadata:
  name: kube-proxy
  namespace: kube-system
```

## 可路由的远程容器组（pod）CIDR
<a name="hybrid-nodes-concepts-k8s-pod-cidrs"></a>

[混合节点的联网概念](hybrid-nodes-concepts-networking.md) 页面详细说明了在混合节点上运行 Webhook 或让在云节点上运行的容器组（pod）与在混合节点上运行的容器组（pod）通信的要求。关键要求是，本地路由器需要知道哪个节点负责特定容器组（pod）IP。有多种方法可以实现这一点，包括边界网关协议（BGP）、静态路由和地址解析协议（ARP）代理。以下部分将介绍这些方法。

 **边界网关协议（BGP）** 

如果您的 CNI 支持这种协议（例如 Cilium 和 Calico），您可以使用 CNI 的 BGP 模式，将每节点容器组（pod）CIDR 的路由从节点传播到本地路由器。使用 CNI 的 BGP 模式时，您的 CNI 充当虚拟路由器，因此本地路由器认为容器组（pod）CIDR 属于不同的子网，而您的节点是该子网的网关。

![\[混合节点 BGP 路由\]](http://docs.aws.amazon.com/zh_cn/eks/latest/userguide/images/hybrid-nodes-bgp.png)


 **静态路由** 

您也可以在本地路由器中配置静态路由。这是将本地容器组（pod）CIDR 路由到您的 VPC 的最简单方法，但这也是最容易出错且最难维护的方法。您需要确保现有节点及其分配的容器组（pod）CIDR 的路由始终是最新的。如果您的节点数量很少且基础设施是静态的，那么这是一个可行的选择，并且无需在路由器中支持 BGP。如果您选择这样做，建议使用要分配给每个节点的容器组（pod）CIDR 切片来配置 CNI，而不是让其 IPAM 决定。

![\[混合节点静态路由\]](http://docs.aws.amazon.com/zh_cn/eks/latest/userguide/images/hybrid-nodes-static-routes.png)


 **地址解析协议（ARP）代理** 

ARP 代理是使本地容器组（pod）IP 可路由的另一种方法，当混合节点与本地路由器位于同一个第 2 层网络上时，这种方法特别有用。启用 ARP 代理后，节点会响应其托管的容器组（pod）IP 的 ARP 请求，即使这些 IP 属于不同的子网，也会如此。

本地网络上的设备尝试访问容器组（pod）IP 时，它会首先发送 ARP 请求，询问“谁拥有此 IP？”。托管该容器组（pod）的混合节点将使用自己的 MAC 地址进行响应，表示“我可以处理该 IP 的流量。” 这无需配置路由器，即可在本地网络上的设备和容器组（pod）之间创建直接路径。

要使此方法起作用，您的 CNI 必须支持代理 ARP 功能。Cilium 内置了对代理 ARP 的支持，您可以通过配置启用该功能。关键考虑因素是容器组（pod）CIDR 不得与环境中的任何其他网络重叠，因为这可能会导致路由冲突。

这种方法有几个优点：\$1 无需为路由器配置 BGP，也无需维护静态路由 \$1 在路由器配置不由您控制的环境中效果良好

![\[混合节点 ARP 代理\]](http://docs.aws.amazon.com/zh_cn/eks/latest/userguide/images/hybrid-nodes-arp-proxy.png)


## 容器组（pod）到容器组（pod）封装
<a name="hybrid-nodes-concepts-k8s-pod-encapsulation"></a>

在本地环境中，CNI 通常使用封装协议来创建叠加网络，这种网络无需重新配置即可在物理网络之上运行。此部分介绍了这种封装的工作原理。请注意，根据您使用的 CNI，某些细节可能会有所不同。

封装将原始容器组（pod）网络数据包包装在另一个网络数据包中，该数据包可以通过底层物理网络路由。这允许容器组（pod）在运行相同 CNI 的节点之间进行通信，物理网络不必理解如何路由这些容器组（pod）CIDR。

Kubernetes 中最常用的封装协议是虚拟可扩展局域网（VXLAN），但也可使用其他封装协议（例如 `Geneve`），具体取决于您的 CNI。

### VXLAN 封装
<a name="_vxlan_encapsulation"></a>

VXLAN 将第 2 层以太网帧封装在 UDP 数据包中。当一个容器组（pod）向不同节点上的另一个容器组（pod）发送流量时，CNI 会执行以下操作：

1. CNI 拦截来自容器组（pod）A 的数据包

1. CNI 将原始数据包封装在 VXLAN 标头中

1. 然后，这个封装后的数据包通过节点的常规网络堆栈发送到目标节点

1. 目标节点上的 CNI 解开数据包并将其传送到容器组（pod）B

以下是 VXLAN 封装期间，数据包结构的情况：

容器组（pod）到容器组（pod）的原始数据包：

```
+-----------------+---------------+-------------+-----------------+
| Ethernet Header | IP Header     | TCP/UDP     | Payload         |
| Src: Pod A MAC  | Src: Pod A IP | Src Port    |                 |
| Dst: Pod B MAC  | Dst: Pod B IP | Dst Port    |                 |
+-----------------+---------------+-------------+-----------------+
```

VXLAN 封装后：

```
+-----------------+-------------+--------------+------------+---------------------------+
| Outer Ethernet  | Outer IP    | Outer UDP    | VXLAN      | Original Pod-to-Pod       |
| Src: Node A MAC | Src: Node A | Src: Random  | VNI: xx    | Packet (unchanged         |
| Dst: Node B MAC | Dst: Node B | Dst: 4789    |            | from above)               |
+-----------------+-------------+--------------+------------+---------------------------+
```

VXLAN 网络标识符（VNI）用于区分不同的叠加网络。

### 容器组（pod）通信场景
<a name="_pod_communication_scenarios"></a>

 **同一个混合节点上的容器组（pod）** 

同一个混合节点上的容器组（pod）通信时，通常不需要封装。CNI 设置本地路由，通过节点的内部虚拟接口引导容器组（pod）之间的流量：

```
Pod A -> veth0 -> node's bridge/routing table -> veth1 -> Pod B
```

数据包永远不会离开节点，也不需要封装。

 **不同混合节点上的容器组（pod）** 

不同混合节点上的容器组（pod）之间的通信需要封装：

```
Pod A -> CNI -> [VXLAN encapsulation] -> Node A network -> router or gateway -> Node B network -> [VXLAN decapsulation] -> CNI -> Pod B
```

这样，容器组（pod）流量就可以遍历物理网络基础架构，而物理网络不必理解容器组（pod）IP 路由。

# 混合节点的网络流量
<a name="hybrid-nodes-concepts-traffic-flows"></a>

本页面详细介绍了 EKS 混合节点的网络流量，其中的图表显示了不同流量类型的端到端网络路径。

涵盖以下流量：
+  [混合节点 `kubelet` 到 EKS 控制面板](#hybrid-nodes-concepts-traffic-flows-kubelet-to-cp) 
+  [EKS 控制面板到混合节点（`kubelet` 服务器）](#hybrid-nodes-concepts-traffic-flows-cp-to-kubelet) 
+  [混合节点上运行的容器组（pod）到 EKS 控制面板](#hybrid-nodes-concepts-traffic-flows-pods-to-cp) 
+  [EKS 控制面板到混合节点上运行的容器组（pod）（Webhook）](#hybrid-nodes-concepts-traffic-flows-cp-to-pod) 
+  [在混合节点上运行的容器组（pod）到容器组（pod）](#hybrid-nodes-concepts-traffic-flows-pod-to-pod) 
+  [云节点上的容器组（pod）到混合节点上的容器组（pod）（东西向流量）](#hybrid-nodes-concepts-traffic-flows-east-west) 

## 混合节点 `kubelet` 到 EKS 控制面板
<a name="hybrid-nodes-concepts-traffic-flows-kubelet-to-cp"></a>

![\[混合节点 kubelet 到 EKS 控制面板\]](http://docs.aws.amazon.com/zh_cn/eks/latest/userguide/images/hybrid-nodes-kubelet-to-cp-public.png)


### 请求
<a name="_request"></a>

 **1`kubelet`. 发起请求** 

混合节点上的 `kubelet` 需要与 EKS 控制面板通信 [例如，报告节点状态或获取容器组（pod）规格] 时，它将使用节点注册期间提供的 `kubeconfig` 文件。此 `kubeconfig` 具有 API 服务器端点 URL（Route53 DNS 名称），而非直接 IP 地址。

`kubelet` 对端点执行 DNS 查找（例如 `https://xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx.gr7.us-west-2.eks.amazonaws.com`）。在公有访问集群中，这会解析为属于 AWS 中运行的 EKS 服务的某个公有 IP 地址（如 `54.239.118.52`）。然后，`kubelet` 创建针对此端点的安全 HTTPS 请求。初始数据包类似于以下示例：

```
+--------------------+---------------------+-----------------+
| IP Header          | TCP Header          | Payload         |
| Src: 10.80.0.2     | Src: 52390 (random) |                 |
| Dst: 54.239.118.52 | Dst: 443            |                 |
+--------------------+---------------------+-----------------+
```

 **2. 本地路由器路由** 

目标 IP 是公有 IP 地址而不是本地网络的一部分，因此 `kubelet` 会将此数据包发送到其默认网关（本地路由器）。路由器检查目标 IP 并确定它是公有 IP 地址。

对于公共流量，路由器通常会将数据包转发到处理互联网出站流量的互联网网关或边界路由器。图表中省略了这一点，并且这取决于您的本地网络设置方式。数据包会穿过您的本地网络基础设施，最终到达互联网服务提供商的网络。

 **3. 分发到 EKS 控制面板** 

数据包通过公共互联网和传输网络进行传输，直至到达 AWS 网络。AWS 网络将数据包路由到相应区域的 EKS 服务端点。数据包到达 EKS 服务时，它会被转发到集群的实际 EKS 控制面板。

这种通过公共互联网进行的路由不同于我们在其他流量流中看到的私有 VPC 路由路径。主要区别在于，在使用公共访问模式时，从本地 `kubelet` [尽管不是从容器组（pod）] 到 EKS 控制面板的流量不会通过您的 VPC，而是使用全球互联网基础设施。

### 响应
<a name="_response"></a>

在 EKS 控制面板处理 `kubelet` 请求后，它会发送回响应：

 **3. EKS 控制面板发送响应** 

EKS 控制面板创建响应数据包。此数据包以该公有 IP 为源，并以混合节点的 IP 为目标：

```
+--------------------+---------------------+-----------------+
| IP Header          | TCP Header          | Payload         |
| Src: 54.239.118.52 | Src: 443            |                 |
| Dst: 10.80.0.2     | Dst: 52390          |                 |
+--------------------+---------------------+-----------------+
```

 **2. 互联网路由** 

响应数据包沿着互联网服务提供商确定的路由路径，通过互联网返回，直至到达本地网络边缘路由器。

 **1。本地分发** 

本地路由器会收到数据包并将目标 IP (`10.80.0.2`) 识别为属于本地网络。它通过本地网络基础设施转发数据包，直至到达目标混合节点，`kubelet` 在该节点接收和处理响应。

## 混合节点 `kube-proxy` 到 EKS 控制面板
<a name="_hybrid_node_kube_proxy_to_eks_control_plane"></a>

如果为集群启用了公有端点访问权限，则返回流量会使用公共互联网。此流量从混合节点上的 `kube-proxy` 出发流向 EKS 控制面板，其路径与从 `kubelet` 流向 EKS 控制面板的流量相同。

## EKS 控制面板到混合节点（`kubelet` 服务器）
<a name="hybrid-nodes-concepts-traffic-flows-cp-to-kubelet"></a>

![\[EKS 控制面板到混合节点\]](http://docs.aws.amazon.com/zh_cn/eks/latest/userguide/images/hybrid-nodes-cp-to-kubelet.png)


### 请求
<a name="_request_2"></a>

 **1。EKS Kubernetes API 服务器启动请求** 

EKS Kubernetes API 服务器从节点对象的状态中检索节点的 IP 地址 (`10.80.0.2`)。然后通过 VPC 中的 ENI 路由此请求，因为目标 IP 属于配置的远程节点 CIDR (`10.80.0.0/16`)。初始数据包类似于以下示例：

```
+-----------------+---------------------+-----------------+
| IP Header       | TCP Header          | Payload         |
| Src: 10.0.0.132 | Src: 67493 (random) |                 |
| Dst: 10.80.0.2  | Dst: 10250          |                 |
+-----------------+---------------------+-----------------+
```

 **2. VPC 网络处理** 

数据包离开 ENI 并进入 VPC 网络层，在此处它会被引导到子网的网关进行进一步路由。

 **3. VPC 路由表查找** 

包含 EKS 控制面板 ENI 的子网的 VPC 路由表具有远程节点 CIDR 的专用路由（图中的第二条路由）。根据此路由规则，数据包将被引导至“VPC 到本地”网关。

 **4. 跨边界传输** 

网关通过您建立的连接（例如 Direct Connect 或 VPN）将数据包跨云边界传输到本地网络。

 **5. 本地网络接收** 

数据包到达本地路由器，该路由器处理混合节点所在子网的流量。

 **6. 最终分发** 

本地路由器确定目标 IP (`10.80.0.2`) 地址属于其直连网络，并将数据包直接转发到目标混合节点，而 `kubelet` 在该节点接收和处理请求。

### 响应
<a name="_response_2"></a>

在混合节点的 `kubelet` 处理请求后，它会按照相同的路径反向发送响应：

```
+-----------------+---------------------+-----------------+
| IP Header       | TCP Header          | Payload         |
| Src: 10.80.0.2  | Src: 10250          |                 |
| Dst: 10.0.0.132 | Dst: 67493          |                 |
+-----------------+---------------------+-----------------+
```

 **6. `kubelet` 发送响应** 

混合节点 (`10.80.0.2`) 上的 `kubelet` 创建以原始源 IP 为目标的响应数据包。该目标不属于本地网络，因此它会发送到主机的默认网关，即本地路由器。

 **5. 本地路由器路由** 

路由器确定目标 IP (`10.0.0.132`) 属于 `10.0.0.0/16`，其中具有指向连接到 AWS 的网关的路由。

 **4. 跨边界返回** 

数据包通过同一个本地与 VPC 的连接（例如 Direct Connect 或 VPN）返回，朝相反的方向穿过云边界。

 **3. VPC 路由** 

数据包到达 VPC 时，路由表确定目标 IP 属于某个 VPC CIDR。数据包将在该 VPC 内路由。

 **2. VPC 网络分发** 

VPC 网络层使用 EKS 控制面板 ENI (`10.0.0.132`) 将数据包转发到子网。

 **1。ENI 接收** 

数据包到达附加到 Kubernetes API 服务器的 EKS 控制面板 ENI，从而完成往返行程。

## 混合节点上运行的容器组（pod）到 EKS 控制面板
<a name="hybrid-nodes-concepts-traffic-flows-pods-to-cp"></a>

![\[混合节点上运行的容器组（pod）到 EKS 控制面板\]](http://docs.aws.amazon.com/zh_cn/eks/latest/userguide/images/hybrid-nodes-pod-to-cp.png)


### 不使用 CNI NAT
<a name="_without_cni_nat"></a>

### 请求
<a name="_request_3"></a>

容器组（pod）通常通过 `kubernetes` 服务与 Kubernetes API 服务器通信。服务 IP 是集群的服务 CIDR 的第一个 IP。此惯例允许需要在 CoreDNS 可用之前运行的容器组（pod）访问 API 服务器，例如 CNI。请求离开以服务 IP 为目标的容器组（pod）。例如，如果服务 CIDR 是 `172.16.0.0/16`，则服务 IP 将为 `172.16.0.1`。

 **1。容器组（pod）发起请求** 

容器组（pod）从随机源端口向 API 服务器端口（443）上的 `kubernetes` 服务 IP（`172.16.0.1`）发送请求。数据包类似于以下示例：

```
+-----------------+---------------------+-----------------+
| IP Header       | TCP Header          | Payload         |
| Src: 10.85.1.56 | Src: 67493 (random) |                 |
| Dst: 172.16.0.1 | Dst: 443            |                 |
+-----------------+---------------------+-----------------+
```

 **2. CNI 处理** 

CNI 检测到目标 IP 不属于其管理的任何容器组（pod）CIDR。由于**传出 NAT 已禁用**，CNI 会将数据包传递到主机网络堆栈，而不会对其进行修改。

 **3. 节点网络处理** 

数据包进入节点的网络堆栈，`netfilter` 钩子在该堆栈中触发 kube-proxy 设置的 `iptables` 规则。有多条规则按以下顺序适用：

1. 数据包首先到达 `KUBE-SERVICES` 链，链中包含与每项服务的 ClusterIP 和端口匹配的规则。

1. 匹配的规则跳转到包含负载均衡规则的 `kubernetes` 服务（发往 `172.16.0.1:443` 的数据包）的 `KUBE-SVC-XXX` 链。

1. 负载均衡规则会为控制面板 ENI IP（`10.0.0.132` 或 `10.0.1.23`）随机选择一条 `KUBE-SEP-XXX` 链。

1. 所选 `KUBE-SEP-XXX` 链具有将目标 IP 从服务 IP 更改为所选 IP 的实际规则。这称为目标网络地址转换（DNAT）。

应用这些规则后，假设所选 EKS 控制面板 ENI 的 IP 是 `10.0.0.132`，则数据包如下所示：

```
+-----------------+---------------------+-----------------+
| IP Header       | TCP Header          | Payload         |
| Src: 10.85.1.56 | Src: 67493 (random) |                 |
| Dst: 10.0.0.132 | Dst: 443            |                 |
+-----------------+---------------------+-----------------+
```

由于目标 IP 不在本地网络中，节点会将数据包转发到其默认网关。

 **4. 本地路由器路由** 

本地路由器确定目标 IP (`10.0.0.132`) 属于 VPC CIDR (`10.0.0.0/16`)，并将其转发到连接至 AWS 的网关。

 **5. 跨边界传输** 

数据包通过您建立的连接（例如 Direct Connect 或 VPN）跨云边界传输到 VPC。

 **6. VPC 网络分发** 

VPC 网络层将数据包路由到 EKS 控制面板 ENI (`10.0.0.132`) 所在的正确子网。

 **7. ENI 接收** 

数据包到达附加到 Kubernetes API 服务器的 EKS 控制面板 ENI。

### 响应
<a name="_response_3"></a>

在 EKS 控制面板处理请求后，它会将响应发送回容器组（pod）：

 **7. API 服务器发送响应** 

EKS Kubernetes API 服务器会创建以原始源 IP 为目标的响应数据包。数据包类似于以下示例：

```
+-----------------+---------------------+-----------------+
| IP Header       | TCP Header          | Payload         |
| Src: 10.0.0.132 | Src: 443            |                 |
| Dst: 10.85.1.56 | Dst: 67493          |                 |
+-----------------+---------------------+-----------------+
```

由于目标 IP 属于配置的远程容器组 CIDR (`10.85.0.0/16`)，它通过 VPC 中的 ENI 将其发送，并将子网的路由器作为下一个跃点。

 **6. VPC 路由** 

VPC 路由表包含远程容器组 CIDR (`10.85.0.0/16`) 的条目，该条目将此流量引导至“VPC 到本地”网关。

 **5. 跨边界传输** 

网关通过您建立的连接（例如 Direct Connect 或 VPN）将数据包跨云边界传输到本地网络。

 **4. 本地网络接收** 

数据包到达您的本地路由器。

 **3. 分发到节点** 

路由器的表中有一个将 `10.80.0.2` 作为下一个跃点的 `10.85.1.0/24` 条目，该条目将数据包分发到我们的节点。

 **2. 节点网络处理** 

当数据包由节点的网络堆栈处理时，`conntrack`（`netfilter` 的一部分）会将数据包与容器组最初建立的连接进行比对。由于最初应用了 DNAT，因此 `conntrack` 会通过将源 IP 从 EKS 控制面板 ENI 的 IP 重写为 `kubernetes` 服务 IP，从而逆转 DNAT：

```
+-----------------+---------------------+-----------------+
| IP Header       | TCP Header          | Payload         |
| Src: 172.16.0.1 | Src: 443            |                 |
| Dst: 10.85.1.56 | Dst: 67493          |                 |
+-----------------+---------------------+-----------------+
```

 **1。CNI 处理** 

CNI 确定目标 IP 属于其网络中的某个容器组（pod），并将数据包分发到正确的容器组（pod）网络命名空间。

此流程展示了为何远程容器组（pod）CIDR 必须能够从 VPC 正确路由到托管每个容器组（pod）的特定节点 – 整个返回路径取决于云和本地网络中容器组（pod）IP 的正确路由。

### 使用 CNI NAT
<a name="_with_cni_nat"></a>

此流程与*不使用 CNI NAT* 的流程非常相似，但有一个主要区别：CNI 会在将数据包发送到节点的网络堆栈之前对数据包应用源 NAT（SNAT）。这会将数据包的源 IP 更改为节点的 IP，从而无需进行额外的路由配置即可将数据包路由回节点。

### 请求
<a name="_request_4"></a>

 **1。容器组（pod）发起请求** 

容器组（pod）从随机源端口向 EKS Kubernetes API 服务器端口（443）上的 `kubernetes` 服务 IP（`172.16.0.1`）发送请求。数据包类似于以下示例：

```
+-----------------+---------------------+-----------------+
| IP Header       | TCP Header          | Payload         |
| Src: 10.85.1.56 | Src: 67493 (random) |                 |
| Dst: 172.16.0.1 | Dst: 443            |                 |
+-----------------+---------------------+-----------------+
```

 **2. CNI 处理** 

CNI 检测到目标 IP 不属于其管理的任何容器组（pod）CIDR。由于**传出 NAT 已启用**，CNI 会对数据包应用 SNAT，将源 IP 更改为节点的 IP，然后再将其传递到节点的网络堆栈：

```
+-----------------+---------------------+-----------------+
| IP Header       | TCP Header          | Payload         |
| Src: 10.80.0.2  | Src: 67493 (random) |                 |
| Dst: 172.16.0.1 | Dst: 443            |                 |
+-----------------+---------------------+-----------------+
```

注意：为清楚起见，CNI 和 `iptables` 在示例中显示为单独的块，但实际上，某些 CNI 可能使用 `iptables` 来应用 NAT。

 **3. 节点网络处理** 

在这里，由 `kube-proxy` 设置的 `iptables` 规则的行为与之前的示例相同，即将数据包负载均衡到其中一个 EKS 控制面板 ENI。现在的数据包如下所示：

```
+-----------------+---------------------+-----------------+
| IP Header       | TCP Header          | Payload         |
| Src: 10.80.0.2  | Src: 67493 (random) |                 |
| Dst: 10.0.0.132 | Dst: 443            |                 |
+-----------------+---------------------+-----------------+
```

由于目标 IP 不在本地网络中，节点会将数据包转发到其默认网关。

 **4. 本地路由器路由** 

本地路由器确定目标 IP (`10.0.0.132`) 属于 VPC CIDR (`10.0.0.0/16`)，并将其转发到连接至 AWS 的网关。

 **5. 跨边界传输** 

数据包通过您建立的连接（例如 Direct Connect 或 VPN）跨云边界传输到 VPC。

 **6. VPC 网络分发** 

VPC 网络层将数据包路由到 EKS 控制面板 ENI (`10.0.0.132`) 所在的正确子网。

 **7. ENI 接收** 

数据包到达附加到 Kubernetes API 服务器的 EKS 控制面板 ENI。

### 响应
<a name="_response_4"></a>

在 EKS 控制面板处理请求后，它会将响应发送回容器组（pod）：

 **7. API 服务器发送响应** 

EKS Kubernetes API 服务器会创建以原始源 IP 为目标的响应数据包。数据包类似于以下示例：

```
+-----------------+---------------------+-----------------+
| IP Header       | TCP Header          | Payload         |
| Src: 10.0.0.132 | Src: 443            |                 |
| Dst: 10.80.0.2  | Dst: 67493          |                 |
+-----------------+---------------------+-----------------+
```

由于目标 IP 属于配置的远程节点 CIDR (`10.80.0.0/16`)，它通过 VPC 中的 ENI 将其发送，并将子网的路由器作为下一个跃点。

 **6. VPC 路由** 

VPC 路由表包含远程节点 CIDR (`10.80.0.0/16`) 的条目，该条目将此流量引导至“VPC 到本地”网关。

 **5. 跨边界传输** 

网关通过您建立的连接（例如 Direct Connect 或 VPN）将数据包跨云边界传输到本地网络。

 **4. 本地网络接收** 

数据包到达您的本地路由器。

 **3. 分发到节点** 

本地路由器确定目标 IP (`10.80.0.2`) 地址属于其直连网络，并将数据包直接转发到目标混合节点。

 **2. 节点网络处理** 

当数据包由节点的网络堆栈处理时，`conntrack`（`netfilter` 的一部分）会将数据包与容器组（pod）最初建立的连接进行匹配，并且由于最初应用了 DNAT，所以可通过将源 IP 从 EKS 控制面板 ENI 的 IP 重写到 `kubernetes` 服务 IP 来反转这一过程：

```
+-----------------+---------------------+-----------------+
| IP Header       | TCP Header          | Payload         |
| Src: 172.16.0.1 | Src: 443            |                 |
| Dst: 10.80.0.2  | Dst: 67493          |                 |
+-----------------+---------------------+-----------------+
```

 **1。CNI 处理** 

CNI 确定此数据包属于它之前应用过 SNAT 的连接。它会反转 SNAT，将目标 IP 改回容器组（pod）的 IP：

```
+-----------------+---------------------+-----------------+
| IP Header       | TCP Header          | Payload         |
| Src: 172.16.0.1 | Src: 443            |                 |
| Dst: 10.85.1.56 | Dst: 67493          |                 |
+-----------------+---------------------+-----------------+
```

CNI 检测到目标 IP 属于其网络中的某个容器组（pod），并将数据包分发到正确的容器组（pod）网络命名空间。

此流程展示了 CNI NAT 操作如何允许将数据包路由回节点，而无需为容器组（pod）CIDR 进行额外路由，从而简化配置。

## EKS 控制面板到混合节点上运行的容器组（pod）（Webhook）
<a name="hybrid-nodes-concepts-traffic-flows-cp-to-pod"></a>

![\[EKS 控制面板到混合节点上运行的容器组（pod）\]](http://docs.aws.amazon.com/zh_cn/eks/latest/userguide/images/hybrid-nodes-cp-to-pod.png)


这种流量模式最常见于 Webhook，其中 EKS 控制面板需要直接启动与在混合节点上的容器组（pod）中运行的 Webhook 服务器的连接。示例包括验证和变更准入 Webhook，它们由 API 服务器在资源验证或变更过程中调用。

### 请求
<a name="_request_5"></a>

 **1。EKS Kubernetes API 服务器启动请求** 

如果集群中配置了 Webhook 并且相关的 API 操作触发了它，EKS Kubernetes API 服务器需要直接连接到 Webhook 服务器容器组（pod）。API 服务器首先从与 Webhook 关联的服务或端点资源中查找容器组（pod）的 IP 地址。

假设 Webhook 容器组在 IP 为 `10.85.1.23` 的混合节点上运行，则 EKS Kubernetes API 服务器会创建一个针对 Webhook 端点的 HTTPS 请求。初始数据包通过 VPC 中的 EKS 控制面板 ENI 发送，因为目标 IP `10.85.1.23` 属于配置的远程容器组 CIDR (`10.85.0.0/16`)。数据包类似于以下示例：

```
+-----------------+---------------------+-----------------+
| IP Header       | TCP Header          | Payload         |
| Src: 10.0.0.132 | Src: 41892 (random) |                 |
| Dst: 10.85.1.23 | Dst: 8443           |                 |
+-----------------+---------------------+-----------------+
```

 **2. VPC 网络处理** 

数据包离开 EKS 控制面板 ENI，进入 VPC 网络层，子网的路由器作为下一个跃点。

 **3. VPC 路由表查找** 

包含 EKS 控制面板 ENI 的子网的 VPC 路由表包含远程容器组 CIDR (`10.85.0.0/16`) 的专用路由。此路由规则将数据包引导至“VPC 到本地”网关（例如，用于 Direct Connect 或 VPN 连接的虚拟专用网关）：

```
Destination     Target
10.0.0.0/16     local
10.85.0.0/16    vgw-id (VPC-to-onprem gateway)
```

 **4. 跨边界传输** 

网关通过您建立的连接（例如 Direct Connect 或 VPN）将数据包跨云边界传输到本地网络。数据包在穿过此连接时会保留其原始源和目标 IP 地址。

 **5. 本地网络接收** 

数据包到达您的本地路由器。路由器会查询其路由表以确定如何访问 10.85.1.23 地址。为此，您的本地网络必须拥有容器组（pod）CIDR 的路由，这些路由可以将流量引导到相应的混合节点。

在这种情况下，路由器的路由表中将包含一个条目，指示可通过 IP 为 `10.80.0.2` 的混合节点访问 `10.85.1.0/24` 子网：

```
Destination     Next Hop
10.85.1.0/24    10.80.0.2
```

 **6. 分发到节点** 

根据路由表条目，路由器将数据包转发到混合节点 (`10.80.0.2`)。数据包到达节点时，它看起来与 EKS Kubernetes API 服务器发送它时相同，目标 IP 仍然是容器组（pod）的 IP。

 **7. CNI 处理** 

节点的网络堆栈接收数据包，由于目标 IP 不是节点自己的 IP，因此将其传递给 CNI 进行处理。CNI 确定目标 IP 属于在此节点上本地运行的容器组（pod），并通过相应的虚拟接口将数据包转发到正确的容器组（pod）：

```
Original packet -> node routing -> CNI -> Pod's network namespace
```

容器组（pod）中的 Webhook 服务器接收并处理请求。

### 响应
<a name="_response_5"></a>

在 Webhook 容器组（pod）处理请求后，它会按照相同的路径反向发送响应：

 **7. 容器组（pod）发送响应** 

Webhook 容器组（pod）创建响应数据包，并以自己的 IP 作为源，原始请求者（EKS 控制面板 ENI）作为目标：

```
+-----------------+---------------------+-----------------+
| IP Header       | TCP Header          | Payload         |
| Src: 10.85.1.23 | Src: 8443           |                 |
| Dst: 10.0.0.132 | Dst: 41892          |                 |
+-----------------+---------------------+-----------------+
```

CNI 识别此数据包发送到外部网络（不是本地容器组），并将数据包传递到节点的网络堆栈，同时保留原始源 IP。

 **6. 节点网络处理** 

节点确定目标 IP (`10.0.0.132`) 不在本地网络中，并将数据包转发到其默认网关（本地路由器）。

 **5. 本地路由器路由** 

本地路由器会查询其路由表并确定目标 IP (`10.0.0.132`) 属于 VPC CIDR (`10.0.0.0/16`)。它会将数据包转发到连接到 AWS 的网关。

 **4. 跨边界传输** 

数据包通过同一个本地到 VPC 的连接返回，朝相反的方向穿过云边界。

 **3. VPC 路由** 

数据包到达 VPC 时，路由表确定目标 IP 属于该 VPC 内的子网。数据包将在 VPC 内相应路由。

 **2. 和 1. EKS 控制面板 ENI 接收** 

数据包到达附加到 Kubernetes API 服务器的 ENI，从而完成往返行程。API 服务器接收 Webhook 响应，并根据此响应继续处理原始 API 请求。

此流量说明了为什么必须正确配置和路由远程容器组（pod）CIDR：
+ VPC 必须具有指向本地网关的远程容器组（pod）CIDR 的路由
+ 您的本地网络必须具有容器组（pod）CIDR 的路由，这些路由可以将流量引导到托管这些容器组（pod）的特定节点
+ 如果没有此路由配置，则无法从 EKS 控制面板访问混合节点上的容器组（pod）中运行的 Webhook 和其他类似服务。

## 在混合节点上运行的容器组（pod）到容器组（pod）
<a name="hybrid-nodes-concepts-traffic-flows-pod-to-pod"></a>

![\[在混合节点上运行的容器组（pod）到容器组（pod）\]](http://docs.aws.amazon.com/zh_cn/eks/latest/userguide/images/hybrid-nodes-pod-to-pod.png)


本节介绍在不同混合节点上运行的容器组（pod）如何相互通信。此示例假设您的 CNI 使用 VXLAN 进行封装，这在 Cilium 或 Calico 等 CNI 中很常见。其他封装协议（例如 Geneve 或 IP-in-IP）的整体过程与示例相似。

### 请求
<a name="_request_6"></a>

 **1。容器组（pod）A 启动通信** 

节点 1 上的容器组 A (`10.85.1.56`) 想要向节点 2 上的容器组 B (`10.85.2.67`) 发送流量。初始数据包类似于以下示例：

```
+------------------+-----------------+-------------+-----------------+
| Ethernet Header  | IP Header       | TCP/UDP     | Payload         |
| Src: Pod A MAC   | Src: 10.85.1.56 | Src: 43721  |                 |
| Dst: Gateway MAC | Dst: 10.85.2.67 | Dst: 8080   |                 |
+------------------+-----------------+-------------+-----------------+
```

 **2. CNI 拦截并处理数据包** 

容器组（pod）A 的数据包离开其网络命名空间时，CNI 会拦截它。CNI 会查询其路由表并确定：– 目标 IP (`10.85.2.67`) 属于容器组 CIDR – 此 IP 不在本地节点上，但属于节点 2 (`10.80.0.3`) – 数据包需要用 VXLAN 进行封装。

封装的决定至关重要，因为底层物理网络不知道如何直接路由容器组（pod）CIDR，它只知道如何在节点 IP 之间路由流量。

CNI 将整个原始数据包封装在 VXLAN 帧中。这实际上创建了一个带有新标头的“数据包中的数据包”：

```
+-----------------+----------------+--------------+------------+---------------------------+
| Outer Ethernet  | Outer IP       | Outer UDP    | VXLAN      | Original Pod-to-Pod       |
| Src: Node1 MAC  | Src: 10.80.0.2 | Src: Random  | VNI: 42    | Packet (unchanged         |
| Dst: Router MAC | Dst: 10.80.0.3 | Dst: 8472    |            | from above)               |
+-----------------+----------------+--------------+------------+---------------------------+
```

关于此封装的要点：– 外部数据包从节点 1 (`10.80.0.2`) 寻址到节点 2 (`10.80.0.3`) – UDP 端口 `8472` 是 Cilium 默认使用的 VXLAN 端口 – VXLAN 网络标识符（VNI）确定此数据包属于哪个叠加网络 – 整个原始数据包（以容器组 A 的 IP 作为源，容器组 B 的 IP 作为目标）完好无损地保留在内部

封装后的数据包现在进入节点 1 的常规网络堆栈，并按照与任何其他数据包相同的方式处理：

1.  **节点网络处理**：节点 1 的网络堆栈根据其目标路由数据包 (`10.80.0.3`)

1.  **本地网络分发**：
   + 如果两个节点都在同一个第 2 层网络上，则数据包将直接发送到节点 2
   + 如果它们位于不同的子网上，则首先将数据包转发到本地路由器

1.  **路由器处理**：路由器根据其路由表转发数据包，然后将其分发到节点 2

 **3. 接收节点处理** 

当封装后的数据包到达节点 2 (`10.80.0.3`) 时：

1. 该节点的网络堆栈接收它并将其标识为 VXLAN 数据包（UDP 端口 `4789`）

1. 数据包传递到 CNI 的 VXLAN 接口进行处理

 **4. VXLAN 解封装** 

节点 2 上的 CNI 处理 VXLAN 数据包：

1. 去掉外部标头（以太网、IP、UDP 和 VXLAN）

1. 提取原始的内部数据包

1. 数据包现在恢复为原始形式：

```
+------------------+-----------------+-------------+-----------------+
| Ethernet Header  | IP Header       | TCP/UDP     | Payload         |
| Src: Pod A MAC   | Src: 10.85.1.56 | Src: 43721  |                 |
| Dst: Gateway MAC | Dst: 10.85.2.67 | Dst: 8080   |                 |
+------------------+-----------------+-------------+-----------------+
```

节点 2 上的 CNI 会检查目标 IP (`10.85.2.67`)，并且：

1. 确定此 IP 属于本地容器组（pod）

1. 通过相应的虚拟接口路由数据包

1. 将数据包分发到容器组（pod）B 的网络命名空间

### 响应
<a name="_response_6"></a>

容器组（pod）B 响应容器组（pod）A 时，整个过程是相反的：

1. 容器组 B 向容器组 A 发送数据包 (`10.85.1.56`)

1. 节点 2 的 CNI 使用 VXLAN 将其封装，并将目标设置为节点 1 (`10.80.0.2`)

1. 封装后的数据包分发到节点 1

1. 节点 1 的 CNI 将其解封并将原始响应分发给容器组（pod）A

## 云节点上的容器组（pod）到混合节点上的容器组（pod）（东西向流量）
<a name="hybrid-nodes-concepts-traffic-flows-east-west"></a>

![\[云节点上的容器组（pod）到混合节点上的容器组（pod）\]](http://docs.aws.amazon.com/zh_cn/eks/latest/userguide/images/hybrid-nodes-east-west.png)


### 请求
<a name="_request_7"></a>

 **1。容器组（pod）A 启动通信** 

EC2 节点上的容器组 A (`10.0.0.56`) 想要向混合节点上的容器组 B (`10.85.1.56`) 发送流量。初始数据包类似于以下示例：

```
+-----------------+---------------------+-----------------+
| IP Header       | TCP Header          | Payload         |
| Src: 10.0.0.56  | Src: 52390 (random) |                 |
| Dst: 10.85.1.56 | Dst: 8080           |                 |
+-----------------+---------------------+-----------------+
```

使用 VPC CNI 时，容器组（pod）A 拥有来自 VPC CIDR 的 IP，并直接附加到 EC2 实例上的 ENI。容器组（pod）的网络命名空间连接到 VPC 网络，因此数据包直接进入 VPC 路由基础设施。

 **2. VPC 路由** 

VPC 路由表包含远程容器组 CIDR (`10.85.0.0/16`) 的专用路由，该路由将此流量引导至“VPC 到本地”网关：

```
Destination     Target
10.0.0.0/16     local
10.85.0.0/16    vgw-id (VPC-to-onprem gateway)
```

根据此路由规则，数据包将被引导至连接到您的本地网络的网关。

 **3. 跨边界传输** 

网关通过您建立的连接（例如 Direct Connect 或 VPN）将数据包跨云边界传输到本地网络。在此整个传输过程中，数据包会保留其原始源和目标 IP 地址。

 **4. 本地网络接收** 

数据包到达您的本地路由器。路由器会查询其路由表，确定到达 10.85.1.56 地址的下一个跃点。您的本地路由器必须拥有容器组（pod）CIDR 的路由，这些路由可以将流量引导到相应的混合节点。

路由器的路由表中将包含一个条目，指示可通过 IP 为 `10.80.0.2` 的混合节点访问 `10.85.1.0/24` 子网：

```
Destination     Next Hop
10.85.1.0/24    10.80.0.2
```

 **5. 节点网络处理** 

路由器将数据包转发到混合节点 (`10.80.0.2`)。当数据包到达节点时，它仍将容器组（pod）A 的 IP 作为源，将容器组（pod）B 的 IP 作为目标。

 **6. CNI 处理** 

节点的网络堆栈接收数据包，由于目标 IP 不是自己的 IP，因此将其传递给 CNI 进行处理。CNI 确定目标 IP 属于在此节点上本地运行的容器组（pod），并通过相应的虚拟接口将数据包转发到正确的容器组（pod）：

```
Original packet -> node routing -> CNI -> Pod B's network namespace
```

容器组（pod）B 接收数据包并根据需要进行处理。

### 响应
<a name="_response_7"></a>

 **6. 容器组（pod）B 发送响应** 

容器组（pod）B 创建一个以自己的 IP 作为源、容器组（pod）A 的 IP 作为目标的响应数据包：

```
+-----------------+---------------------+-----------------+
| IP Header       | TCP Header          | Payload         |
| Src: 10.85.1.56 | Src: 8080           |                 |
| Dst: 10.0.0.56  | Dst: 52390          |                 |
+-----------------+---------------------+-----------------+
```

CNI 确定此数据包发往外部网络，并将其传递到节点的网络堆栈。

 **5. 节点网络处理** 

节点确定目标 IP (`10.0.0.56`) 不属于本地网络，并将数据包转发到其默认网关（本地路由器）。

 **4. 本地路由器路由** 

本地路由器会查询其路由表并确定目标 IP (`10.0.0.56`) 属于 VPC CIDR (`10.0.0.0/16`)。它会将数据包转发到连接到 AWS 的网关。

 **3. 跨边界传输** 

数据包通过同一个本地到 VPC 的连接返回，朝相反的方向穿过云边界。

 **2. VPC 路由** 

数据包到达 VPC 时，路由系统确定目标 IP 属于该 VPC 内的子网。数据包通过 VPC 网络路由到托管容器组（pod）A 的 EC2 实例。

 **1。容器组（pod）A 收到响应** 

数据包到达 EC2 实例，并通过其附加的 ENI 直接分发到容器组（pod）A。由于 VPC CNI 不对 VPC 中的容器组（pod）使用叠加网络，因此无需进行额外的解封 – 数据包到达时其原始标头保持不变。

此东西向流量说明了为什么必须正确配置远程容器组（pod）CIDR 并可从两个方向路由：
+ VPC 必须具有指向本地网关的远程容器组（pod）CIDR 的路由
+ 您的本地网络必须具有容器组（pod）CIDR 的路由，这些路由可以将流量引导到托管这些容器组（pod）的特定节点。

# 混合节点 `nodeadm` 参考
<a name="hybrid-nodes-nodeadm"></a>

Amazon EKS 混合节点功能 CLI (`nodeadm`) 简化了混合节点组件的安装、配置、注册和卸载。您可以将 `nodeadm` 包含在操作系统映像中以自动执行混合节点引导过程，有关更多信息，请参阅[为混合节点准备操作系统](hybrid-nodes-os.md)。

用于混合节点的 `nodeadm` 版本，与用于引导 Amazon EC2 实例以作为 Amazon EKS 集群中节点的 `nodeadm` 版本不同。请按照相应 `nodeadm` 版本的文档和参考进行操作。此文档页面适用于混合节点 `nodeadm` 版本。

https://github.com/aws/eks-hybrid GitHub 存储库发布了混合节点 `nodeadm` 的源代码。

**重要**  
您必须使用具有 root/sudo 权限的用户运行 `nodeadm`。

## 下载 `nodeadm`
<a name="_download_nodeadm"></a>

`nodeadm` 的混合节点版本在 Amazon S3 中托管，由 Amazon CloudFront 分发。要在每台本地主机上安装 `nodeadm`，您可以在本地主机上运行以下命令。

 **x86\$164 主机：**

```
curl -OL 'https://hybrid-assets.eks.amazonaws.com/releases/latest/bin/linux/amd64/nodeadm'
```

 **ARM 主机** 

```
curl -OL 'https://hybrid-assets.eks.amazonaws.com/releases/latest/bin/linux/arm64/nodeadm'
```

将可执行文件权限添加到每台主机上下载的二进制文件。

```
chmod +x nodeadm
```

## `nodeadm install`
<a name="_nodeadm_install"></a>

`nodeadm install` 命令用于安装运行和将混合节点加入 Amazon EKS 集群所需的构件和依赖项。`nodeadm install` 命令可以在每个混合节点上单独运行，也可以在映像生成管道期间运行，以便在操作系统映像中预装混合节点依赖项。

 **用法** 

```
nodeadm install [KUBERNETES_VERSION] [flags]
```

 **定位参数** 

（必需）`KUBERNETES_VERSION` 要安装的 EKS Kubernetes 的主要.次要版本，例如 `1.32` 

 **Flags** 


| 名称 | 必需 | 说明 | 
| --- | --- | --- | 
|   `-p`,  `--credential-provider`   |  TRUE  |  要安装的凭证提供者。支持的值为 `iam-ra` 和 `ssm`。请参阅[准备用于混合节点的凭证](hybrid-nodes-creds.md)了解更多信息。  | 
|   `-s`,  `--containerd-source`   |  FALSE  |  `containerd` 的来源。`nodeadm` 支持从操作系统发行版、Docker 软件包安装 `containerd` 以及跳过 `containerd` 安装。  **值**   `distro`：此为默认值。`nodeadm` 会安装由节点操作系统分发的、与 EKS Kubernetes 版本兼容的最新 `containerd` 软件包。`distro` 并非 Red Hat Enterprise Linux（RHEL）操作系统的有效值。  `docker`：`nodeadm` 会安装由 Docker 编译并分发的、与 EKS Kubernetes 版本兼容的最新 `containerd` 软件包。`docker` 并非 Amazon Linux 2023 的有效值。  `none`：`nodeadm` 不会安装 `containerd` 软件包。您必须首先手动安装 `containerd`，然后再运行 `nodeadm init`。  | 
|   `-r`,  `--region`   |  FALSE  |  指定用于下载 SSM Agent 等构件的 AWS 区域。默认值为 `us-west-2`。  | 
|   `-t`,  `--timeout`   |  FALSE  |  安装命令的最大持续时间。输入遵循持续时间格式。例如 `1h23m`。安装命令的默认下载超时设置为 20 分钟。  | 
|   `-h`, `--help`   |  FALSE  |  显示带有可用标志、子命令和位置值参数的帮助消息。  | 

 **示例** 

安装 Kubernetes 版本 `1.32`，并将 AWS Systems Manager（SSM）作为凭证提供者

```
nodeadm install 1.32 --credential-provider ssm
```

安装 Kubernetes 版本 `1.32`，并将 AWS Systems Manager（SSM）作为凭证提供者，将 Docker 作为 containerd 源，下载超时设置为 20 分钟。

```
nodeadm install 1.32 --credential-provider ssm --containerd-source docker --timeout 20m
```

安装 Kubernetes 版本 `1.32`，并将 AWS IAM Roles Anywhere 作为凭证提供者

```
nodeadm install 1.32 --credential-provider iam-ra
```

## `nodeadm config check`
<a name="_nodeadm_config_check"></a>

`nodeadm config check` 命令会检查提供的节点配置是否存在错误。此命令可用于确认和验证混合节点配置文件的正确性。

 **用法** 

```
nodeadm config check [flags]
```

 **Flags** 


| 名称 | 必需 | 说明 | 
| --- | --- | --- | 
|   `-c`,  `--config-source`   |  TRUE  |  nodeadm 配置的来源。对于混合节点，输入应遵循带文件架构的 URI。  | 
|   `-h`, `--help`   |  FALSE  |  显示带有可用标志、子命令和位置值参数的帮助消息。  | 

 **示例** 

```
nodeadm config check -c file://nodeConfig.yaml
```

## `nodeadm init`
<a name="_nodeadm_init"></a>

`nodeadm init` 命令会启动混合节点并将其连接到配置的 Amazon EKS 集群。有关如何配置 `nodeConfig.yaml` 文件的详细信息，请参阅[SSM 混合激活的节点配置](#hybrid-nodes-node-config-ssm)或[IAM Roles Anywhere 的节点配置](#hybrid-nodes-node-config-iamra)。

 **用法** 

```
nodeadm init [flags]
```

 **Flags** 


| 名称 | 必需 | 说明 | 
| --- | --- | --- | 
|   `-c`,  `--config-source`   |  TRUE  |  `nodeadm` 配置的来源。对于混合节点，输入应遵循带文件架构的 URI。  | 
|   `-s`,  `--skip`   |  FALSE  |  要跳过的 `init` 阶段。除非有助于解决问题，否则不建议跳过任何阶段。  **值**   `install-validation` 会跳过检查之前的安装命令是否成功运行。  如果节点上启用了防火墙，则 `cni-validation` 会跳过检查 Cilium 或 Calico CNI 的 VXLAN 端口是否已打开  如果节点 IP 在远程节点网络的 CIDR 范围内，`node-ip-validation` 将会跳过检查。  | 
|   `-h`, `--help`   |  FALSE  |  显示带有可用标志、子命令和位置值参数的帮助消息。  | 

 **示例** 

```
nodeadm init -c file://nodeConfig.yaml
```

## `nodeadm upgrade`
<a name="_nodeadm_upgrade"></a>

`nodeadm upgrade` 命令会将所有已安装的构件升级到最新版本，启动节点以配置升级后的构件并加入 AWS 上的 EKS 集群。对于在节点上运行的工作负载，升级是一个中断性命令。在运行升级之前，请将您的工作负载转移至其他节点。

 **用法** 

```
nodeadm upgrade [KUBERNETES_VERSION] [flags]
```

 **定位参数** 

（必需）`KUBERNETES_VERSION` 要安装的 EKS Kubernetes 的主要.次要版本，例如 `1.32` 

 **Flags** 


| 名称 | 必需 | 说明 | 
| --- | --- | --- | 
|   `-c`,  `--config-source`   |  TRUE  |  `nodeadm` 配置的来源。对于混合节点，输入应遵循带文件架构的 URI。  | 
|   `-t`,  `--timeout`   |  FALSE  |  下载构件超时。输入遵循持续时间格式。例如，1h23m。升级命令的默认下载超时设置为 10 分钟。  | 
|   `-s`,  `--skip`   |  FALSE  |  要跳过的升级阶段。除非有助于解决问题，否则不建议跳过任何阶段。  **值**   `pod-validation` 会跳过检查除进程守护程序集和静态容器组外，是否节点上的所有容器组都在运行。  `node-validation` 会跳过检查节点是否已被封锁。  `init-validation` 会跳过检查节点在运行升级之前是否已成功初始化。  `containerd-major-version-upgrade` 可避免在节点升级期间对 containerd 执行大版本升级操作。  | 
|   `-h`, `--help`   |  FALSE  |  显示带有可用标志、子命令和位置值参数的帮助消息。  | 

 **示例** 

```
nodeadm upgrade 1.32 -c file://nodeConfig.yaml
```

```
nodeadm upgrade 1.32 -c file://nodeConfig.yaml --timeout 20m
```

## `nodeadm uninstall`
<a name="_nodeadm_uninstall"></a>

`nodeadm uninstall` 命令会停止并移除在 `nodeadm install` 期间安装的构件 `nodeadm`，包括 kubelet 和 containerd。请注意，卸载命令不会从集群中清空或删除混合节点。您必须分别运行清空和删除操作，有关更多信息，请参阅[移除混合节点](hybrid-nodes-remove.md)。默认情况下，如果节点上还有容器组，则 `nodeadm uninstall` 不会执行。同样，`nodeadm uninstall` 也不会移除 CNI 依赖项或您在集群上运行的其他 Kubernetes 附加组件的依赖项。要从主机上完全移除 CNI 安装，请参阅[为混合节点配置 CNI](hybrid-nodes-cni.md) 中的说明。如果将 AWS SSM 混合激活作为本地凭证提供者，则 `nodeadm uninstall` 命令将从 AWS SSM 托管式实例中注销您的主机。

 **用法** 

```
nodeadm uninstall [flags]
```

 **Flags** 


| 名称 | 必需 | 说明 | 
| --- | --- | --- | 
|   `-s`,  `--skip`   |  FALSE  |  要跳过的卸载阶段。除非有助于解决问题，否则不建议跳过任何阶段。  **值**   `pod-validation` 会跳过检查除进程守护程序集和静态容器组外，是否节点上的所有容器组都在运行。  `node-validation` 会跳过检查节点是否已被封锁。  `init-validation` 会跳过检查节点在运行卸载之前是否已成功初始化。  | 
|   `-h`,  `--help`   |  FALSE  |  显示带有可用标志、子命令和位置值参数的帮助消息。  | 
|   `-f`,  `--force`   |  FALSE  |  强制删除可能包含 Kubernetes 和 CNI 组件中剩余文件的其他目录。  **WARNING**  此操作将删除默认 Kubernetes 和 CNI 目录（`/var/lib/cni`、`/etc/cni/net.d` 等）中的所有内容。如果您将自己的数据存储在这些位置，请不要使用此标志。 从 nodeadm `v1.0.9` 开始，`./nodeadm uninstall --skip node-validation,pod-validation --force` 命令不再删除 `/var/lib/kubelet` 目录。这是因为该目录可能包含容器组（pod）卷和 volume-subpath 目录，这些目录有时会包含已挂载的节点文件系统。  **安全处理提示**  - 删除已挂载的路径可能会导致意外删除实际挂载的节点文件系统。在手动删除 `/var/lib/kubelet` 目录之前，请仔细检查所有活动的挂载并安全地卸载卷，以免丢失数据。  | 

 **示例** 

```
nodeadm uninstall
```

```
nodeadm uninstall --skip node-validation,pod-validation
```

## `nodeadm debug`
<a name="_nodeadm_debug"></a>

`nodeadm debug` 命令可用于对运行不正常或配置有错误的混合节点进行故障排除。此命令可以验证以下要求是否已经满足。
+ 该节点具有必需 AWS API 的网络访问权限以获取凭证，
+ 该节点能够获取所配置混合节点 IAM 角色的 AWS 凭证，
+ 该节点具有对 EKS Kubernetes API 端点的网络访问权限，并且 EKS Kubernetes API 端点证书的有效，
+ 该节点能够通过 EKS 集群身份验证，其在集群中的身份有效，并且该节点可以通过为 EKS 集群配置的 VPC 访问 EKS 集群。

如果发现错误，该命令的输出会提供故障排除步骤建议。某些验证步骤会显示子进程。如果这些子进程失败，则输出将显示在验证错误下的 stderr 部分中。

 **用法** 

```
nodeadm debug [flags]
```

 **Flags** 


| 名称 | 必需 | 说明 | 
| --- | --- | --- | 
|   `-c`, `--config-source`   |  TRUE  |  `nodeadm` 配置的来源。对于混合节点，输入应遵循带文件架构的 URI。  | 
|   `--no-color`   |  FALSE  |  禁用彩色输出。对自动化很有用。  | 
|   `-h`, `--help`   |  FALSE  |  显示带有可用标志、子命令和位置值参数的帮助消息。  | 

 **示例** 

```
nodeadm debug -c file://nodeConfig.yaml
```

## nodeadm 文件位置
<a name="_nodeadm_file_locations"></a>

### nodeadm 安装
<a name="_nodeadm_install_2"></a>

运行 `nodeadm install` 时，将配置以下文件和文件位置。


| Artifact | 路径 | 
| --- | --- | 
|  IAM Roles Anywhere CLI  |  /usr/local/bin/aws\$1signing\$1helper  | 
|  Kubelet 二进制包  |  /usr/bin/kubelet  | 
|  Kubectl 二进制包  |  usr/local/bin/kubectl  | 
|  ECR 凭证提供者  |  /etc/eks/image-credential-provider/ecr-credential-provider  | 
|   AWS IAM 身份验证器  |  /usr/local/bin/aws-iam-authenticator  | 
|  SSM 安装 CLI  |  /opt/ssm/ssm-setup-cli  | 
|  SSM Agent  |  在 Ubuntu 上：/snap/amazon-ssm-agent/current/amazon-ssm-agent 在 RHEL 和 AL2023 上：/usr/bin/amazon-ssm-agent  | 
|  Containerd  |  在 Ubuntu 和 AL2023 上：/usr/bin/containerd 在 RHEL 上：/bin/containerd  | 
|  Iptables  |  在 Ubuntu 和 AL2023 上：/usr/sbin/iptables 在 RHEL 上：/sbin/iptables  | 
|  CNI 插件  |  /opt/cni/bin  | 
|  安装的构件跟踪器  |  /opt/nodeadm/tracker  | 

### nodeadm init
<a name="_nodeadm_init_2"></a>

运行 `nodeadm init` 时，将配置以下文件和文件位置。


| 名称 | 路径 | 
| --- | --- | 
|  Kubelet kubeconfig  |  /var/lib/kubelet/kubelet/kubecconfig  | 
|  Kubelet config  |  /etc/kubernetes/kubelet/config.json  | 
|  Kubelet systemd 单元  |  /etc/systemd/system/kubelet.service  | 
|  映像凭证提供者配置  |  /etc/eks/image-credential-provider/config.json  | 
|  Kubelet 环境文件  |  /etc/eks/kubelet/environment  | 
|  Kubelet 证书  |  /etc/kubernetes/pki/ca.crt  | 
|  Containerd 配置  |  /etc/containerd/config.toml  | 
|  Containerd 内核模块配置  |  /etc/modules-load.d/contianerd.conf  | 
|   AWS 配置文件  |  /etc/aws/hybrid/config  | 
|   AWS 凭证文件（如果启用了凭证文件）  |  /eks-hybrid/.aws/credentials  | 
|   AWS 签名助手系统单元  |  /etc/systemd/system/aws\$1signing\$1helper\$1update.service  | 
|  Sysctl conf 文件  |  /etc/sysctl.d/99-nodeadm.conf  | 
|  Ca-certificates  |  /etc/ssl/certs/ca-certificates.crt  | 
|  Gpg 密钥文件  |  /etc/apt/keyrings/docker.asc  | 
|  Docker 存储库源文件  |  /etc/apt/sources.list.d/docker.list  | 

## SSM 混合激活的节点配置
<a name="hybrid-nodes-node-config-ssm"></a>

以下是将 AWS SSM 混合激活作为混合节点凭证的示例 `nodeConfig.yaml`。

```
apiVersion: node.eks.aws/v1alpha1
kind: NodeConfig
spec:
  cluster:
    name:             # Name of the EKS cluster
    region:           # AWS Region where the EKS cluster resides
  hybrid:
    ssm:
      activationCode: # SSM hybrid activation code
      activationId:   # SSM hybrid activation id
```

## IAM Roles Anywhere 的节点配置
<a name="hybrid-nodes-node-config-iamra"></a>

以下是将 AWS IAM Roles Anywhere 作为混合节点凭证的示例 `nodeConfig.yaml`。

如果将 AWS IAM Roles Anywhere 作为本地凭证提供者，您在 `nodeadm` 配置中使用的 `nodeName` 必须与您为混合节点 IAM 角色设定的权限范围一致。例如，假设混合节点 IAM 角色的权限仅允许 AWS IAM Roles Anywhere 在角色会话名称等于主机证书的 CN 时代入该角色，则 `nodeadm` 配置中的 `nodeName` 必须与证书的 CN 相同。您使用的 `nodeName` 长度不能超过 64 个字符。有关更多信息，请参阅 [准备用于混合节点的凭证](hybrid-nodes-creds.md)。

```
apiVersion: node.eks.aws/v1alpha1
kind: NodeConfig
spec:
  cluster:
    name:              # Name of the EKS cluster
    region:            # AWS Region where the EKS cluster resides
  hybrid:
    iamRolesAnywhere:
      nodeName:        # Name of the node
      trustAnchorArn:  # ARN of the IAM Roles Anywhere trust anchor
      profileArn:      # ARN of the IAM Roles Anywhere profile
      roleArn:         # ARN of the Hybrid Nodes IAM role
      certificatePath: # Path to the certificate file to authenticate with the IAM Roles Anywhere trust anchor
      privateKeyPath:  # Path to the private key file for the certificate
```

## 自定义 kubelet 的节点配置（可选）
<a name="hybrid-nodes-nodeadm-kubelet"></a>

您可以在 `nodeadm` 配置中传递 kubelet 配置和标志。有关如何添加额外节点标签 `abc.amazonaws.com/test-label` 和配置，以将 `shutdownGracePeriod` 设置为 30 秒的信息，请参阅以下示例。

```
apiVersion: node.eks.aws/v1alpha1
kind: NodeConfig
spec:
  cluster:
    name:             # Name of the EKS cluster
    region:           # AWS Region where the EKS cluster resides
  kubelet:
    config:           # Map of kubelet config and values
       shutdownGracePeriod: 30s
    flags:            # List of kubelet flags
       - --node-labels=abc.company.com/test-label=true
  hybrid:
    ssm:
      activationCode: # SSM hybrid activation code
      activationId:   # SSM hybrid activation id
```

## 自定义 containerd 的节点配置（可选）
<a name="_node_config_for_customizing_containerd_optional"></a>

您可以在 `nodeadm` 配置中传递自定义 containerd 配置。`nodeadm` containerd 配置接受内联 TOML。要了解如何配置 containerd 以禁用删除 containerd 内容存储中未打包的映像层，请参阅以下示例。

```
apiVersion: node.eks.aws/v1alpha1
kind: NodeConfig
spec:
  cluster:
    name:             # Name of the EKS cluster
    region:           # AWS Region where the EKS cluster resides
  containerd:
    config: |         # Inline TOML containerd additional configuration
       [plugins."io.containerd.grpc.v1.cri".containerd]
       discard_unpacked_layers = false
  hybrid:
    ssm:
      activationCode: # SSM hybrid activation code
      activationId:   # SSM hybrid activation id
```

**注意**  
containerd 1.x 与 2.x 采用不同的配置文件格式。containerd 1.x 使用配置版本 2，而 containerd 2.x 使用配置版本 3。虽然 containerd 2.x 对配置版本 2 仍保持向下兼容，但为实现最优性能，建议使用配置版本 3。您可通过 `containerd --version` 命令查看 containerd 版本，也可查阅 `nodeadm` 安装日志。有关配置版本控制的更多详细信息，请参阅 https://containerd.io/releases/

您还可以使用 containerd 配置来实现 SELinux 支持。在 containerd 上启用 SELinux 后，确保在节点上调度的容器组启用了正确的 securityContext 和 seLinuxOptions。有关配置安全上下文的更多信息，请参阅 [Kubernetes 文档](https://kubernetes.io/docs/tasks/configure-pod-container/security-context/)。

**注意**  
Red Hat Enterprise Linux（RHEL）8 和 RHEL 9 在主机上默认启用了 SELinux 并设置为严格模式。Amazon Linux 2023 默认启用 SELinux 并设置为宽松模式。当主机上的 SELinux 设置为宽容模式时，在 containerd 上启用此功能不会阻止请求，但会根据主机上的 SELinux 配置记录请求。

```
apiVersion: node.eks.aws/v1alpha1
kind: NodeConfig
spec:
  cluster:
    name:             # Name of the EKS cluster
    region:           # AWS Region where the EKS cluster resides
  containerd:
    config: |         # Inline TOML containerd additional configuration
       [plugins."io.containerd.grpc.v1.cri"]
       enable_selinux = true
  hybrid:
    ssm:
      activationCode: # SSM hybrid activation code
      activationId:   # SSM hybrid activation id
```

# 混合节点故障排除
<a name="hybrid-nodes-troubleshooting"></a>

本主题介绍在使用 Amazon EKS 混合节点功能时可能遇到的一些常见错误以及修复方法。有关其他故障排除信息，请参阅[排查 Amazon EKS 集群和节点问题](troubleshooting.md)以及 AWS re:Post** 上[有关 Amazon EKS 的知识中心标签](https://repost.aws/tags/knowledge-center/TA4IvCeWI1TE66q4jEj4Z9zg/amazon-elastic-kubernetes-service)。如果您无法解决问题，请联系 AWS Support。

 **使用 `nodeadm debug` 对节点进行故障排除** 您可以从混合节点运行 `nodeadm debug` 命令来验证是否满足联网和凭证要求。有关 `nodeadm debug` 命令的更多信息，请参阅 [混合节点 `nodeadm` 参考](hybrid-nodes-nodeadm.md)。

 **使用集群见解检测混合节点的问题** Amazon EKS 集群见解包括*见解检查*，可检测集群中 EKS 混合节点配置的常见问题。您可以从 AWS 管理控制台、AWS CLI 和 AWS SDK 中查看所有见解检查的结果。有关集群见解的更多信息，请参阅 [利用集群见解为 Kubernetes 版本升级做好准备并对错误配置进行问题排查](cluster-insights.md)。

## 混合节点安装故障排除
<a name="hybrid-nodes-troubleshooting-install"></a>

以下故障排除主题与使用 `nodeadm install` 命令在主机上安装混合节点依赖项有关。

 ** `nodeadm`命令失败，`must run as root`**

运行 `nodeadm install` 命令的用户必须具有主机上的根权限或 `sudo` 权限。如果以没有根权限或 `sudo` 权限的用户身份运行 `nodeadm install`，则会在 `nodeadm` 输出中看到以下错误。

```
"msg":"Command failed","error":"must run as root"
```

 **无法连接到依赖项** 

`nodeadm install` 命令会安装混合节点必需的依赖项。混合节点依赖项包括 `containerd`、`kubelet`、`kubectl` 和 AWS SSM 或 AWS IAM Roles Anywhere 组件。您必须具有从运行 `nodeadm install` 的位置访问的权限才能下载这些依赖项。要详细了解您必须具有访问权限的位置列表，请参阅[准备混合节点的联网](hybrid-nodes-networking.md)。如果您没有访问权限，则会在 `nodeadm install` 输出中看到与以下类似的错误。

```
"msg":"Command failed","error":"failed reading file from url: ...: max retries achieved for http request"
```

 **更新软件包管理器失败** 

`nodeadm install` 命令会在安装混合节点依赖项之前运行 `apt update` 或 `yum update` 或 `dnf update`。如果此步骤未成功，您可能会看到与以下类似的错误。要修复错误，您可以首先运行 `apt update` 或 `yum update` 或 `dnf update`，然后再运行 `nodeadm install`，也可以尝试重新运行 `nodeadm install`。

```
failed to run update using package manager
```

 **超时或超过上下文截止时间** 

运行 `nodeadm install` 时，如果您在安装过程的若干阶段看到问题，并错误消息指示超时或超过上下文截止时间，则可能说明连接速度较慢，导致无法在超时之前安装混合节点依赖项。要解决这些问题，您可以尝试在 `nodeadm` 中使用 `--timeout` 标志来延长下载依赖项的超时期限。

```
nodeadm install K8S_VERSION --credential-provider CREDS_PROVIDER --timeout 20m0s
```

## 混合节点连接故障排除
<a name="hybrid-nodes-troubleshooting-connect"></a>

本节中的故障排除主题与使用 `nodeadm init` 命令将混合节点连接到 EKS 集群的过程有关。

 **操作错误或架构不受支持** 

运行 `nodeadm init` 时，如果您看到与 `operation error` 或 `unsupported scheme` 相关的错误，请检查 `nodeConfig.yaml` 以确保其格式正确并且已传递给 `nodeadm`。有关 `nodeConfig.yaml` 格式和选项的更多信息，请参阅[混合节点 `nodeadm` 参考](hybrid-nodes-nodeadm.md)。

```
"msg":"Command failed","error":"operation error ec2imds: GetRegion, request canceled, context deadline exceeded"
```

 **混合节点 IAM 角色缺少 `eks:DescribeCluster` 操作的权限** 

运行 `nodeadm init` 时，`nodeadm` 会尝试通过调用 EKS `DescribeCluster` 操作来收集有关 EKS 集群的信息。若混合节点 IAM 角色不具备 `eks:DescribeCluster` 操作的权限，则在执行 `nodeadm init` 时，您必须在传入 `nodeadm` 的节点配置中，手动指定 Kubernetes API 端点、集群 CA 证书包以及服务 IPv4 CIDR。请参阅[准备用于混合节点的凭证](hybrid-nodes-creds.md)，以了解有关混合节点 IAM 角色所需权限的更多信息。

```
"msg":"Command failed","error":"operation error EKS: DescribeCluster, https response error StatusCode: 403 ... AccessDeniedException"
```

 **混合节点 IAM 角色缺少 `eks:ListAccessEntries` 操作的权限** 

执行 `nodeadm init` 时，`nodeadm` 会尝试调用 EKS `ListAccessEntries` 操作，验证 EKS 集群是否存在一个与该混合节点 IAM 角色绑定的、类型为 `HYBRID_LINUX` 的访问条目。若混合节点 IAM 角色不具备 `eks:ListAccessEntries` 操作的权限，那么在执行 `nodeadm init` 命令时，您必须传入 `--skip cluster-access-validation` 标记。请参阅[准备用于混合节点的凭证](hybrid-nodes-creds.md)，以了解有关混合节点 IAM 角色所需权限的更多信息。

```
"msg":"Command failed","error":"operation error EKS: ListAccessEntries, https response error StatusCode: 403 ... AccessDeniedException"
```

 **节点 IP 不在远程节点网络 CIDR 范围内** 

运行 `nodeadm init` 时，如果节点 IP 地址不在指定远程节点网络 CIDR 范围内，则可能会出现错误。此错误将与以下示例类似：

```
node IP 10.18.0.1 is not in any of the remote network CIDR blocks [10.0.0.0/16 192.168.0.0/16]
```

此示例显示一个 IP 为 10.18.0.1 的节点正在尝试加入一个远程网络 CIDR 为 10.0.0.0/16 和 192.168.0.0/16 的集群。之所以出现此错误，是因为这两个 CIDR 均不包含 10.18.0.1。

确认您已正确配置 `RemoteNodeNetworks`，使其包含所有节点 IP 地址。有关网络配置的更多信息，请参阅[准备混合节点的联网](hybrid-nodes-networking.md)。
+ 在集群所在区域运行以下命令，检查您的 `RemoteNodeNetwork` 配置。验证输出中列出的 CIDR 块是否包含您的节点 IP 范围，并且与错误消息中列出的 CIDR 块相同。如果不一致，请确认 `nodeConfig.yaml` 中的集群名称和区域与预期的集群一致。

```
aws eks describe-cluster --name CLUSTER_NAME --region REGION_NAME --query cluster.remoteNetworkConfig.remoteNodeNetworks
```
+ 确认您使用的是预期的节点：
  + 检查节点的主机名和 IP 地址是否与您计划注册到集群的主机名和 IP 地址一致，从而确认节点是否正确。
  + 确认此节点所在的本地网络是否正确（其 CIDR 范围在集群设置期间注册为 `RemoteNodeNetwork`）。

如果节点 IP 仍不符合预期，请检查以下内容：
+ 如果您使用的是 IAM Roles Anywhere，`kubelet` 将对 IAM Roles Anywhere `nodeName` 执行 DNS 查找，并使用与节点名称关联的 IP（如果可用）。如果您负责维护节点的 DNS 条目，请确认这些条目指向远程节点网络 CIDR 内的 IP。
+ 如果节点有多个网络接口，`kubelet` 选择的默认接口的 IP 地址可能在远程节点网络 CIDR 范围外。要使用其他接口，请使用 `nodeConfig.yaml` 中的 `--node-ip` `kubelet` 标志指定其 IP 地址。有关更多信息，请参阅 [混合节点 `nodeadm` 参考](hybrid-nodes-nodeadm.md)。您可以通过在节点上运行以下命令，来查看节点的网络接口及其 IP 地址：

```
ip addr show
```

 **混合节点未在 EKS 集群中出现** 

如果运行 `nodeadm init`，但在运行完成后，您的混合节点未在集群中出现，则说明混合节点与 EKS 控制面板之间的网络连接可能存在问题，您可能没有配置所需的安全组权限，或者可能没有将混合节点 IAM 角色映射到 Kubernetes 基于角色的访问控制（RBAC）。您可以使用以下命令检查 `kubelet` 和 `kubelet` 日志的状态，从而启动调试进程。从加入集群失败的混合节点上运行以下命令。

```
systemctl status kubelet
```

```
journalctl -u kubelet -f
```

 **无法与集群通信** 

如果混合节点无法与集群控制面板通信，则可能会看到与以下类似的日志。

```
"Failed to ensure lease exists, will retry" err="Get ..."
```

```
"Unable to register node with API server" err="Post ..."
```

```
Failed to contact API server when waiting for CSINode publishing ... dial tcp <ip address>: i/o timeout
```

如果您看到此类消息，请检查以下内容以确保其符合[准备混合节点的联网](hybrid-nodes-networking.md)中详述的混合节点要求。
+ 确认传递给 EKS 集群的 VPC 具有指向本地节点以及（可选）容器组 CIDR 的中转网关（TGW）或虚拟专用网关（VGW）的路由。
+ 确认您的 EKS 集群还有一个额外的安全组，其中包含针对本地节点 CIDR 和（可选）容器组 CIDR 的入站规则。
+ 确认您的本地路由器已配置为允许进出 EKS 控制面板的流量。

 **未授权** 

如果混合节点能够与 EKS 控制面板通信但无法注册，则可能会看到与以下类似的日志。请注意，以下日志消息的主要区别在于 `Unauthorized` 错误。这表明该节点无法执行其任务，因为没有所需的权限。

```
"Failed to ensure lease exists, will retry" err="Unauthorized"
```

```
"Unable to register node with API server" err="Unauthorized"
```

```
Failed to contact API server when waiting for CSINode publishing: Unauthorized
```

如果您看到此类消息，请检查以下内容以确保其符合[准备用于混合节点的凭证](hybrid-nodes-creds.md)和[准备混合节点的集群访问权限](hybrid-nodes-cluster-prep.md)中详述的混合节点要求。
+ 确认混合节点的身份与您预期的混合节点 IAM 角色相符。这可以通过在混合节点上运行 `sudo aws sts get-caller-identity` 来完成。
+ 确认混合节点 IAM 角色具有必需的权限。
+ 确认集群中是否有混合节点 IAM 角色的 EKS 访问条目，或者确认 `aws-auth` ConfigMap 中是否有混合节点 IAM 角色的条目。如果使用 EKS 访问条目，请确认混合节点 IAM 角色的访问条目具有 `HYBRID_LINUX` 访问类型。如果使用 `aws-auth` ConfigMap，请确认您输入的混合节点 IAM 角色符合[准备混合节点的集群访问权限](hybrid-nodes-cluster-prep.md)中详述的要求和格式。

### 混合节点已在 EKS 集群中注册但显示的状态为 `Not Ready`
<a name="hybrid-nodes-troubleshooting-not-ready"></a>

如果混合节点已成功注册到您的 EKS 集群，但混合节点显示状态为 `Not Ready`，则首先要检查的是容器网络接口（CNI）状态。如果您尚未安装 CNI，则混合节点状态预期将为 `Not Ready`。一旦 CNI 安装并成功运行，节点的状态就会更新为 `Ready`。如果您尝试安装 CNI 但未成功运行，请参阅本页上的[混合节点 CNI 故障排除](#hybrid-nodes-troubleshooting-cni)。

 **证书签名请求（CSR）停滞在待处理状态** 

将混合节点连接到 EKS 集群后，如果您发现混合节点有待处理的 CSR，则表示您的混合节点不满足自动批准的要求。如果混合节点的 CSR 是由带有 `eks.amazonaws.com/compute-type: hybrid` 标签的节点创建的，并且 CSR 具有以下主体备用名称（SAN），则会自动批准和颁发混合节点的 CSR：至少有一个 DNS SAN 等于节点名称且 IP SAN 属于远程节点网络 CIDR。

 **混合配置文件已经存在** 

如果您更改了 `nodeadm` 配置并尝试使用新配置重新注册节点，则可能会看到一条错误消息，指示混合配置文件已经存在，但其内容已更改。请勿在配置更改之间运行 `nodeadm init`，而应运行 `nodeadm uninstall`，然后再运行 `nodeadm install` 和 `nodeadm init`。这样可以确保根据配置更改进行正确的清理。

```
"msg":"Command failed","error":"hybrid profile already exists at /etc/aws/hybrid/config but its contents do not align with the expected configuration"
```

 **混合节点解析私有 API 失败** 

运行 `nodeadm init` 后，如果您在 `kubelet` 日志中看到某个错误，显示由于存在 `no such host` 而无法连接到 EKS Kubernetes API 服务器，则可能需要在本地网络或主机级别更改 EKS Kubernetes API 端点的 DNS 条目。请参阅《AWS Route53 文档》**中的 [Forwarding inbound DNS queries to your VPC](https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/resolver-forwarding-inbound-queries.html)。

```
Failed to contact API server when waiting for CSINode publishing: Get ... no such host
```

 **无法在 EKS 控制台中查看混合节点** 

如果您已注册了混合节点，但无法在 EKS 控制台中查看，请检查您用于查看控制台的 IAM 主体的权限。您使用的 IAM 主体必须具有特定的最低 IAM 和 Kubernetes 权限，才能在控制台中查看资源。有关更多信息，请参阅 [在 AWS 管理控制台中查看 Kubernetes 资源](view-kubernetes-resources.md)。

## 混合节点运行故障排查
<a name="_running_hybrid_nodes_troubleshooting"></a>

如果混合节点已注册到 EKS 集群并且状态为 `Ready`，但状态很快变为 `Not Ready`，则可能存在多种导致运行不正常的问题，例如节点缺少足够的 CPU、内存或可用磁盘空间资源，或者节点与 EKS 控制面板之间的连接已断开等。您可以使用以下步骤对节点进行故障排除，如果无法解决问题，请联系 AWS Support。

从您的混合节点运行 `nodeadm debug` 以验证是否满足网络和凭证要求。有关 `nodeadm debug` 命令的更多信息，请参阅 [混合节点 `nodeadm` 参考](hybrid-nodes-nodeadm.md)。

 **获取节点状态** 

```
kubectl get nodes -o wide
```

 **检查节点条件和事件** 

```
kubectl describe node NODE_NAME
```

 **获取容器组状态** 

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

 **检查容器组状况和事件** 

```
kubectl describe pod POD_NAME
```

 **检查容器组日志** 

```
kubectl logs POD_NAME
```

 **检查 `kubectl` 日志** 

```
systemctl status kubelet
```

```
journalctl -u kubelet -f
```

 **容器组存活探针失败或 Webhook 不起作用** 

如果在混合节点上运行的应用程序、附加组件或 Webhook 未正常启动，则可能存在网络问题，阻碍了与容器组的通信。要让 EKS 控制面板连接到在混合节点上运行的 Webhook，您必须将 EKS 集群配置为远程容器组网络，并在 VPC 路由表中包含本地容器组 CIDR 的路由，以中转网关（TGW）、虚拟专用网关（VPW）或您用于将 VPC 与本地网络连接的其他网关为目标。有关混合节点联网要求的更多信息，请参阅[准备混合节点的联网](hybrid-nodes-networking.md)。此外，您还必须在本地防火墙中允许此流量，并确保您的路由器可以正确路由到您的容器组。要详细了解在混合节点上运行 Webhook 的要求，请参阅[为混合节点配置 Webhook](hybrid-nodes-webhooks.md)。

下方显示了此场景的一条常见容器组日志消息，其中 ip-address 是 Kubernetes 服务的集群 IP。

```
dial tcp <ip-address>:443: connect: no route to host
```

 **`kubectl logs` 或者 `kubectl exec` 命令不起作用（`kubelet` API 命令）** 

如果 `kubectl attach`、`kubectl cp`、`kubectl exec`、`kubectl logs` 和 `kubectl port-forward` 命令超时，而其他 `kubectl` 命令能够成功运行，则问题可能与远程网络配置有关。这些命令通过集群连接到节点上的 `kubelet` 端点。有关更多信息，请参阅 [`kubelet` 端点](hybrid-nodes-concepts-kubernetes.md#hybrid-nodes-concepts-k8s-kubelet-api)。

确认节点 IP 和容器组 IP 位于为集群配置的远程节点网络和远程容器组网络 CIDR 范围内。使用以下命令检查 IP 分配。

```
kubectl get nodes -o wide
```

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

将这些 IP 与您配置的远程网络 CIDR 进行比较，确保路由正确。有关网络配置要求，请参阅[准备混合节点的联网](hybrid-nodes-networking.md)。

## 混合节点 CNI 故障排除
<a name="hybrid-nodes-troubleshooting-cni"></a>

如果您在首次使用混合节点启动 Cilium 或 Calico 时遇到问题，则通常是由于混合节点或在混合节点上运行的 CNI 容器组与 EKS 控制面板之间的网络问题所致。确保您的环境符合“准备混合节点的联网”中的要求。将问题分解成若干部分会非常实用。

EKS 集群配置  
RemoteNodeNetwork 和 RemotePodNetwork 的配置是否正确？

VPC 配置  
VPC 路由表中是否有 RemoteNodeNetwork 和 RemotePodNetwork 的路由，并以中转网关或虚拟专用网关为目标？

安全组配置  
是否有 RemoteNodeNetwork 和 RemoteNetwork 的入站和出站规则？

本地网络  
是否存在往返于 EKS 控制面板、混合节点以及在混合节点上运行的容器组的路由和访问权限？

CNI 配置  
如果使用叠加网络，CNI 的 IP 池配置是否与使用 Webhook 时为 EKS 集群配置的 RemotePodNetwork 相匹配？

 **混合节点的状态为 `Ready`，但未安装 CNI** 

如果混合节点显示状态为 `Ready`，但您尚未在集群上安装 CNI，则说明混合节点上可能存在旧的 CNI 构件。默认情况下，当您使用 Helm 等工具卸载 Cilium 和 Calico 时，磁盘上的资源不会从物理计算机或虚拟机中移除。此外，在旧安装中，这些 CNI 的自定义资源定义（CRD）可能仍存在于集群上。有关更多信息，请参阅[为混合节点配置 CNI](hybrid-nodes-cni.md)中的 Cilium 和 Delete Calico 部分。

 **Cilium 故障排除** 

如果您在混合节点上运行 Cilium 时遇到问题，请参阅 Cilium 文档中的[故障排除步骤](https://docs.cilium.io/en/stable/operations/troubleshooting/)。以下章节介绍了在混合节点上部署 Cilium 时可能遇到的特有问题。

 **Cilium 未启动** 

如果在每个混合节点上运行的 Cilium 代理都未启动，请检查 Cilium 代理容器组的日志中是否存在错误。Cilium 代理需要连接到 EKS Kubernetes API 端点才能启动。如果此连接配置不正确，Cilium 代理将无法启动。在这种情况下，您将在 Cilium 代理容器组日志中看到与以下类似的日志消息。

```
msg="Unable to contact k8s api-server"
level=fatal msg="failed to start: Get \"https://<k8s-cluster-ip>:443/api/v1/namespaces/kube-system\": dial tcp <k8s-cluster-ip>:443: i/o timeout"
```

Cilium 代理在主机网络上运行。您的 EKS 集群必须将 Cilium 连接配置为 `RemoteNodeNetwork`。确认您的 EKS 集群还有一个额外的安全组，其中包含 `RemoteNodeNetwork` 的入站规则，您的 VPC 中有 `RemoteNodeNetwork` 的路由，并且您的本地网络配置正确，从而能够连接到 EKS 控制面板。

如果 Cilium 操作符正在运行，并且某些但不是全部 Cilium 代理正在运行，请确认您有可用的容器组 IP 可以分配给集群中的所有节点。在 Cilium 配置中使用带 `clusterPoolIPv4PodCIDRList` 的集群池 IPAM 时，您需要配置可分配的容器组 CIDR 的大小。每节点 CIDR 大小是使用 Cilium 配置中的 `clusterPoolIPv4MaskSize` 设置来配置的。有关更多信息，请参阅 Cilium 文档中的 [Expanding the cluster pool](https://docs.cilium.io/en/stable/network/concepts/ipam/cluster-pool/#expanding-the-cluster-pool)。

 **Cilium BGP 不起作用** 

如果您使用 Cilium BGP 控制面板向本地网络公开您的容器组或服务地址，则可以使用以下 Cilium CLI 命令来检查 BGP 是否在公开指向您的资源的路由。有关安装 Cilium CLI 的步骤，请参阅 Cilium 文档中的 [Install the Cilium CLI](https://docs.cilium.io/en/stable/gettingstarted/k8s-install-default/#install-the-cilium-cli)。

如果 BGP 工作正常，则应在输出中看到会话状态为 `established` 的混合节点。您可能需要联系网络团队，确定环境的本地 AS、对等连接 AS 和对等连接地址的正确值。

```
cilium bgp peers
```

```
cilium bgp routes
```

如果您使用 Cilium BGP 来公开 `LoadBalancer` 类型的服务 IP，则您的 `CiliumLoadBalancerIPPool` 和服务上必须使用相同的标签，该标签应在 `CiliumBGPAdvertisement` 的选择器中使用。下面显示了一个示例。注意，如果您使用 Cilium BGP 来公开 LoadBalancer 类型服务的 IP，则在 Cilium 代理重启期间，BGP 路由可能会中断。有关更多信息，请参阅 Cilium 文档中的 [Failure Scenarios](https://docs.cilium.io/en/latest/network/bgp-control-plane/bgp-control-plane-operation/#failure-scenarios)。

 **服务**：

```
kind: Service
apiVersion: v1
metadata:
  name: guestbook
  labels:
    app: guestbook
spec:
  ports:
  - port: 3000
    targetPort: http-server
  selector:
    app: guestbook
  type: LoadBalancer
```

 **CiliumLoadBalancerIPPool** 

```
apiVersion: cilium.io/v2alpha1
kind: CiliumLoadBalancerIPPool
metadata:
  name: guestbook-pool
  labels:
    app: guestbook
spec:
  blocks:
  - cidr: <CIDR to advertise>
  serviceSelector:
    matchExpressions:
      - { key: app, operator: In, values: [ guestbook ] }
```

 **CiliumBGPAdvertisement** 

```
apiVersion: cilium.io/v2alpha1
kind: CiliumBGPAdvertisement
metadata:
  name: bgp-advertisements-guestbook
  labels:
    advertise: bgp
spec:
  advertisements:
    - advertisementType: "Service"
      service:
        addresses:
          - ExternalIP
          - LoadBalancerIP
      selector:
        matchExpressions:
          - { key: app, operator: In, values: [ guestbook ] }
```

 **Calico 故障排除** 

如果您在混合节点上运行 Calico 时遇到问题，请参阅 Calico 文档中的[故障排除步骤](https://docs.tigera.io/calico/latest/operations/troubleshoot/)。以下章节介绍了在混合节点上部署 Calico 时可能遇到的特有问题。

下表总结了 Calico 的组件以及这些组件默认情况下是在节点网络还是在容器组网络上运行。如果将 Calico 配置为使用 NAT 来处理传出的容器组流量，则必须将本地网络配置为将流量路由到本地节点 CIDR，并且 VPC 路由表必须配置本地节点 CIDR 的路由，并将中转网关（TGW）或虚拟专用网关（VGW）作为目标。如果未将 Calico 配置为使用 NAT 来处理传出的容器组流量，则必须将本地网络配置为将流量路由到本地容器组 CIDR，并且 VPC 路由表必须配置本地容器组 CIDR 的路由，并将中转网关（TGW）或虚拟专用网关（VGW）作为目标。


| 组件 | Network | 
| --- | --- | 
|  Calico API 服务器  |  节点  | 
|  适用于 Kubernetes 的 Calico 控制器  |  Pod  | 
|  Calico 节点代理  |  节点  | 
|  Calico `typha`   |  节点  | 
|  Calico CSI 节点驱动程序  |  Pod  | 
|  Calico 操作符  |  节点  | 

 **Calico 资源在封锁的节点上调度或运行** 

默认情况下，不作为 DaemonSet 运行的 Calico 资源具有灵活的容忍度，可以将其调度到尚未准备好调度或运行容器组的封锁节点上。您可以通过更改操作符安装来包括以下内容，从而收紧对非 DaemonSet Calico 资源的容忍度。

```
installation:
  ...
  controlPlaneTolerations:
  - effect: NoExecute
    key: node.kubernetes.io/unreachable
    operator: Exists
    tolerationSeconds: 300
  - effect: NoExecute
    key: node.kubernetes.io/not-ready
    operator: Exists
    tolerationSeconds: 300
  calicoKubeControllersDeployment:
    spec:
      template:
        spec:
          tolerations:
          - effect: NoExecute
            key: node.kubernetes.io/unreachable
            operator: Exists
            tolerationSeconds: 300
          - effect: NoExecute
            key: node.kubernetes.io/not-ready
            operator: Exists
            tolerationSeconds: 300
  typhaDeployment:
    spec:
      template:
        spec:
          tolerations:
          - effect: NoExecute
            key: node.kubernetes.io/unreachable
            operator: Exists
            tolerationSeconds: 300
          - effect: NoExecute
            key: node.kubernetes.io/not-ready
            operator: Exists
            tolerationSeconds: 300
```

## 凭证故障排除
<a name="hybrid-nodes-troubleshooting-creds"></a>

对于 AWS SSM 混合激活和 AWS IAM Roles Anywhere，您都可以通过在混合节点上运行以下命令来验证混合节点上的混合节点 IAM 角色凭证配置是否正确。确认节点名称和混合节点 IAM 角色名称是否符合预期。

```
sudo aws sts get-caller-identity
```

```
{
    "UserId": "ABCDEFGHIJKLM12345678910:<node-name>",
    "Account": "<aws-account-id>",
    "Arn": "arn:aws:sts::<aws-account-id>:assumed-role/<hybrid-nodes-iam-role/<node-name>"
}
```

 ** AWSSystems Manager（SSM）故障排除** 

如果将 AWS SSM 混合激活用作混合节点凭证，请注意以下将由 `nodeadm` 在混合节点上安装的 SSM 目录和构件。有关更多信息，请参阅《AWS Systems Manager 用户指南》**中的[使用 SSM Agent](https://docs.aws.amazon.com/systems-manager/latest/userguide/ssm-agent.html)。


| 说明 | 位置 | 
| --- | --- | 
|  SSM 代理  |  Ubuntu – `/snap/amazon-ssm-agent/current/amazon-ssm-agent` RHEL 和 AL2023 – `/usr/bin/amazon-ssm-agent`   | 
|  SSM 代理日志  |   `/var/log/amazon/ssm`   | 
|   AWS 凭证  |   `/root/.aws/credentials`   | 
|  SSM 安装 CLI  |   `/opt/ssm/ssm-setup-cli`   | 

 **重新启动 SSM Agent** 

有些问题可以通过重新启动 SSM Agent 来解决。您可以使用以下命令重新启动此代理。

 **AL2023 和其他操作系统** 

```
systemctl restart amazon-ssm-agent
```

 **Ubuntu** - 

```
systemctl restart snap.amazon-ssm-agent.amazon-ssm-agent
```

 **检查与 SSM 端点的连接** 

确认您可以从混合节点连接到 SSM 端点。有关 SSM 端点列表，请参阅 [AWS Systems Manager endpoints and quotas](https://docs.aws.amazon.com/general/latest/gr/ssm.html)。对于 AWS SSM 混合激活，请将以下命令中的 `us-west-2` 替换为 AWS 区域。

```
ping ssm.us-west-2.amazonaws.com
```

 **查看已注册 SSM 实例的连接状态** 

您可以使用以下 AWS CLI 命令检查通过 SSM 混合激活注册的实例的连接状态。请将 machine ID 替换为实例的机器 ID。

```
aws ssm get-connection-status --target mi-012345678abcdefgh
```

 **SSM 安装 CLI 校验和不匹配** 

运行 `nodeadm install` 时，如果您发现 `ssm-setup-cli` 校验和不匹配问题，应确认主机上没有早期版本的现有 SSM 安装。如果您的主机上有早期版本的 SSM 安装，请将其移除并重新运行 `nodeadm install` 以解决问题。

```
Failed to perform agent-installation/on-prem registration: error while verifying installed ssm-setup-cli checksum: checksum mismatch with latest ssm-setup-cli.
```

 **SSM `InvalidActivation`** 

如果您在将实例注册到 AWS SSM 时看到错误，请确认 `nodeConfig.yaml` 中的 `region`、`activationCode` 和 `activationId` 正确无误。EKS 集群的 AWS 区域必须与 SSM 混合激活区域一致。如果这些值的配置错误，则可能会看到与以下类似的错误。

```
ERROR Registration failed due to error registering the instance with AWS SSM. InvalidActivation
```

 **SSM `ExpiredTokenException`：请求中包含的安全令牌已过期** 

如果 SSM Agent 无法刷新凭证，您可能会看到 `ExpiredTokenException`。在这种情况下，如果能够从混合节点连接到 SSM 端点，则可能需要重新启动 SSM Agent 以强制刷新凭证。

```
"msg":"Command failed","error":"operation error SSM: DescribeInstanceInformation, https response error StatusCode: 400, RequestID: eee03a9e-f7cc-470a-9647-73d47e4cf0be, api error ExpiredTokenException: The security token included in the request is expired"
```

 **运行注册计算机命令时出现 SSM 错误** 

如果在将计算机注册到 SSM 时看到错误，则可能需要重新运行 `nodeadm install` 以确保正确安装所有 SSM 依赖项。

```
"error":"running register machine command: , error: fork/exec /opt/aws/ssm-setup-cli: no such file or directory"
```

 **SSM `ActivationExpired`** 

运行 `nodeadm init` 时，如果在将实例注册到 SSM 时因激活已过期而出现错误，则需要创建新的 SSM 混合激活，使用新 SSM 混合激活的 `activationCode` 和 `activationId` 更新 `nodeConfig.yaml`，然后重新运行 `nodeadm init`。

```
"msg":"Command failed","error":"SSM activation expired. Please use a valid activation"
```

```
ERROR Registration failed due to error registering the instance with AWS SSM. ActivationExpired
```

 **SSM 刷新缓存的凭证失败** 

如果发现无法刷新缓存的凭证，则说明 `/root/.aws/credentials` 文件可能已从主机中删除。首先检查您的 SSM 混合激活并确保其处于活动状态，并且混合节点已正确配置为使用该激活。检查 `/var/log/amazon/ssm` 中的 SSM Agent 日志，并在解决 SSM 端的问题后重新运行 `nodeadm init` 命令。

```
"Command failed","error":"operation error SSM: DescribeInstanceInformation, get identity: get credentials: failed to refresh cached credentials"
```

 **清理 SSM** 

要从主机上移除 SSM Agent，可以运行以下命令。

```
dnf remove -y amazon-ssm-agent
sudo apt remove --purge amazon-ssm-agent
snap remove amazon-ssm-agent
rm -rf /var/lib/amazon/ssm/Vault/Store/RegistrationKey
```

 ** AWSIAM Roles Anywhere 故障排除** 

如果将 AWS IAM Roles Anywhere 用作混合节点凭证，请注意将由 `nodeadm` 在混合节点上安装的以下目录和构件。有关 IAM Roles Anywhere 故障排除的更多信息，请参阅《AWS IAM Roles Anywhere 用户指南》**中的 [Troubleshooting AWS IAM Roles Anywhere identity and access](https://docs.aws.amazon.com/rolesanywhere/latest/userguide/security_iam_troubleshoot.html)。


| 说明 | 位置 | 
| --- | --- | 
|  IAM Roles Anywhere CLI  |   `/usr/local/bin/aws_signing_helper`   | 
|  默认证书位置和名称  |   `/etc/iam/pki/server.pem`   | 
|  默认密钥位置和名称  |   `/etc/iam/pki/server.key`   | 

 **IAM Roles Anywhere 刷新缓存的证书失败** 

如果您发现刷新缓存的证书失败，请检查 `/etc/aws/hybrid/config` 的内容并确认 `nodeadm` 配置中正确配置了 IAM Roles Anywhere。确认 `/etc/iam/pki` 存在。每个节点都必须具有唯一的证书和密钥。默认情况下，凭证提供者为 IAM Roles Anywhere 作时，`nodeadm` 将 `/etc/iam/pki/server.pem` 作为证书位置和名称，并将 `/etc/iam/pki/server.key` 作为私有密钥。在将证书和密钥放入目录之前，您可能需要首先使用 `sudo mkdir -p /etc/iam/pki` 创建目录。您可以使用以下命令验证证书的内容。

```
openssl x509 -text -noout -in server.pem
```

```
open /etc/iam/pki/server.pem: no such file or directory
could not parse PEM data
Command failed {"error": "... get identity: get credentials: failed to refresh cached credentials, process provider error: error in credential_process: exit status 1"}
```

 **IAM Roles Anywhere 无权执行 `sts:AssumeRole`** 

在 `kubelet` 日志中，如果您在使用 IAM Roles Anywhere 时看到 `sts:AssumeRole` 操作出现访问被拒绝的问题，请检查混合节点 IAM 角色的信任策略，以确认允许 IAM Roles Anywhere 服务主体代入该混合节点 IAM 角色。此外，请确认在混合节点 IAM 角色信任策略中正确配置了信任锚 ARN，并且已将混合节点 IAM 角色添加到 IAM Roles Anywhere 配置文件中。

```
could not get token: AccessDenied: User: ... is not authorized to perform: sts:AssumeRole on resource: ...
```

 **IAM Roles Anywhere 无权设置 `roleSessionName`** 

在 `kubelet` 日志中，如果您发现设置 `roleSessionName` 时出现访问被拒绝的问题，请确认您已将 IAM Roles Anywhere 配置文件的 `acceptRoleSessionName` 设置为 true。

```
AccessDeniedException: Not authorized to set roleSessionName
```

## 操作系统故障排除
<a name="hybrid-nodes-troubleshooting-os"></a>

### RHEL
<a name="_rhel"></a>

 **授权或订阅管理器注册失败** 

如果您运行的是 `nodeadm install`，但由于授权注册问题而无法安装混合节点依赖项，请确保在主机上正确设置了 Red Hat 用户名和密码。

```
This system is not registered with an entitlement server
```

### Ubuntu
<a name="_ubuntu"></a>

 **找不到 GLIBC** 

如果您的操作系统为 Ubuntu 操作系统，混合节点的凭证提供者为 IAM Roles Anywhere，但出现找不到 GLIBC 的问题，则可以通过手动安装该依赖项来解决问题。

```
GLIBC_2.32 not found (required by /usr/local/bin/aws_signing_helper)
```

运行以下命令安装依赖项：

```
ldd --version
sudo apt update && apt install libc6
sudo apt install glibc-source
```

### Bottlerocket
<a name="_bottlerocket"></a>

如果启用了 Bottlerocket 管理容器，则可以使用 SSH 访问该容器，从而使用更高的权限进行高级调试和故障排除。以下章节包含需要在 Bottlerocket 主机的上下文中运行的命令。进入管理容器后，您可以运行 `sheltie` 来获取 Bottlerocket 主机中的完整根 Shell。

```
sheltie
```

此外还可以通过在各个命令前加上前缀 `sudo chroot /.bottlerocket/rootfs`，从而在管理容器 Shell 中运行以下章节中的命令。

```
sudo chroot /.bottlerocket/rootfs <command>
```

 **使用 logdog 收集日志** 

Bottlerocket 提供了 `logdog` 实用程序，可用来高效地收集日志和系统信息，以满足故障排除的需要。

```
logdog
```

`logdog` 实用程序可从 Bottlerocket 主机的不同位置收集日志，然后组合成压缩包。默认情况下，该压缩包将在 `/var/log/support/bottlerocket-logs.tar.gz` 位置创建，并且可以从主机容器的 `/.bottlerocket/support/bottlerocket-logs.tar.gz` 位置访问。

 **使用 journalctl 访问系统日志** 

您可以使用以下命令检查各种系统服务（例如 `kubelet`、`containerd` 等）的状态以及查看其日志。`-f` 标志会实时跟踪日志。

要检查 `kubelet` 服务状态和检索 `kubelet` 日志，您可以运行以下命令：

```
systemctl status kubelet
journalctl -u kubelet -f
```

要检查 `containerd` 服务状态和检索已编排的 `containerd` 实例的日志，您可以运行以下命令：

```
systemctl status containerd
journalctl -u containerd -f
```

要检查 `host-containerd` 服务状态和检索主机 `containerd` 实例的日志，您可以运行以下命令：

```
systemctl status host-containerd
journalctl -u host-containerd -f
```

要检索引导容器和主机容器的日志，您可以运行以下命令：

```
journalctl _COMM=host-ctr -f
```