Kubernetes 架构:节点

Table of Contents

https://kubernetes.io/docs/concepts/architecture/nodes/

Kubernetes 在 节点(nodes) 上将容器放入 Pods 中运行你的工作负载。节点可能是一个虚拟或者物理的机器,依赖于你的集群。 每个节点都会被控制平面管理,并且包含运行 Pods 所需要的服务。

通常,一个集群中包含多个节点。在学习或者有限的资源环境中,您可能只有一个节点。

节点上的 组件 包含:kubelet,容器运行时(container runtime)和 kube-proxy。

1. 管理

将节点添加到 API server 主要有两种方法:

  1. 节点上的 kubelet 自动注册到控制平面
  2. 你(或者其他人)手动添加节点对象

在你创建了节点对象之后,或者节点上的 kubelet 自注册,控制平面会检查新的节点是否有效。举个例子,如果你想用一下的 JSON 创建一个节点:

{
    "kind": "Node",
    "apiVersion": "v1",
    "metadata": {
        "name": "10.240.79.157",
        "labels": {
            "name": "my-first-k8s-node"
        }
    }
}

Kubernetes 在内部创建一个节点对象,Kubernetes 会检查 kubelet 已注册到 API server 的与 metadata.name 字段是否匹配。 如果节点健康(是否所有必要的服务都在运行),确定它是否有资格运行 Pod。否则的话,该节点对于任何的集群活动都会被忽略,直到它变得健康为止。

注意: Kubernetes 将保留无效的节点,然后持续检查该节点是否健康。

你,或者控制器,必须显式的删除节点对象才能停止该健康检测。

节点对象的命名格式必须是一个有效的 DNS 子域格式

1.1. 节点名称唯一性

名字可以标识一个节点。两个节点不可能在同一个时间内有相同的名字。Kubernetes 假定具有相同名称的资源是相同的对象。对于节点,他隐式的假定相同名称的实例 具有相同的状态(比如说:网络设置,根磁盘内容)。如果在不更改实例名称的情况下对其进行了修改,则可能导致不一致。如果需要大量更换或者更新的节点,现有的节点 对象首先从 APIServer 中删除,并在更新后重新添加。

1.2. 节点的自注册

如果 kubelet 的 --register-node 是 true(默认值),kubelet 会尝试注册自己到 API server。这是大多数发行版首选的模式。

对于自注册的,kubelet 使用以下选项启动:

  • --kubeconfig - 向 API server 进行身份验证的证书路径;
  • --cloud-provider - 如何与云提供商交互以获取自身的元数据;
  • --register-node - 自动向 API server 注册;
  • --register-with-taints - 使用给定的污点列表(逗号分隔的 <key>=<value>:<effect> )注册节点。 如果 register-node 是 false 则什么都不操作;
  • --node-ip - 节点的 IP 地址;
  • --node-labels - 注册到集群之后添加的标签;
  • --node-status-update-frequency - 指定 kubelet 多久同步一次节点状态到主节点;

节点认证模式节点限制准入插件 是开启状态,kubelet 仅被授权创建/修改自己的节点资源。

1.3. 手动管理节点

你可以使用 kubectl 创建或者修改节点对象。

当需要手动创建节点对象时,给 kubelet 设置 --register-node=false

无论 --register-node 是什么样的,你都可以修改节点对象。比如,你可以在现有的节点上设置标签,或者将他标记为不可调度。

你可结合节点上的标签和 Pod 的节点选择器(node selector)来控制调度。比如,你可以约束 Pod 只有资格运行在一些可用节点的子集上。

标记节点不可调度会阻止新的 Pods 调度到该节点上,但是不会影响节点上现有的 Pods。这作为重启或者维护之前的准备步骤很有效。

标记一个节点不可调度,运行:

kubectl cordon $NODENAME

注意: 作为 DaemonSet 的一部分 Pods 是可以运行在不可调度节点上的。DaemonSet 通常会提供本地节点服务,即使正在耗尽工作负载的应用程序, 它也应该在节点上运行。

2. 节点状态

一个节点包含:地址状况(conditions)容量和可分配信息。可通过 kubectl describe node <node-name> 查看详细信息。

2.1. 地址(Addresses)

这些字段值的运用取决于你的云提供商或者裸机配置。

  • HostName:由节点的内核指定。可以通过 kubelet 的 --hostname-override 参数覆盖;
  • ExternalIP:外部路由的节点 IP 地址(从集群外可访问);
  • InternalIP:集群内部路由的节点 IP 地址;

2.2. 状况(Conditions)

