节点(Nodes)
Kubernetes 通过将容器放入 Pod 以在节点上运行来运行您的工作负载。节点可以是虚拟机或物理机,具体取决于集群。每个节点由 控制平面 并包含运行所需的服务 Pod.
通常一个集群中有多个节点;在学习或资源有限的环境中,您可能只有一个节点。
节点上的组件包括 kubelet, 一个 容器运行时,以及 kube代理.
管理
有两种主要方法可以将节点添加到 接口服务器:
- 节点上的 kubelet 自注册到控制平面
- 您(或其他用户)手动添加 Node 对象
创建 Node 对象或节点上的 kubelet 自注册后,控制平面会检查新的 Node 对象是否有效。例如,如果您尝试从以下 JSON 清单创建节点:
{
"kind": "Node",
"apiVersion": "v1",
"metadata": {
"name": "10.240.79.157",
"labels": {
"name": "my-first-k8s-node"
}
}
}
Kubernetes 在内部创建一个 Node 对象(表示)。Kubernetes 检查 kubelet 是否已注册到与 Node.jsmetadata.name
字段匹配的 API 服务器。如果节点是健康的(即所有必要的服务都在运行),那么它就有资格运行一个 Pod。否则,任何集群活动都会忽略该节点,直到它变得健康为止。
笔记:
Kubernetes 保留无效节点的对象并继续检查它是否变得健康。
你,或者一个 控制器, 必须明确删除 Node 对象才能停止健康检查。
Node 对象的名称必须是有效的 DNS 子域名。
节点名称唯一性Node Name Uniqueness
该名称标识一个节点。两个节点不能同时具有相同的名称。Kubernetes 还假设同名的资源是同一个对象。在节点的情况下,隐式假设使用相同名称的实例将具有相同的状态(例如网络设置、根磁盘内容)和节点标签等属性。如果修改实例而不更改其名称,这可能会导致不一致。如果 Node 需要大量更换或更新,则需要先从 API 服务器中删除现有的 Node 对象,并在更新后重新添加。
节点自注册(Self-registration of Nodes)
当 kubelet 标志--register-node
为 true(默认)时,kubelet 将尝试向 API 服务器注册自己。这是大多数发行版使用的首选模式。
对于自注册,kubelet 使用以下选项启动:
--kubeconfig
- 用于向 API 服务器进行身份验证的凭据路径。--cloud-provider
- 如何与人交谈 云供应商 读取关于自身的元数据。--register-node
- 自动向 API 服务器注册。-
--register-with-taints
- 使用给定的列表注册节点 污点(逗号分隔
)。= : 如果
register-node
为假则无操作。 --node-ip
- 节点的 IP 地址。--node-labels
—— 标签在集群中注册节点时添加(请参阅NodeRestriction 准入插件强制执行的标签限制)。--node-status-update-frequency
- 指定 kubelet 向 master 发布节点状态的频率。
当启用Node 授权模式和 NodeRestriction 准入插件时,kubelet 仅被授权创建/修改自己的 Node 资源。
笔记:
正如节点名称唯一性部分所述,当需要更新节点配置时,最好将节点重新注册到 API 服务器。例如,如果 kubelet 使用新的 集合重新启动--node-labels
,但使用相同的节点名称,则更改将不会生效,因为正在节点注册上设置标签。
如果节点配置将在 kubelet 重新启动时更改,则已在节点上调度的 Pod 可能会出现错误行为或导致问题。例如,已经运行的 Pod 可能会被分配给节点的新标签污染,而与该 Pod 不兼容的其他 Pod 将根据这个新标签进行调度。节点重新注册可确保所有 Pod 都将被耗尽并正确重新调度。
手动节点管理(Manual Node Administration)
您可以使用创建和修改 Node 对象 kubectl.
当您想手动创建 Node 对象时,请设置 kubelet 标志--register-node=false
。
无论 的设置如何,您都可以修改 Node 对象--register-node
。例如,您可以在现有节点上设置标签或将其标记为不可调度。
您可以将节点上的标签与 Pod 上的节点选择器结合使用来控制调度。例如,您可以将 Pod 限制为只能在可用节点的子集上运行。
将节点标记为不可调度可防止调度程序将新 Pod 放置到该节点上,但不会影响该节点上的现有 Pod。这作为节点重新启动或其他维护之前的准备步骤非常有用。
要将节点标记为不可调度,请运行:
kubectl cordon $NODENAME
有关 更多详细信息,请参阅安全耗尽节点。
注意:属于守护进程集容忍在不可调度的节点上运行。DaemonSets 通常提供节点本地服务,这些服务应该在节点上运行,即使它正在耗尽工作负载应用程序。
节点状态
节点的状态包含以下信息:
- 地址
- 条件
- 容量和可分配
- 信息
您可以使用kubectl
来查看节点的状态和其他详细信息:
kubectl describe node
下面描述了输出的每个部分。
地址
这些字段的使用因您的云提供商或裸机配置而异。
- HostName:节点内核报告的主机名。可以通过 kubelet
--hostname-override
参数覆盖。 - ExternalIP:通常是可从外部路由的节点的 IP 地址(可从集群外部获得)。
- InternalIP:通常是仅在集群内可路由的节点的 IP 地址。
条件
该conditions
字段描述了所有Running
节点的状态。条件示例包括:
节点条件 | 描述 |
---|---|
Ready |
True 如果节点健康并准备好接受 pod,False 如果节点不健康并且不接受 pod,并且Unknown 节点控制器最后没有收到节点的消息node-monitor-grace-period (默认为 40 秒) |
DiskPressure |
True 磁盘大小是否有压力——即磁盘容量是否不足;否则False |
MemoryPressure |
True 节点内存是否存在压力——即节点内存是否不足;否则False |
PIDPressure |
True 如果进程存在压力——即节点上的进程过多;否则False |
NetworkUnavailable |
True 如果节点的网络配置不正确,否则 False |
注意:如果您使用命令行工具打印封锁节点的详细信息,则条件包括 SchedulingDisabled
. SchedulingDisabled
不是 Kubernetes API 中的条件;相反,被封锁的节点在其规范中被标记为不可调度。
在 Kubernetes API 中,节点的条件表示为.status
节点资源的一部分。例如,以下 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"
}
]
如果status
Ready 条件的 保持Unknown
或False
持续时间长于pod-eviction-timeout
(传递给 kube-控制器-管理器),然后节点控制器触发 API 发起的驱逐 对于分配给该节点的所有 Pod。默认的驱逐超时持续时间是 五分钟。在某些节点不可达的情况下,API 服务器无法与节点上的 kubelet 通信。在重新建立与 API 服务器的通信之前,无法将删除 Pod 的决定传达给 kubelet。同时,计划删除的 Pod 可能会继续在分区节点上运行。
节点控制器不会强制删除 pod,直到确认它们已停止在集群中运行。您可以看到可能在无法访问的节点上运行的 Pod 处于Terminating
或Unknown
状态。如果 Kubernetes 无法从底层基础设施推断出节点是否永久离开集群,则集群管理员可能需要手动删除节点对象。从 Kubernetes 中删除节点对象会导致节点上运行的所有 Pod 对象从 API 服务器中删除并释放它们的名称。
当节点出现问题时,Kubernetes 控制平面会自动创建 与影响节点的条件匹配的污点。调度程序在将 Pod 分配给节点时会考虑节点的污点。Pods 也可以有容忍 即使它具有特定的污点,也可以让它们在节点上运行。
有关 更多详细信息,请参阅按条件分类的污点节点。
容量和可分配
描述节点上可用的资源:CPU、内存以及可以调度到节点上的最大 Pod 数。
容量块中的字段表示节点拥有的资源总量。可分配块指示节点上可供普通 Pod 消耗的资源量。
您可以在学习如何 在节点上预留计算资源的同时阅读更多关于容量和可分配资源的信息。
信息
描述有关节点的一般信息,例如内核版本、Kubernetes 版本(kubelet 和 kube-proxy 版本)、容器运行时详细信息以及节点使用的操作系统。kubelet 从节点收集此信息并将其发布到 Kubernetes API。
心跳(Heartbeats)
由 Kubernetes 节点发送的心跳帮助您的集群确定每个节点的可用性,并在检测到故障时采取行动。
对于节点,有两种形式的心跳:
-
.status
节点的更新 - 租赁范围内的对象
kube-node-lease
命名空间. 每个节点都有一个关联的 Lease 对象。
与.status
节点的更新相比,租约是一种轻量级资源。使用 Leases for heartbeats 降低了这些更新对大型集群的性能影响。
kubelet 负责创建和更新.status
Nodes,并更新它们相关的 Lease。
-
.status
当状态发生变化或在配置的时间间隔内没有更新时,kubelet 会更新节点。.status
节点更新的默认间隔是 5 分钟,这比不可达节点的 40 秒默认超时要长得多。 - kubelet 每 10 秒(默认更新间隔)创建并更新其 Lease 对象。租约更新独立于节点的
.status
. 如果租约更新失败,kubelet 会重试,使用从 200 毫秒开始并以 7 秒为上限的指数退避。
节点控制器
节点 控制器 是一个 Kubernetes 控制平面组件,用于管理节点的各个方面。
节点控制器在节点的生命周期中具有多个角色。第一个是在节点注册时为其分配 CIDR 块(如果启用了 CIDR 分配)。
第二个是使节点控制器的内部节点列表与云提供商的可用机器列表保持同步。当在云环境中运行并且节点不健康时,节点控制器会询问云提供商该节点的 VM 是否仍然可用。如果不是,则节点控制器从其节点列表中删除该节点。
第三是监控节点的健康状况。节点控制器负责:
- 在节点变得无法访问的情况下,更新节点内的 NodeReady 条件
.status
。在这种情况下,节点控制器将 NodeReady 条件设置为ConditionUnknown
。 - 如果节点仍然无法访问: 为无法访问的节点上的所有 Pod触发 API 启动的驱逐。默认情况下,节点控制器在将节点标记为
ConditionUnknown
和提交第一个驱逐请求之间等待 5 分钟。
节点控制器每秒检查每个节点的状态--node-monitor-period
。
驱逐速率限制
在大多数情况下,节点控制器将逐出率限制为 --node-eviction-rate
(默认为 0.1)每秒,这意味着它不会每 10 秒从超过 1 个节点中逐出 Pod。
当给定可用区中的节点变得不健康时,节点驱逐行为会发生变化。节点控制器同时检查区域中不健康节点的百分比(NodeReady 条件为ConditionUnknown
或ConditionFalse
):
- 如果不健康节点的比例至少为
--unhealthy-zone-threshold
(默认为 0.55),则驱逐率会降低。 - 如果集群很小(即少于或等于
--large-cluster-size-threshold
节点数 - 默认为 50),则停止驱逐。 - 否则,逐出率将降低到
--secondary-node-eviction-rate
(默认 0.01)每秒。
每个可用区实施这些策略的原因是,一个可用区可能会从主服务器分区,而其他可用区保持连接。如果您的集群不跨越多个云提供商可用区,则驱逐机制不会考虑每个区域的不可用性。
跨可用区分布节点的一个关键原因是,当整个区域出现故障时,工作负载可以转移到健康区域。因此,如果一个区域中的所有节点都不健康,那么节点控制器会以正常的速率驱逐--node-eviction-rate
。极端情况是所有区域都完全不健康(集群中没有一个节点是健康的)。在这种情况下,节点控制器假定控制平面和节点之间的连接存在一些问题,并且不执行任何驱逐。(如果发生中断并且某些节点重新出现,节点控制器会从其余不健康或无法访问的节点中驱逐 Pod)。
节点控制器还负责驱逐在带有NoExecute
污点的节点上运行的 Pod,除非这些 Pod 容忍该污点。节点控制器还添加了污点 对应于节点不可达或未就绪等节点问题。这意味着调度程序不会将 Pod 放在不健康的节点上。
资源容量追踪
节点对象跟踪有关节点资源容量的信息:例如,可用内存量和 CPU 数量。自行注册的节点在注册期间报告其容量。如果手动添加一个Node,那么在添加的时候需要设置该节点的容量信息。
Kubernetes 调度器确保节点上的所有 Pod 都有足够的资源。调度器检查节点上容器的请求总和不大于节点的容量。该请求总数包括由 kubelet 管理的所有容器,但不包括由容器运行时直接启动的任何容器,也不包括在 kubelet 控制之外运行的任何进程。
注意:如果您想为非 Pod 进程显式保留资源,请参阅 为系统守护进程保留资源。
节点拓扑(Node Topology)
功能状态: Kubernetes v1.16 [alpha]
如果您启用了TopologyManager
特性 gate,那么 kubelet 可以在做出资源分配决策时使用拓扑提示。有关 详细信息,请参阅控制节点上的拓扑管理策略。
优雅的节点关闭(Graceful node shutdown)
功能状态: Kubernetes v1.21 [beta]
kubelet 尝试检测节点系统关闭并终止在节点上运行的 pod。
Kubelet 确保 Pod在节点关闭期间遵循正常的Pod 终止过程。
优雅的节点关闭功能依赖于 systemd,因为它利用 systemd 抑制锁来延迟节点关闭给定的持续时间。
优雅的节点关闭由GracefulNodeShutdown
特性门控制,该特性门在 1.21 中默认启用。
注意,默认情况下,无论是配置选项如下所述, shutdownGracePeriod
并且shutdownGracePeriodCriticalPods
被设置为零,因此不激活平滑节点关机功能。要激活该功能,应适当配置两个 kubelet 配置设置并将其设置为非零值。
在正常关闭期间,kubelet 分两个阶段终止 pod:
- 终止在节点上运行的常规 Pod。
- 终止在节点上运行的关键 Pod。
优雅的节点关闭功能配置有两个KubeletConfiguration
选项:
-
shutdownGracePeriod
:- 指定节点应该延迟关闭的总持续时间。这是常规Pod和关键 Pod 的Pod 终止的总宽限期。
-
shutdownGracePeriodCriticalPods
:- 指定在节点关闭期间用于终止关键 Pod的持续时间。该值应小于
shutdownGracePeriod
。
- 指定在节点关闭期间用于终止关键 Pod的持续时间。该值应小于
例如,如果shutdownGracePeriod=30s
, 和 shutdownGracePeriodCriticalPods=10s
,kubelet 将延迟节点关闭 30 秒。在关闭期间,前 20 (30-10) 秒将保留用于正常终止正常 Pod,最后 10 秒将保留用于终止关键 Pod。
笔记:
当 Pod 在正常节点关闭期间被驱逐时,它们被标记为关闭。Runningkubectl get pods
将被驱逐的 Pod 的状态显示为Terminated
。并kubectl describe pod
表示 pod 因节点关闭而被驱逐:
Reason: Terminated
Message: Pod was terminated in response to imminent node shutdown.
基于 Pod 优先级的优雅节点关闭
功能状态: Kubernetes v1.23 [alpha]
为了在正常节点关闭期间围绕关闭期间 Pod 的顺序提供更大的灵活性,如果您在集群中启用了此功能,则正常节点关闭会尊重 Pod 的 PriorityClass。该功能允许集群管理员在基于优先级的正常节点关闭期间明确定义 pod 的顺序。
如上所述,Graceful Node Shutdown功能分两个阶段关闭 pod,非关键 pod,然后是关键 pod。如果需要额外的灵活性以更精细的方式在关闭期间明确定义 pod 的顺序,则可以使用基于 pod 优先级的优雅关闭。
当优雅的节点关闭尊重 pod 优先级时,这使得可以在多个阶段进行优雅的节点关闭,每个阶段关闭特定优先级的 pod。kubelet 可以配置确切的阶段和每个阶段的关闭时间。
假设 集群中有以下自定义 pod优先级类,
Pod 优先级类名 | Pod 优先级值 |
---|---|
custom-class-a |
100000 |
custom-class-b |
10000 |
custom-class-c |
1000 |
regular/unset |
0 |
在kubelet 配置中, 其设置shutdownGracePeriodByPodPriority
可能如下所示:
Pod 优先级值 | 停产期 |
---|---|
100000 | 10 秒 |
10000 | 180 秒 |
1000 | 120 秒 |
0 | 60 秒 |
相应的 kubelet config YAML 配置将是:
shutdownGracePeriodByPodPriority:
- priority: 100000
shutdownGracePeriodSeconds: 10
- priority: 10000
shutdownGracePeriodSeconds: 180
- priority: 1000
shutdownGracePeriodSeconds: 120
- priority: 0
shutdownGracePeriodSeconds: 60
上表意味着任何优先级值 >= 100000 的 pod 将只有 10 秒停止,任何值 >= 10000 和 < 100000 的 pod 将得到 180 秒停止,任何值 >= 1000 和 < 10000 的 pod 将得到120秒停止。最后,所有其他 Pod 将有 60 秒的时间停止。
不必指定对应于所有类的值。例如,您可以改为使用这些设置:
Pod 优先级值 | 停产期 |
---|---|
100000 | 300 秒 |
1000 | 120 秒 |
0 | 60 秒 |
在上述情况下,带有 custom-class-b 的 pod 将进入与 custom-class-c 相同的存储桶以进行关闭。
如果特定范围内没有 Pod,则 kubelet 不会等待该优先级范围内的 Pod。相反,kubelet 会立即跳到下一个优先级类值范围。
如果启用此功能且未提供任何配置,则不会执行任何订购操作。
使用此功能,需要启用 GracefulNodeShutdownBasedOnPodPriority
功能门,并将 kubelet 配置设置为ShutdownGracePeriodByPodPriority
包含 pod 优先级类值及其各自关闭时间的所需配置。
交换内存管理
功能状态: Kubernetes v1.22 [alpha]
在 Kubernetes 1.22 之前,节点不支持使用交换内存,如果在节点上检测到交换,kubelet 将默认无法启动。从 1.22 开始,可以在每个节点的基础上启用交换内存支持。
要在节点上启用交换,NodeSwap
必须在 kubelet 上启用功能门,并且 必须将--fail-swap-on
命令行标志或failSwapOn
配置设置设置为 false。
警告:当内存交换功能打开时,Kubernetes 数据(例如现在写入 tmpfs 的 Secret 对象的内容)可以交换到磁盘。
用户还可以选择配置memorySwap.swapBehavior
以指定节点将如何使用交换内存。例如,
memorySwap:
swapBehavior: LimitedSwap
可用的配置选项swapBehavior
有:
-
LimitedSwap
:Kubernetes 工作负载在它们可以使用的交换量方面受到限制。不受 Kubernetes 管理的节点上的工作负载仍然可以交换。 -
UnlimitedSwap
:Kubernetes 工作负载可以使用它们请求的尽可能多的交换内存,最多可达系统限制。
如果memorySwap
没有指定配置并且启用了特性门,默认情况下 kubelet 将应用与LimitedSwap
设置相同的行为 。
LimitedSwap
设置的行为取决于节点是使用 v1 还是 v2 控制组(也称为“cgroups”)运行:
- cgroupsv1: Kubernetes 工作负载可以使用内存和交换的任意组合,最高可达 pod 的内存限制(如果设置)。
- cgroupsv2: Kubernetes 工作负载不能使用交换内存。