

 **帮助改进此页面** 

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

# 混合节点的概念
<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）的特定节点。