

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

# 混合部署的最佳实践
<a name="hybrid"></a>

本指南提供了有关使用 EKS 混合节点或 EKS Anywhere 在本地或边缘环境中运行部署的指导。

我们目前已经发布了以下主题的指南：
+  [EKS 混合节点和网络断开的最佳实践](hybrid-nodes-network-disconnections.md) 

# EKS 混合节点和网络断开连接
<a name="hybrid-nodes-network-disconnections"></a>

对于习惯于完全在自己的数据中心或边缘位置运行本地 Kubernetes 集群的客户来说，EKS Hybrid Nodes 架构可能是全新的架构。使用 EKS 混合节点，Kubernetes 控制平面在 AWS 区域中运行，并且只有节点在本地运行，从而形成 “延伸” 或 “扩展” 的 Kubernetes 集群架构。

这就引出了一个常见的问题：“如果我的节点与 Kubernetes 控制平面断开连接会发生什么？”

在本指南中，我们通过回顾以下主题来回答这个问题。建议通过断开网络来验证应用程序的稳定性和可靠性，因为每个应用程序的行为可能因其依赖关系、配置和环境而有所不同。有关测试设置、程序和结果，请参阅 aws-sam eks-hybrid-examples GitHub ples/ 存储库，您可以参考这些测试与 EKS 混合节点和您自己的应用程序的网络断开连接。该 GitHub 存储库还包含用于验证本指南中所述行为的测试的更多详细信息。
+  [通过网络断开连接实现稳定性的最佳实践](hybrid-nodes-network-disconnection-best-practices.md) 
+  [通过网络断开连接实现的 Kubernetes 容器故障转移行为](hybrid-nodes-kubernetes-pod-failover.md) 
+  [通过网络断开连接产生的应用程序网络流量](hybrid-nodes-app-network-traffic.md) 
+  [通过网络断开连接获得的主机凭证](hybrid-nodes-host-creds.md) 

# 通过网络断开连接实现稳定性的最佳实践
<a name="hybrid-nodes-network-disconnection-best-practices"></a>

## 高度可用的网络
<a name="_highly_available_networking"></a>