conditions 描述 Running 节点的状态。Conditions 的 Type 包括:

条件 描述
Ready 节点状态是否健康, True 健康状态可以接受新的 pods; False 不健康; Unknown 在最后的 node-monitor-grace-period 没有接受到节点控制器的信息(默认 40s)
DiskPressure True 表示存在磁盘压力,即磁盘空间剩余较低,否则为 False
MemoryPressure True 表示内存存在压力,即节点剩余内存较低
PIDPressure True 表示节点进程存在压力,即进程过多,否则为 False
NetworkUnavailable True 表示节点网络配置不正确

注意: 如果你使用 CLI 工具查看被 crodoned 的节点,Conditions 包括 SchedulingDisabledSchedulingDisabled 不是 Kubernetes API 的 Condition;而是由节点标记为「不可调度」。

节点 condition 可以表示为一个 JSON 对象。比如,下面是一个健康节点的描述结构:

"conditions": [
  {
    "type": "Ready",
    "status": "True",
    "reason": "KubeletReady",
    "message": "kubelet is posting ready status",
    "lastHeartbeatTime": "2019-06-05T18:38:35Z",
    "lastTransitionTime": "2019-06-05T11:41:27Z"
  }
]

如果节点的 Ready 条件处于 Unknown 或者 False 超过了 pod-eviction-timeout (传递给 kube-controller-manager 的参数)时间, 节点控制器上的 Pod 会被调度器从该节点上删除(迁移)。默认的驱逐超时时间为 5 分钟 。在某些情况下节点不可到达,API server 无法与节点上的 kubelet 通信。删除 Pod 的决定无法传递给 kubelet 直到 kubelet 与 API server 重新建立连接为止。 同时,计划删除的 Pod 可能会继续在分区节点上运行。

在确认节点已停止在集群中运行之前,节点控制器不会强制删除。你可以看到 Pod 可能在不可到达的节点处于 Terminating 或者 Unknown 状态。 如果 Kubernetes 无法从基础架构判断出某个节点永久离开集群的情况,集群管理员可能需要手动删除节点对象。从 Kubernetes 中删除该节点对象会导致 该节点上上运行的所有 Pod 对象从 API server 中删除,并释放其名称。

节点的生命周期控制器会自动创建代表 condition 的污点。在将 Pod 分配给节点时,调度程序会考虑节点的污点。Pods 也可以具有容忍度, 以使它们可以容忍节点的污点。

查看按条件污染节点获取更多的信息。

2.3. 容量和可分配(Capacity and Allocatable)

描述节点上的可用资源:CPU、内存和可以调度到该节点上的 Pods 最大数量。

  • Capacity 显示节点的资源总量
  • Allocatable 显示可提供给 Pod 消耗的资源总量

2.4. 信息(info)

节点的通用信息(System Info),包含:内核版本、系统、容器运行时以及 Kubernetes 版本信息等。

2.5. 节点控制器

节点控制器是 Kubernetes 控制面板组件用来管理节点的各个方面。

节点控制器在节点的生命周期中扮演多个角色。第一个是注册时将 CIDR 分配给该节点(如果 CIDR 分配已打开)。

第二个是节点控制器的内部节点列表与云提供商的可用机器列表保持最新。在云环境中运行时,只要节点运行不健康。节点控制器就询问云提供商,该节点的 VM 是否仍然可用。如果不可用,节点控制器将从其节点列表中删除该节点。

第三是监控节点的运行状况。当节点不可到达时,节点控制器负责将 NodeStatus 的 NodeReady 条件更新为 ConditionUnknown (即,由于某些原因(例如节点关闭)节点控制器停止接收心跳),然后如果该节点继续无法访问,则从该节点驱逐(优雅终结)所有的 Pods (默认超时为 40 秒,开始上报 ConditionUnknown,只有5分钟,开始驱逐 Pods)。节点控制器每隔 -node-monitor-period 秒检查一次节点的状态。

2.5.1. 心跳

心跳,由 Kubernetes 节点,帮助确定节点的可用性。

两种形式的心跳, NodeStatus 的更新和租赁对象。每个节点在 kube-node-lease 命名空间中都有一个关联的租赁对象。 租赁(lease)是一种轻量级的资源,随着集群扩展,这么做可以提高节点心跳的性能。

kubelet 负责创建和更新 NodeStatus 和租赁对象。

  • 状态更改或在配置时间间隔内没有更新时,kubelet 会更新 NodeStatus 。默认的 NodeStatus 更新间隔是 5 分钟 (比无法到达的节点的默认 40 秒超时判断要长的多);
  • 每 10 秒(默认的更新间隔),kubelet 创建和更新他的租赁对象。租赁的更新与 NodeStatus 更新保持独立。 如果租赁更新失败,kubelet 将从 200 毫秒开始以指数递增重试,上限为 7 秒;

2.5.2. 可靠性

多数情况下,节点控制器将驱逐速率限制为每秒 --node-eviction-rate (默认为 0.1),表示每 10 秒不会从一个以上的节点上驱逐 Pod。

当给定可用性区域中的节点不正常时,节点驱逐行为会更改。节点控制器从区域中检查同时有多少百分比的节点不正常(NodeReady 条件为 ConditionUnknown 或者 ConditionFalse)。 如果不健康的节点的分数至少为 --unhealth-zone-threshold (默认为 0.55),则驱逐率会降低:如果集群较小驱逐会被终止(小于或者等于 --large-cluster-size-threshold 默认 50),否则驱逐速率会被降低为 --secondary-node-evicition-rate (默认为 0.01)每秒。每个可用区都实施这些策略的原因是,一个可用区可能会与主分区分开, 而其他可用区仍保持连接。如果您的集群没有跨越多个云提供商可用性区域,则只有一个可用性区域(整个集群)。

将节点分布在各个可用区域上的一个关键原因是,当一个整个区域出现故障时,可以将工作负载转移到运行状况良好的区域。因此,如果区域中的所有节点都不正常, 则节点控制器将以 --node-eviction-rate 的正常速率逐出。极端的情况是所有区域都完全不健康。在这种情况下,节点控制器会假定主连接存在问题,并停止所有逐出, 直到恢复某些连接为止。

节点控制器还负责驱逐在具有 NoExecute 污染的节点上运行的 Pod,除非那些 Pods 容忍那个污点。节点控制器还会添加与节点问题(例如,节点不可达或未就绪)相对应的污点。 这意味着调度程序不会将 Pod 放置在不正常的节点上。

警告: kubectl cordon 标记节点为「不可调度」,具有 service 控制器的副作用,该 service 控制器将从之前符合资格的任何 Loadbanlancer 的目标列表中删除该节点,有效地从 cordoned 的节点中删除负载均衡器流量。

2.6. 节点容量

节点对象会跟踪节点资源的容量信息(比如:可用内存量和 CPU 数量)。自注册的节点在注册过程中报告其容量。如果你手动添加的节点,你需要在添加的时候设置节点的容量。

Kubernetes 调度程序确保所有的 Pod 都有足够的资源。调度器检查节点上的容器请求总和不大于节点的容量。请求总数包括了 kubelet 管理的所有容器,但是不包含 使用容器运行时直接启动的任何容器,也排除在 kubelet 组件之外的任何进程。

注意: 如果你要为非 Pod 进程显式的保留资源,查看为系统后台进程预留资源

3. 节点拓扑结构

FEATURE STATE: Kubernetes v1.16 [alpha]

如果你开启了 TopologyManager 特性开关,那么 kubelet 可以在做出资源分配决策时使用拓扑提示。查看控制节点上的拓扑管理策略获取更多信息。

4. 优雅关闭节点

如果你启动了 GracefulNodeShutdown 特性开关,kubelet 会尝试检测节点系统关闭并终止在节点上运行的 Pod。 kubelet 确保节点在关闭期间,容器遵循正常的 容器终止进程

GracefulNodeShutdown 特性开关开启时,kubelet 使用 systemd 抑制锁 以给定的时间延迟节点关闭。在关闭期间,kubelet 分两个阶段终止 pod:

  1. 终止在节点上运行的常规 Pod;
  2. 终止在节点上运行的关键 Pods

优雅关闭节点特性由以下两个 KubeletConfiguration 选项配置:

  • ShutdownGracePeriod:
    • 指定节点关闭延迟的总持续时间。这是常规 Pods 和 关键 Pods 的总时间;
  • ShutdownGracePeriodCriticalPods:
    • 指定关键 Pods 终止的总时间。这个应该比 ShutdownGracePeriod 要短;

举例,如果 ShutdownGracePeriod=30s, ShutdownGracePeriodCriticalPods=10s ,kubelet 会将节点关闭延迟 30s。在关机期间, 前 20(30-10)秒将保留用于正常终止正常 Pod,而后 10 秒将保留用于终止关键 Pod。

First created: 2021-02-28 18:00:19
Last updated: 2021-11-15 Mon 10:18
Power by Emacs 27.2 (Org mode 9.4.6)