避免混合节点和 Kubernetes 控制平面之间网络断开的最佳方法是使用本地环境与 AWS 之间的冗余弹性连接。有关使用这些解决方案构建高可用性混合网络的更多信息，请参阅 [AWS Di [rect Connect Connect 弹性工具包](https://docs.aws.amazon.com/directconnect/latest/UserGuide/resiliency_toolkit.html)和 AWS Site-to-Site VPN 文档](https://docs.aws.amazon.com/vpn/latest/s2svpn/vpn-redundant-connection.html)。

## 高可用性应用程序
<a name="_highly_available_applications"></a>

在设计应用程序时，请考虑您的故障域以及不同类型的中断的影响。Kubernetes 提供了跨节点、区域和区域域部署和维护应用程序副本的内置机制。这些机制的使用取决于您的应用程序架构、环境和可用性要求。例如，无状态应用程序通常可以部署多个副本，并且可以在任意主机和基础架构容量之间移动，并且您可以使用节点选择器和拓扑分布限制在不同的域中运行应用程序的实例。[有关在 Kubernetes 上构建弹性应用程序的应用程序级技术的详细信息，请参阅 EKS 最佳实践指南。](https://aws.github.io/aws-eks-best-practices/reliability/docs/application/)

在确定是否将 Pod 移至其他节点时，Kubernetes 会评估与 Kubernetes 控制平面断开连接的节点的区域信息。如果一个区域中的所有节点都无法访问，Kubernetes 将取消该区域中节点的容器驱逐。作为最佳实践，如果您的部署中有节点在多个数据中心或物理位置运行，请根据每个节点的数据中心或物理位置为其分配一个区域。当您在云中的节点上运行 EKS 时，AWS 会自动应用此区域标签 cloud-controller-manager。但是，混合节点 cloud-controller-manager不使用 a，因此您可以通过 kubelet 配置传递这些信息。下面显示了如何在混合节点的节点配置中配置区域的示例。当您使用混合节点 CLI (`nodeadm`) 将混合节点连接到集群时，配置即被传递。有关`topology.kubernetes.io/zone`标签的更多信息，请参阅 [Kubernetes 文档](https://kubernetes.io/docs/reference/labels-annotations-taints/#topologykubernetesiozone)。有关混合节点 CLI 的更多信息，请参阅混合节[点 nodeadm](https://docs.aws.amazon.com/eks/latest/userguide/hybrid-nodes-nodeadm.html) 参考。

```
apiVersion: node.eks.aws/v1alpha1
kind: NodeConfig
spec:
  cluster:
    name: my-cluster
    region: my-region
  kubelet:
    flags:
       - --node-labels=topology.kubernetes.io/zone=dc1
  hybrid:
    ...
```

## 网络监测
<a name="_network_monitoring"></a>

如果您使用 AWS Direct Connect 或 AWS Site-to-Site VPN 进行混合连接，则可以利用 CloudWatch 警报、日志和指标来观察混合连接的状态并诊断问题。有关更多信息，请参阅[监控 AWS Direct Connect 资源](https://docs.aws.amazon.com/directconnect/latest/UserGuide/monitoring-overview.html)和[监控 AWS Site-to-Site VPN 连接](https://docs.aws.amazon.com/vpn/latest/s2svpn/monitoring-overview-vpn.html)。

建议为在 EKS 控制平面上 node-lifecycle-controller运行时报告`NodeNotReady`的事件创建警报，这些事件表示混合节点可能出现网络断开的情况。您可以通过以下方式创建此警报：为控制器管理器启用 EKS 控制平面日志记录，然后在 CloudWatch status= “” 中为 “记录节点的状态更改事件消息” 消息创建指标过滤器。NodeNotReady创建指标筛选器后，您可以根据所需的阈值为此过滤器创建警报。有关更多信息，请参阅[ CloudWatch 文档中的日志警报](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/Alarm-On-Logs.html)。

您可以使用 Transit Gateway (TGW) 和虚拟专用网关 (VGW) 的内置指标来观察进出您的 TGW 或 VGW 的网络流量。您可以为这些指标创建警报，以检测网络流量降至正常水平以下的情况，这表明混合节点和 EKS 控制平面之间存在潜在的网络问题。下表描述了 TGW 和 VGW 指标。


| 网关 | 指标 | 说明 | 
| --- | --- | --- | 
|  Transit Gateway  |  BytesIn  |  TGW 从附件（EKS 控制平面到混合节点）接收的字节  | 
|  Transit Gateway  |  BytesOut  |  从 TGW 发送到附件（混合节点到 EKS 控制平面）的字节  | 
|  虚拟专用网关  |  TunnelDataIn  |  从 AWS 端通过 VPN 隧道发送到客户网关（EKS 控制平面到混合节点）的字节  | 
|  虚拟专用网关  |  TunnelDataOut  |  通过 VPN 隧道从客户网关（到 EKS 控制平面的混合节点）在连接的 AWS 端接收的字节  | 

您还可以使用 [CloudWatch Network Monit](https://aws.amazon.com/blogs/networking-and-content-delivery/monitor-hybrid-connectivity-with-amazon-cloudwatch-network-monitor/) or 更深入地了解您的混合连接，从而缩短平均恢复时间，并确定网络问题是源于 AWS 还是您的环境。 CloudWatch Network Monitor 可用于可视化混合网络连接中的数据包丢失和延迟，设置警报和阈值，然后采取措施提高网络性能。有关更多信息，请参阅[使用 Amazon CloudWatch 网络监视器](https://docs.aws.amazon.com/AmazonCloudWatch/latest/monitoring/what-is-network-monitor.html)。

EKS 提供了多种用于监控集群和应用程序运行状况的选项。对于集群运行状况，您可以使用 EKS 控制台中的可观察性控制面板来快速检测、故障排除和修复问题。您还可以使用适用于 Prometheus 的亚马逊托管服务、用于开放遥测 (ADOT) 的 AWS Distro 以及集群 CloudWatch 、应用程序和基础设施监控。有关 EKS 可观察性选项的更多信息，请参阅[监控集群性能和查看日志](https://docs.aws.amazon.com/eks/latest/userguide/eks-observe.html)。

## 本地故障排除
<a name="_local_troubleshooting"></a>

要为混合节点和 EKS 控制平面之间的网络断开做好准备，您可以设置辅助监控和日志后端，以便在无法访问区域 AWS 服务时保持应用程序的可观察性。例如，您可以将 AWS Distro 开放遥测版 (ADOT) 收集器配置为向多个后端发送指标和日志。您还可以使用本地工具（例如 `crictl` CLI）与 Pod 和容器进行本地交互，以替代通常查询 Kubernetes API 服务器端点的其他 Kubernetes API 兼容客户端。`kubectl`有关的更多信息`crictl`，请参阅 cri- GitHub t [`crictl`ools 中的文档](https://github.com/kubernetes-sigs/cri-tools/blob/master/docs/crictl.md)。下面列出了一些有用的`crictl`命令。

列出主机上运行的 pod：

```
crictl pods
```

列出主机上运行的容器：

```
crictl ps
```

列出主机上运行的映像：

```
crictl images
```

获取主机上运行的容器的日志：

```
crictl logs CONTAINER_NAME
```

获取主机上运行的 Pod 的统计信息：

```
crictl statsp
```

## 应用程序网络流量
<a name="_application_network_traffic"></a>

使用混合节点时，重要的是要考虑和了解应用程序流量的网络流量，以及用于向集群外部公开应用程序的技术。在网络断开连接期间，不同的应用程序负载平衡和入口技术的行为会有所不同。例如，如果您使用 Cilium 的 BGP 控制平面功能进行应用程序负载平衡，则在网络断开连接期间，Pod 和服务的 BGP 会话可能会关闭。之所以发生这种情况，是因为 BGP 扬声器功能与 Cilium 代理集成在一起，而且 Cilium 代理在与 Kubernetes 控制平面断开连接时将持续重启。重启的原因是Cilium的运行状况检查失败，因为它的生命值与对Kubernetes控制平面的访问权限相结合（参见 [CFP: \$131702，C](https://github.com/cilium/cilium/issues/31702) ilium v1.17 中有选择加入的改进）。同样，如果您使用应用程序负载均衡器 (ALB) 或网络负载均衡器 (NLB) 来处理源自 AWS 区域的应用程序流量，则如果您的本地环境与 AWS 区域断开连接，则该流量可能会暂时中断。建议在部署到生产环境之前，验证用于负载平衡和入口的技术在网络断开连接期间是否保持稳定。[aws-samples/ eks-hybrid-examples](https://github.com/aws-samples/eks-hybrid-examples) GitHub 存储库中的示例使用 MetalLB 在 [L2 模式下](https://metallb.universe.tf/concepts/layer2/)进行负载平衡，在混合节点和 EKS 控制平面之间的网络断开连接期间，负载平衡保持稳定。

## 查看对远程 AWS 服务的依赖关系
<a name="_review_dependencies_on_remote_aws_services"></a>

使用混合节点时，请注意您对本地或边缘环境外部的区域 AWS 服务的依赖性。示例包括访问 Amazon S3 或 Amazon RDS 获取应用程序数据、使用适用于 Prometheus 的亚马逊托管服务 CloudWatch 或指标和日志、使用应用程序和网络负载均衡器处理源自区域的流量，以及从 Amazon 弹性容器注册表中提取容器。在您的本地环境与 AWS 之间断开网络连接期间，将无法访问这些服务。如果您的本地环境容易与 AWS 断开网络连接，请检查您对 AWS 服务的使用情况，并确保与这些服务的连接中断不会影响应用程序的静态稳定性。

## 调整 Kubernetes 容器故障转移行为
<a name="_tune_kubernetes_pod_failover_behavior"></a>

对于无法跨主机移植的应用程序，或者没有备用容量进行容器故障转移的资源受限的环境，可以选择在网络断开连接期间调整容器故障转移行为。通常，重要的是要考虑应用程序的资源需求，并有足够的容量让一个或多个应用程序实例在节点出现故障时故障转移到另一台主机。
+  选项 1-使用 DaemonSets：此选项适用于可以而且应该在集群中的所有节点上运行的应用程序。 DaemonSets 会自动配置为容忍无法访问的污点，这会通过网络断开连接使 DaemonSet Pod 与其节点绑定。
+  选项 2-调整无法访问`tolerationSeconds`的污点：您可以调整网络断开连接期间 Pod 与节点绑定的时间。为此，请将应用程序 pod 配置为在您指定的持续时间（在应用程序`NoExecute`规范`tolerationSeconds`中）内容忍无法达到的污点。使用此选项，当网络断开连接时，您的应用程序 Pod 将一直绑定到节点，直到`tolerationSeconds`到期。请仔细考虑这一点，因为增加无法访问`tolerationSeconds`的污点`NoExecute`意味着在无法访问的主机上运行的 Pod 可能需要更长的时间才能移动到其他可访问、运行良好的主机。
+  选项 3：自定义控制器：你可以创建并运行一个自定义控制器（或其他软件），用于监控 Kubernetes 中是否有无法触及的污点。`NoExecute`当检测到这种污点时，自定义控制器可以检查应用程序特定的指标以评估应用程序的运行状况。如果应用程序运行正常，则自定义控制器可以移除无法访问的污点，从而防止在网络断开连接期间将 Pod 从节点中驱逐。

下面显示了如何`tolerationSeconds`为无法到达的污点配置部署的示例。在示例中，设置`tolerationSeconds`为`1800`（30 分钟），这意味着只有在网络断开连接持续时间超过 30 分钟时，在无法访问的节点上运行的 Pod 才会被驱逐出去。

```
apiVersion: apps/v1
kind: Deployment
metadata:
...
spec:
...
      tolerations:
      - key: "node.kubernetes.io/unreachable"
        operator: "Exists"
        effect: "NoExecute"
        tolerationSeconds: 1800
```

# 通过网络断开连接实现的 Kubernetes 容器故障转移
<a name="hybrid-nodes-kubernetes-pod-failover"></a>

我们首先回顾一下在节点与 Kubernetes 控制平面之间网络断开连接期间影响 Kubernetes 行为的关键概念、组件和设置。EKS 符合上游 Kubernetes 标准，因此此处描述的所有 Kubernetes 概念、组件和设置都适用于 EKS 和 EKS 混合节点部署。

对 EKS 进行了一些改进，专门用于改善网络断开连接期间的 pod 故障转移行为，有关更多信息，请参阅上游 Kubernetes 存储库中的 GitHub 问题 [\$1131294](https://github.com/kubernetes/kubernetes/pull/131294) 和 [\$1131481](https://github.com/kubernetes/kubernetes/issues/131481)。

## 概念
<a name="_concepts"></a>

 污点和容忍度：Kubernetes 中使用污点和容忍度来控制 Pod 在节点上的调度。由设置污点 node-lifecycle-controller以表示节点不符合调度条件或应驱逐这些节点上的 Pod。当由于网络断开连接而无法访问节点时，将 node-lifecycle-controller应用 node.kubernetes。 io/unreachable taint with a NoSchedule effect, and with a NoExecute effect if certain conditions are met. The node.kubernetes.io/unreachable污点对应于 NodeCondition Ready being Unknown。用户可以在中指定应用程序级别对污点的容忍度。 PodSpec
+ NoSchedule: 除非有匹配的容忍度，否则不会在受污染的节点上调度新 Pod。已在节点上运行的 Pod 不会被驱逐。
+ NoExecute: 不容忍污点的 Pod 会立即被驱逐出境。容忍污点（未指定 TolerationSeconds）的 Pod 将永远保持绑定。容忍具有指定 TolerationSeconds 污点的 Pod 将在指定的时间内保持绑定。在这段时间过后，节点生命周期控制器会将 Pod 逐出节点。

 节点租约：Kubernetes 使用 Lease API 将 kubelet 节点心跳传送到 Kubernetes API 服务器。对于每个节点，都有一个名称匹配的 Lease 对象。在内部，每个 kubelet 心跳都会更新 Lease 对象的 spec.renewTime 字段。Kubernetes 控制平面使用该字段的时间戳来确定节点的可用性。如果节点与 Kubernetes 控制平面断开连接，则它们无法为其租约更新 spec.renewTime，控制平面会将其解释为 Ready being Unknown。 NodeCondition 

## 组件
<a name="_components"></a>

![\[容器故障转移行为中涉及的 Kubernetes 组件\]](http://docs.aws.amazon.com/zh_cn/eks/latest/best-practices/images/hybrid/k8s-components-pod-failover.png)



| 组件 | 子组件 | 说明 | 
| --- | --- | --- | 
|  Kubernetes 控制平面  |  kube-api-server  |  API 服务器是 Kubernetes 控制平面的核心组件，用于公开 Kubernetes API。  | 
|  Kubernetes 控制平面  |  node-lifecycle-controller  |   kube-controller-manager运行的控制器之一。它负责检测和响应节点问题。  | 
|  Kubernetes 控制平面  |  kube-scheduler  |  一个控制平面组件，用于监视未分配节点的新创建的 Pod，并选择一个节点让它们运行。  | 
|  Kubernetes 节点  |  kubelet  |  在群集中的每个节点上运行的代理。kubelet 会监视 PodSpecs 并确保其中描述的容 PodSpecs 器运行良好。  | 

## 配置设置
<a name="_configuration_settings"></a>


| 组件 | 设置 | 说明 | K8s 默认 | EKS 默认 | 可在 EKS 中配置 | 
| --- | --- | --- | --- | --- | --- | 
|  kube-api-server  |  default-unreachable-toleration-seconds  |  表示`tolerationSeconds`默认情况下，每个还没有`unreachable:NoExecute`这种容忍度的 pod 都会添加该容忍度。  |  300  |  300  |  否  | 
|  node-lifecycle-controller  |  node-monitor-grace-period  |  节点在被标记为不健康之前可能没有响应的时间。必须是 kubelet 的 N 倍`nodeStatusUpdateFrequency`，其中 N 是 kubelet 发布节点状态时允许的重试次数。  |  40  |  40  |  否  | 
|  node-lifecycle-controller  |  large-cluster-size-threshold  |  在驱逐逻辑中，将集群 node-lifecycle-controller视为大型集群的节点数。 `--secondary-node-eviction-rate`对于这种大小或更小的群集，则重写为 0。  |  50  |  100000  |  否  | 
|  node-lifecycle-controller  |  unhealthy-zone-threshold  |  区域中必须处于 “未就绪” 状态才能将该区域视为不健康的节点的百分比。  |  55%  |  55%  |  否  | 
|  kubelet  |  node-status-update-frequency  |  kubelet 向控制平面发布节点状态的频率。必须与 `nodeMonitorGracePeriod` in 兼容 node-lifecycle-controller。  |  10  |  10  |  是  | 
|  kubelet  |  节点标签  |  在集群中注册节点时要添加的标签。`topology.kubernetes.io/zone`可以为混合节点指定标签，以将节点分组为多个区域。  |  无  |  无  |  是  | 

## 通过网络断开连接实现的 Kubernetes 容器故障转移
<a name="_kubernetes_pod_failover_through_network_disconnections"></a>

此处描述的行为假设 Pod 以默认设置的 Kubernetes 部署形式运行，并且 EKS 被用作 Kubernetes 提供者。根据您的环境、网络断开连接的类型、应用程序、依赖关系和群集配置，实际行为可能会有所不同。本指南中的内容已使用特定的应用程序、集群配置和插件子集进行了验证。强烈建议在进入生产环境之前，在自己的环境和自己的应用程序中测试行为。

当节点和 Kubernetes 控制平面之间出现网络断开连接时，每个断开连接的节点上的 kubelet 将无法与 Kubernetes 控制平面通信。因此，在恢复连接之前，kubelet 无法驱逐这些节点上的 pod。这意味着，假设没有其他故障导致它们关闭，则在网络断开连接之前在这些节点上运行的 Pod 将在断开连接期间继续运行。总而言之，在节点与 Kubernetes 控制平面之间的网络断开连接期间，你可以实现静态稳定性，但是在恢复连接之前，你无法对节点或工作负载执行变更操作。

根据网络断开的性质，有五种主要场景会产生不同的 pod 故障转移行为。在所有情况下，一旦节点重新连接到 Kubernetes 控制平面，集群就会恢复健康，无需操作员干预。以下场景概述了基于我们的观察结果的预期结果，但这些结果可能不适用于所有可能的应用程序和集群配置。

### 场景 1：集群完全中断
<a name="_scenario_1_full_cluster_disruption"></a>

 **预期结果**：无法访问的节点上的 Pod 不会被驱逐并继续在这些节点上运行。

集群完全中断意味着集群中的所有节点都与 Kubernetes 控制平面断开连接。在这种情况下，控制平面 node-lifecycle-controller上的 pod 检测到集群中的所有节点都无法访问并取消任何 Pod 驱逐。

在断开连接`Not Ready`期间，集群管理员将看到所有带有状态的节点。Pod 状态不会改变，在断开连接和后续重新连接期间，也不会在任何节点上调度新的 Pod。

### 场景 2：整个区域中断
<a name="_scenario_2_full_zone_disruption"></a>

 **预期结果**：无法访问的节点上的 Pod 不会被驱逐并继续在这些节点上运行。

整个区域中断意味着该区域中的所有节点都与 Kubernetes 控制平面断开连接。在这种情况下，控制平面 node-lifecycle-controller上的 pod 检测到该区域中的所有节点都无法访问并取消任何 Pod 驱逐。

在断开连接`Not Ready`期间，集群管理员将看到所有带有状态的节点。Pod 状态不会改变，在断开连接和后续重新连接期间，也不会在任何节点上调度新的 Pod。

### 场景 3：多数区域中断
<a name="_scenario_3_majority_zone_disruption"></a>

 **预期结果**：无法访问的节点上的 Pod 不会被驱逐并继续在这些节点上运行。

多数区域中断意味着给定区域中的大多数节点都与 Kubernetes 控制平面断开连接。Kubernetes 中的区域由具有相同标签的节点定义。`topology.kubernetes.io/zone`如果集群中未定义任何区域，则大多数中断意味着整个集群中的大多数节点都已断开连接。默认情况下，多数由 node-lifecycle-controller 's定义`unhealthy-zone-threshold`，在Kubernetes和EKS中均设置为55％。由于在 EKS 中设置`large-cluster-size-threshold`为 100,000，因此如果一个区域中 55% 或更多的节点无法访问，则吊舱驱逐将被取消（假设大多数集群远小于 100,000 个节点）。

在断开连接`Not Ready`期间，集群管理员将看到区域中的大多数节点都处于状态状态，但是 Pod 的状态不会改变，也不会在其他节点上重新调度。

请注意，上述行为仅适用于大于三个节点的集群。在三个或更少节点的集群中，无法访问的节点上的 Pod 会被安排驱逐，而新 Pod 则被调度到健康的节点上。

在测试过程中，我们偶尔会观察到，在网络断开连接期间，Pod 会被逐出一个无法访问的节点，即使该区域的大多数节点都无法访问也是如此。我们仍在调查 Kubernetes 中可能存在的竞争条件 node-lifecycle-controller作为这种行为的原因。

### 情景 4：少数族裔区域中断
<a name="_scenario_4_minority_zone_disruption"></a>

 **预期结果**：Pod 被从无法访问的节点中逐出，而新 Pod 被调度到可用的符合条件的节点上。

少量中断意味着区域中与 Kubernetes 控制平面断开连接的节点比例较小。如果集群中未定义任何区域，则少数中断意味着整个集群中的少数节点已断开连接。如前所述，少数群体由的`unhealthy-zone-threshold`设置来定义 node-lifecycle-controller，默认情况下为 55%。在这种情况下，如果网络断开的持续时间超过`default-unreachable-toleration-seconds`（5 分钟）和`node-monitor-grace-period`（40 秒），并且一个区域中只有不到 55% 的节点无法访问，则新 Pod 将调度到健康的节点上，而无法访问的节点上的 Pod 则被标记为驱逐。

集群管理员将看到在运行正常的节点上创建的新 Pod，断开连接的节点上的 pod 将显示为`Terminating`。请记住，尽管断开连接的节点上的 Pod 具有`Terminating`状态，但在节点重新连接到 Kubernetes 控制平面之前，它们不会被完全驱逐出去。

## 场景 5：网络中断期间节点重启
<a name="_scenario_5_node_restart_during_network_disruption"></a>

 **预期结果**：无法访问的节点上的 Pod 要等到节点重新连接到 Kubernetes 控制平面后才会启动。Pod 故障转移遵循场景 1-3 中描述的逻辑，具体取决于无法访问的节点的数量。

在网络中断期间重启节点意味着在网络断开连接的同时，节点上发生了另一次故障（例如电源循环、 out-of-memory事件或其他问题）。如果 kubelet 也已重新启动，则网络断开连接开始时在该节点上运行的 Pod 不会在断开连接期间自动重启。kubelet 在启动时会查询 Kubernetes API 服务器，以了解它应该运行哪些 pod。如果 kubelet 由于网络断开连接而无法访问 API 服务器，则无法检索启动 pod 所需的信息。

在这种情况下，不能使用本地故障排除工具（例如 `crictl` CLI）来手动启动 pod，这是 “漏洞” 措施。Kubernetes 通常会移除失败的 pod 并创建新的 pod，而不是重启现有 pod（详情参见 containerd 存储库[中的](https://github.com/containerd/containerd/pull/10213) \$110213）。 GitHub 静态容器是唯一由 kubelet 控制的 Kubernetes 工作负载对象，可以在这些场景中重启。但是，通常不建议使用静态 pod 进行应用程序部署。相反，应在不同的主机上部署多个副本，以确保在出现多个同时发生故障（例如节点故障以及节点与 Kubernetes 控制平面之间的网络断开连接）时应用程序的可用性。

# 通过网络断开连接产生的应用程序网络流量
<a name="hybrid-nodes-app-network-traffic"></a>

本页上的主题与 Kubernetes 集群网络以及节点与 Kubernetes 控制平面之间网络断开连接期间的应用程序流量有关。

## Cilium
<a name="_cilium"></a>

Cilium 有多种模式用于 IP 地址管理 (IPAM)、封装、负载平衡和集群路由。本指南中验证的模式使用了集群范围 IPAM、VXLAN 叠加、BGP 负载平衡和 kube-proxy。Cilium 也在没有 BGP 负载平衡的情况下使用，取而代之的是 MetalL L2 负载平衡。

Cilium 安装的基础由 Cilium 操作员和 Cilium 代理组成。[Cilium 运算符作为部署运行，注册 Cilium 自定义资源定义 (CRDs)、管理 IPAM 以及将集群对象与 Kubernetes API 服务器同步以及其他功能。](https://docs.cilium.io/en/stable/internals/cilium_operator/)Cilium 代理作为在每个节点上运行， DaemonSet 并管理 eBPF 程序，以控制集群上运行的工作负载的网络规则。

通常，在网络断开连接期间，Cilium 配置的集群内路由保持可用和原位，这可以通过观察集群内流量和 pod 网络的 IP 表 (iptables) 规则来确认。

```
ip route show table all | grep cilium
```

```
10.86.2.0/26 via 10.86.3.16 dev cilium_host proto kernel src 10.86.3.16 mtu 1450
10.86.2.64/26 via 10.86.3.16 dev cilium_host proto kernel src 10.86.3.16 mtu 1450
10.86.2.128/26 via 10.86.3.16 dev cilium_host proto kernel src 10.86.3.16 mtu 1450
10.86.2.192/26 via 10.86.3.16 dev cilium_host proto kernel src 10.86.3.16 mtu 1450
10.86.3.0/26 via 10.86.3.16 dev cilium_host proto kernel src 10.86.3.16
10.86.3.16 dev cilium_host proto kernel scope link
...
```

但是，在网络断开连接期间，Cilium 操作员和 Cilium 代理会重新启动，因为他们的运行状况检查与与 Kubernetes API 服务器的连接的运行状况相结合。在网络断开连接期间，预计将在Cilium操作员和Cilium代理的日志中看到以下内容。在网络断开连接期间，您可以使用诸如 `crictl` CLI 之类的工具来观察这些组件的重启情况，包括其日志。

```
msg="Started gops server" address="127.0.0.1:9890" subsys=gops
msg="Establishing connection to apiserver" host="https://<k8s-cluster-ip>:443" subsys=k8s-client
msg="Establishing connection to apiserver" host="https://<k8s-cluster-ip>:443" subsys=k8s-client
msg="Unable to contact k8s api-server" error="Get \"https://<k8s-cluster-ip>:443/api/v1/namespaces/kube-system\": dial tcp <k8s-cluster-ip>:443: i/o timeout" ipAddr="https://<k8s-cluster-ip>:443" subsys=k8s-client
msg="Start hook failed" function="client.(*compositeClientset).onStart (agent.infra.k8s-client)" error="Get \"https://<k8s-cluster-ip>:443/api/v1/namespaces/kube-system\": dial tcp <k8s-cluster-ip>:443: i/o timeout"
msg="Start failed" error="Get \"https://<k8s-cluster-ip>:443/api/v1/namespaces/kube-system\": dial tcp <k8s-cluster-ip>:443: i/o timeout" duration=1m5.003834026s
msg=Stopping
msg="Stopped gops server" address="127.0.0.1:9890" subsys=gops
msg="failed to start: Get \"https://<k8s-cluster-ip>:443/api/v1/namespaces/kube-system\": dial tcp <k8s-cluster-ip>:443: i/o timeout" subsys=daemon
```

如果您使用 Cilium 的 BGP 控制平面功能进行应用程序负载平衡，则在网络断开连接期间，Pod 和服务的 BGP 会话可能会关闭，因为 BGP 扬声器功能已与 Cilium 代理集成，而且 Cilium 代理在与 Kubernetes 控制平面断开连接时将持续重新启动。有关更多信息，请参阅 Cilium 文档中的 Cilium BGP 控制平面操作指南。此外，如果您在网络断开连接（例如电源循环或计算机重启）期间同时遇到故障，则不会通过这些操作保留 Cilium 路由，尽管当节点重新连接到 Kubernetes 控制平面并且 Cilium 再次启动时，会重新创建路由。

## Calico
<a name="_calico"></a>

 *即将推出* 

## MetalL B
<a name="_metallb"></a>

MetalLB 有两种负载平衡模式：[L2 模式和 [BG](https://metallb.universe.tf/concepts/bgp/) P 模式](https://metallb.universe.tf/concepts/layer2/)。有关这些负载平衡模式的工作原理及其局限性的详细信息，请参阅 MetalLB 文档。本指南的验证在 L2 模式下使用了 MetalLB，在这种模式下，集群中的一台计算机拥有 Kubernetes 服务的所有权，并使用 ARP IPv4 使负载均衡器的 IP 地址可在本地网络上访问。运行MetalLB时，有一个控制器负责IP分配，每个节点上都有一个扬声器，负责通过分配的IP地址发布服务。MetalLB 控制器作为部署模式运行，MetalLB 扬声器作为部署模式运行。 DaemonSet在网络断开连接期间，MetalLB 控制器和扬声器无法监视 Kubernetes API 服务器以获取集群资源，但会继续运行。最重要的是，在网络断开连接期间，使用 MetalLB 进行外部连接的服务仍然可用且可访问。

## kube-proxy
<a name="_kube_proxy"></a>

在 EKS 集群中，kube-proxy 作为 DaemonSet 在每个节点上运行，负责管理网络规则，通过将服务 IP 地址转换为底层 Pod 的 IP 地址来实现服务与 Pod 之间的通信。kube-proxy 配置的 IP 表 (iptables) 规则在网络断开连接期间得到维护，集群内路由继续运行，kube-proxy pod 继续运行。

你可以使用以下 iptables 命令来观察 kube-proxy 规则。第一条命令显示通过`PREROUTING`链的数据包被定向到`KUBE-SERVICES`链。

```
iptables -t nat -L PREROUTING
```

```
Chain PREROUTING (policy ACCEPT)
target         prot opt source      destination
KUBE-SERVICES  all  --  anywhere    anywhere      /* kubernetes service portals */
```

通过检查`KUBE-SERVICES`链，我们可以看到各种集群服务的规则。

```
Chain KUBE-SERVICES (2 references)
target                     prot opt source      destination
KUBE-SVL-NZTS37XDTDNXGCKJ  tcp  --  anywhere    172.16.189.136  /* kube-system/hubble-peer:peer-service cluster IP /
KUBE-SVC-2BINP2AXJOTI3HJ5  tcp  --  anywhere    172.16.62.72    / default/metallb-webhook-service cluster IP /
KUBE-SVC-LRNEBRA3Z5YGJ4QC  tcp  --  anywhere    172.16.145.111  / default/redis-leader cluster IP /
KUBE-SVC-I7SKRZYQ7PWYV5X7  tcp  --  anywhere    172.16.142.147  / kube-system/eks-extension-metrics-api:metrics-api cluster IP /
KUBE-SVC-JD5MR3NA4I4DYORP  tcp  --  anywhere    172.16.0.10     / kube-system/kube-dns:metrics cluster IP /
KUBE-SVC-TCOU7JCQXEZGVUNU  udp  --  anywhere    172.16.0.10     / kube-system/kube-dns:dns cluster IP /
KUBE-SVC-ERIFXISQEP7F7OF4  tcp  --  anywhere    172.16.0.10     / kube-system/kube-dns:dns-tcp cluster IP /
KUBE-SVC-ENODL3HWJ5BZY56Q  tcp  --  anywhere    172.16.7.26     / default/frontend cluster IP /
KUBE-EXT-ENODL3HWJ5BZY56Q  tcp  --  anywhere    <LB-IP>    / default/frontend loadbalancer IP /
KUBE-SVC-NPX46M4PTMTKRN6Y  tcp  --  anywhere    172.16.0.1      / default/kubernetes:https cluster IP /
KUBE-SVC-YU5RV2YQWHLZ5XPR  tcp  --  anywhere    172.16.228.76   / default/redis-follower cluster IP /
KUBE-NODEPORTS             all  --  anywhere    anywhere        / kubernetes service nodeports; NOTE: this must be the last rule in this chain */
```

检查应用程序的前端服务链，我们可以看到支持该服务的 pod IP 地址。

```
iptables -t nat -L KUBE-SVC-ENODL3HWJ5BZY56Q
```

```
Chain KUBE-SVC-ENODL3HWJ5BZY56Q (2 references)
target                     prot opt source    destination
KUBE-SEP-EKXE7ASH7Y74BGBO  all  --  anywhere  anywhere    /* default/frontend -> 10.86.2.103:80 / statistic mode random probability 0.33333333349
KUBE-SEP-GCY3OUXWSVMSEAR6  all  --  anywhere  anywhere    / default/frontend -> 10.86.2.179:80 / statistic mode random probability 0.50000000000
KUBE-SEP-6GJJR3EF5AUP2WBU  all  --  anywhere  anywhere    / default/frontend -> 10.86.3.47:80 */
```

在网络断开连接期间，当它尝试监视 Kubernetes API 服务器的节点和端点资源更新时，预计会出现以下 kube-proxy 日志消息。

```
"Unhandled Error" err="k8s.io/client-go/informers/factory.go:160: Failed to watch *v1.Node: failed to list *v1.Node: Get \"https://<k8s-endpoint>/api/v1/nodes?fieldSelector=metadata.name%3D<node-name>&resourceVersion=2241908\": dial tcp <k8s-ip>:443: i/o timeout" logger="UnhandledError"
"Unhandled Error" err="k8s.io/client-go/informers/factory.go:160: Failed to watch *v1.EndpointSlice: failed to list *v1.EndpointSlice: Get \"https://<k8s-endpoint>/apis/discovery.k8s.io/v1/endpointslices?labelSelector=%21service.kubernetes.io%2Fheadless%2C%21service.kubernetes.io%2Fservice-proxy-name&resourceVersion=2242090\": dial tcp <k8s-ip>:443: i/o timeout" logger="UnhandledError"
```

## CoreDNS
<a name="_coredns"></a>

默认情况下，EKS 集群中的 Pod 使用 CoreDNS 集群 IP 地址作为集群内 DNS 查询的名称服务器。在 EKS 集群中，CoreDNS 作为节点上的部署运行。使用混合节点，当混合节点上有 CoreDNS 副本在本地运行时，Pod 可以在网络断开连接期间继续与 CoreDNS 通信。如果您的 EKS 集群的节点位于云中，而混合节点位于本地环境中，则建议每个环境中至少有一个 CoreDNS 副本。CoreDNS 继续为网络断开连接之前创建的记录提供 DNS 查询，并通过网络重新连接继续运行，以保持静态稳定。

在网络断开连接期间，当它尝试列出来自 Kubernetes API 服务器的对象时，预计会出现以下 CoreDNS 日志消息。

```
Failed to watch *v1.Namespace: failed to list *v1.Namespace: Get "https://<k8s-cluster-ip>:443/api/v1/namespaces?resourceVersion=2263964": dial tcp <k8s-cluster-ip>:443: i/o timeout
Failed to watch *v1.Service: failed to list *v1.Service: Get "https://<k8s-cluster-ip>:443/api/v1/services?resourceVersion=2263966": dial tcp <k8s-cluster-ip>:443: i/o timeout
Failed to watch *v1.EndpointSlice: failed to list *v1.EndpointSlice: Get "https://<k8s-cluster-ip>:443/apis/discovery.k8s.io/v1/endpointslices?resourceVersion=2263896": dial tcp <k8s-cluster-ip>: i/o timeout
```

# 通过网络断开连接获得的主机凭证
<a name="hybrid-nodes-host-creds"></a>

EKS 混合节点与 AWS Systems Manager (SSM) 混合激活和 AWS IAM Anywhere 角色集成，用于通过 EKS 控制平面对节点进行身份验证的临时 IAM 证书。SSM 和 IAM Anywhere 角色都会自动刷新他们在本地主机上管理的临时证书。建议在集群中的混合节点上使用单一凭证提供商，即 SSM 混合激活或 IAM 角色随处可见，但不能两者兼而有之。

## SSM 混合激活
<a name="_ssm_hybrid_activations"></a>

SSM 提供的临时证书有效期为一小时。使用 SSM 作为凭证提供商时，您无法更改凭证有效期。临时证书将在到期前由 SSM 自动轮换，并且轮换不会影响您的节点或应用程序的状态。但是，当 SSM 代理和 SSM 区域端点之间的网络断开连接时，SSM 无法刷新凭证，并且凭据可能会过期。

如果 SSM 无法连接到 SSM 区域端点，则使用指数退避来重试凭据刷新。在 SSM 代理版本`3.3.808.0`及更高版本（2024 年 8 月发布）中，指数级退缩上限为 30 分钟。根据网络断开连接的持续时间，SSM 最多可能需要 30 分钟才能刷新凭据，并且在刷新凭据之前，混合节点不会重新连接到 EKS 控制平面。在这种情况下，您可以重新启动 SSM 代理以强制刷新凭据。当前 SSM 凭证刷新行为的副作用是，节点可能会在不同的时间重新连接，具体取决于每个节点上的 SSM 代理何时设法刷新其凭据。因此，您可能会看到尚未重新连接的节点的 Pod 故障转移到已经重新连接的节点。

获取 SSM 代理版本。您也可以查看 SSM 控制台的舰队管理器部分：

```
# AL2023, RHEL
yum info amazon-ssm-agent
# Ubuntu
snap list amazon-ssm-agent
```

重新启动 SSM 代理：

```
# AL2023, RHEL
systemctl restart amazon-ssm-agent
# Ubuntu
systemctl restart snap.amazon-ssm-agent.amazon-ssm-agent
```

查看 SSM 代理日志：

```
tail -f /var/log/amazon/ssm/amazon-ssm-agent.log
```

网络断开连接期间的预期日志消息：

```
INFO [CredentialRefresher] Credentials ready
INFO [CredentialRefresher] Next credential rotation will be in 29.995040663666668 minutes
ERROR [CredentialRefresher] Retrieve credentials produced error: RequestError: send request failed
INFO [CredentialRefresher] Sleeping for 35s before retrying retrieve credentials
ERROR [CredentialRefresher] Retrieve credentials produced error: RequestError: send request failed
INFO [CredentialRefresher] Sleeping for 56s before retrying retrieve credentials
ERROR [CredentialRefresher] Retrieve credentials produced error: RequestError: send request failed
INFO [CredentialRefresher] Sleeping for 1m24s before retrying retrieve credentials
```

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

默认情况下，由 IAM Roles Anywhere 配置的临时证书有效期为一小时。您可以通过 IAM Roles Anywhere 配置文件中的[https://docs.aws.amazon.com/rolesanywhere/latest/userguide/authentication-create-session.html#credentials-object](https://docs.aws.amazon.com/rolesanywhere/latest/userguide/authentication-create-session.html#credentials-object)字段配置凭证有效期。凭证的最长有效期为 12 小时。您的混合节点 IAM 角色的[https://docs.aws.amazon.com/managedservices/latest/ctref/management-advanced-identity-and-access-management-iam-update-maxsessionduration.html](https://docs.aws.amazon.com/managedservices/latest/ctref/management-advanced-identity-and-access-management-iam-update-maxsessionduration.html)设置必须大于您的 IAM Roles Anywhere 个人资料中的`durationSeconds`设置。

使用 IAM Rolet Anywhere 作为混合节点的凭证提供商时，网络断开连接后通常会在网络恢复后的几秒钟内重新连接到 EKS 控制平面，因为 kubelet 会调用按`aws_signing_helper credential-process`需获取证书。尽管与混合节点或网络断开连接没有直接关系，但在使用 IAM Roles Anywhere 时，您可以配置证书到期通知和警报。有关更多信息，请参阅 [IAM 角色中的自定义 Anywhere 中的通知设置](https://docs.aws.amazon.com/rolesanywhere/latest/userguide/customize-notification-settings.html)。