1、集群架构示意图

在这里插入图片描述

2、概述

kubernetes通过将容器放入在节点(Node)上运行的Pod中来执行工作负载

节点可以是一个虚拟机或者一台物理机器,取决于所在集群的配置。

每个节点包含运行Pod所需的服务,这些节点由控制面板负责管理

通常集群中会有若干个节点;节点上的组件包括kubelet容器运行时以及kube-proxy

3、管理

向API服务器添加节点的方式主要有两种:

  1. 节点上的kubelet向控制面执行自注册;
  2. 人为手动添加一个Node对象

在创建了Node对象或者节点上的kubelet执行了自注册操作之后,控制面会检查新的Node对象是否合法

例如:使用下面的SON对象来创建Node对象

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

kubernetes会在内部创建一个Node对象作为节点的表示。kubernetes检查kubelet向API服务器注册节点时使用的metadata.name字段是否匹配。

如果节点是健康的(即所有必要的服务都在运行中),则该节点可以用来运行Pod。否则,直到该节点变为健康之前,所有的集群活动都会忽略该节点。

说明:

  • kubernetes会一直保存着非法节点对应的对象,并持续检查该节点是否变得健康
  • 用户或某个控制器必须显式的删除该node对象以停止健康检查操作
  • Node对象的名称必须是合法的DNS子域名

3.1 节点名称唯一性

节点的名称用来标识Node对象。没有两个Node可以同时使用相同的名称。

kubernetes还假定名字相同的资源是同一个对象。就Node而言,隐式假定使用相同名称的实例会具有相同的状态(如网络配置、根磁盘内容)和类似节点标签这种属性。这可能在节点被更改但其名称未变时导致系统状态不一致。

如果某个Node需要被替换或者大量变更,需要从API服务器移除现有的Node对象,之后再在更新之后重新将其加入。

3.2 节点自注册

kubelet标志--register-node为**True(默认)**时,它会尝试向API服务注册自己。这是首选模式,被绝大多数发行版使用。

对于自注册模式,kubelet使用以下参数启动:

  • --kubeconfig:用于向API服务器执行身份认证所用的凭据的路径
  • --cloud-provider:与某云驱动进行通信以读取与自身相关的元数据的方式
  • --register-node:自动向API服务器注册
  • --register-with-taints:使用所给的污点列表(逗号分隔的 <key>=<value>:<effect>)注册节点,当register-node为false时无效
  • --node-ip:可选的以英文逗号隔开的节点IP地址列表。只能为每个地址簇指定一个地址。例如:在单协议栈IPv4集群中,需要将此值设置为kubelet应使用的节点IPv4地址。如果没有提供这个参数,kubelet将会使用节点默认的IPv4地址,如果节点没有IPv4地址,则使用节点默认的IPv6地址。
  • --node-labels:在集群中注册节点时需要添加的标签
  • --node-status-update-frequency:指定kubelet向API服务器发送其节点状态的频率

Node鉴权模式NodeRestriction准入插件被启用后,仅授权kubelet创建/修改自己的Node资源

说明:

  1. 由于节点名称唯一性,当Node的配置需要更新时,一种好的做法是:重新向API服务器注册该节点。例如:如果kubelet重启时其--node-labels是新的值,但同一个Node名称已经被使用,则所做变更不会起作用,因为节点的标签是在Node注册时完成的
  2. 如果在kubelet重启期间Node配置发生了变化,已经被调度到某Node上的Pod可能会出现行为不正常或者其他问题。例如:已经运行的Pod可能通过污点机制设置了与Node上新设置的标签相排斥的规则,也有一些其他Pod,本来与此Pod之间存在不兼容问题,也会因为新的标签设置被调度到同一节点。节点重新注册操作可以确保节点上所有的Pod都被排空并且被正确的重新调度

3.3 手动节点管理

可是使用kubectl 来创建和修改Node对象。

如果希望手动创建Node对象,需要设置kubelet标志--register-node=false

可以修改Node对象。如:修改节点上的标签标记为不可被调度
结合使用Node上的标签个Pod上的选择算符来控制调度。如:限制某Pod只能在符合要求的节点子集上运行。

如果 标记节点为不可调度(unschedulable,将阻止新Pod调度到该Node之上,但不会影响任何已经在其上的Pod。这是重启节点或者执行其他维护操作之前的一个有用的准备步骤。

要标记一个Node为不可调度:kubectl cordon $NODENAME

4、节点状态

一个节点的状态包含以下信息:

  1. 地址(Addresses
  2. 状况(Condition
  3. 容量(Capacity)与可分配(Allocatable
  4. 信息(Info

可以通过kubectl来查看节点状态和其他细节信息:
kubectl describe node <节点名称>

4.1 地址(Addresses

这些字段的用法取决于云服务商或者物理机配置

  • hostName:由节点的内核报告。可以通过kubelet的--hostname-override参数覆盖
  • ExternalIP:通常是节点的可外部路由(从集群外可访问)的IP地址
  • InternalIP:通常是节点的仅可在集群内部路由的IP地址。

4.2 状况(Condition

conditions字段描述了所有 running 节点的状况。状况的示例包括:

节点状况描述
Ready取值有三个,True、False、Unknown
True:节点是健康的并且已经准备好接收Pod
False:节点不健康且不能接收Pod
Unknown:表示节点控制器在最近node-monitor-grace-period期间没有收到节点的消息(默认40s)
DiskPressureTrue 表示节点存在磁盘空间压力,即磁盘可用量低,否则为 False
MemoryPressureTrue 表示节点存在内存压力,即节点内存可用量低,否则为 False
PIDPressureTrue 表示节点存在进程压力,即节点上进程过多;否则为 False
NetworkUnavailableTrue 表示节点网络配置不正确;否则为 False

在 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"
  }
]

当节点上出现问题时,kubernetes控制面会自动创建与影响节点状况对应的污点
如:当Ready状况的status保持Unknown或者False的时间长于kube-controller-managerNodeMonitorGracePeriod(默认40秒)时,会造成Unknown状态下为节点添加node.kubernetes.io/unreachable污点或者False状态下为节点添加node.kubernetes.io/not-ready污点

这些污点会影响悬决的Pod,因为调度器在将Pod分配到节点时会考虑节点的污点。已调度到节点的当前Pod可能会由于施加NoExecute污点被驱逐。Pod还可以设置容忍度,使得这些Pod仍然能够调度到且继续运行在设置了特定污点的节点上。

4.3 容量(Capacity)与可分配(Allocatable

这两个值描述节点山的可用资源:CPU、内存、可以调度到节点上的Pod个数上限。

capacity 块中的字段标示节点拥有的资源总量。 allocatable 块指示节点上可供普通 Pod 使用的资源量

4.4 信息(Info)

Info指的是节点的一般信息,如内核版本、kubernetes版本、容器运行时详细信息、以及节点使用的操作系统

kubelet从节点收集这些信息并将其发布到kubernetes API

5、节点心跳

kubernetes节点发送的心跳帮助你的集群确定每个节点的可用性,并在检测到故障时采取行动。

对于节点,有两种形式的心跳:

  • 更新节点的.status
  • kube-node-lease命名空间中的Lease(租约)对象。每个节点都有一个关联的Lease对象。

与节点的.status更新相比,Lease是一种轻量级资源。使用Lease来表达心跳在大型集群中可以减少这些更新对性能的影响。

kubelet负责创建和更新节点的.status,以及更新他们对应的Lease

  • 当节点状态发生变化时,或者在配置的时间间隔内没有更新事件时,kubelet会更新.status.status 更新的默认间隔为 5 分钟(比节点不可达事件的 40 秒默认超时时间长很多)
  • kubelet会创建并每10秒(默认更新间隔时间)更新Lease对象。 Lease的更新独立于节点的.status更新而发生。如果Lease的更新操作失败,kubelet会采用指数回退机制,从 200 毫秒开始重试, 最长重试间隔为 7 秒钟。

6、节点控制器

节点控制器是kubernetes控制面板组件,管理节点的方方面面。

节点控制器在节点的生命周期每扮演多个角色:

  1. 节点注册时为其分配一个CIDR区段(如果启用了CIDR分配)
  2. 保持节点控制器里的节点列表云服务商提供的可用机器列表同步
    如果在云环境下运行,只要某节点不健康,节点控制器就会询问云服务是否节点的虚拟机仍可用。如果不可用,节点控制器会将该节点从他的节点列表中删除。
  3. 监控节点的健康状况
    3.1 在节点不可达的情况下,在Node的 .status中更新Ready状况。在这种情况下,节点控制器将NodeReady状况更新为Unknown
    3.2 如果节点仍然无法访问:对于不可达节点上的所有Pod触发API发起的逐出操作。默认情况下,节点控制器在将节点标记为 Unknown 后等待 5 分钟提交第一个驱逐请求。

默认情况下,节点控制器每 5 秒检查一次节点状态,可以使用 kube-controller-manager 组件上的 --node-monitor-period 参数来配置周期

6.1 逐出速率限制

大部分情况下,节点控制器把逐出速率限制在每秒--node-eviction-rate个(默认为0.1)。这表示他每10秒内至多从一个节点驱逐Pod

当一个可用区域(Availability Zone)中的节点变不健康时,节点的驱逐行为将发生改变。节点控制器会同时检查可用区域中不健康(Ready状况为UnknownFalse)节点的百分比:

  • 如果不健康节点的比例超过--unhealthy-zone-threshold(默认为0.55),驱逐速率将会降低
  • 如果集群较小(小于等于--large-cluster-size-threshold个节点,默认为50),驱逐操作将会停止
  • 否则,驱逐速率将会降为每秒--secondary-node-eviction-rate个(默认为0.01)

在逐个可用区域中实施这些策略的主要原因是:当一个可用区域可能从控制面脱离时其他可用区域可能仍然保持连接。如果你的集群没有跨越云服务商的多个可用区域,那真个集群就只有一个可用区域。

跨多个可用区域部署节点的一个关键原因是:当某个可用区域整体出现故障时,工作负载可以转移到健康的可用区域。因此,如果一个可用区域中的节点都不健康时,节点控制器会以正常的速率(--node-eviction-rate)进行驱逐操作。在所有可用区域都不健康(即整个集群中没有健康节点)的极端情况下,节点控制器将假设控制面与节点间的连接出了某些问题,他将停止所有驱逐动作(如果故障后部分节点重新连接,节点控制器会从剩下的不健康或者不可达的节点中驱逐Pod)

节点控制器还负责驱逐运行在拥有NoExecute污点的节点上的Pod,除非这些Pod能够容忍污点。节点控制器还负责根据节点故障(如不可访问或没有就绪)为其添加污点,这意味着调度器不会将Pod调度到不健康的节点上。

6.2 资源容量跟踪

Node对象会跟踪节点上资源的容量(例如:可用内存和CPU数量)。通过自注册机制生成的Node对象会在注册期间报告自身容量。如果是手动添加Node,需要在添加节点时手动设置节点容量。

kubernetes调度器保证节点上有足够的资源供其上的Pod使用。他会检查节点上所有容器的请求的资源的总和不会超过节点的容量。

总的请求包括由kubelet启动的所有容器,但不包括由容器运行时直接启动的容器,也不包括不受kubectl控制的其他进程

7、节点拓扑

如果启用了topologyManager特性门控,kubelet可以在做出资源分配决策时使用拓扑提示。

8、节点体面关闭

kubelet会尝试检测节点系统关闭事件终止在节点上运行的所有Pod

在节点终止期间,kubelet保证Pod遵从常规的Pod终止流程,且不接受新的Pod(即使这些Pod已经绑定到该节点)

节点体面关闭特性依赖于systemd,因为他要利用systemd 抑制锁机制,在给定的期限内延迟节点关闭。

节点体面关闭受GracefulNodeShutdown特性门控制,在1.21版本中是默认启用的。

注意:默认情况下,shutdownGracePeriodshutdownGracePeriodCriticalPods都是被设置为0的,因此不会激活节点体面关闭功能。要激活此特性,这两个kubelet配置选项要适当配置,并设置为非0值。

一旦systemd检测到或通知节点关闭,kubelet就会在节点上设置一个NotReady状况,并将reason设置为node is shutting down, kube-scheduler会重视此状况,不将Pod调度到受影响的节点上;其他第三方调度程序也应当遵循相同的逻辑。这意味着新的Pod不会被调度到该节点上,因此不会有新Pod启动。

如果检测到节点关闭过程正在进行中,kubelet 也会 在PodAdmission阶段拒绝Pod,即使是该Pod带有node.kuberbetes.io/not-ready:NoSchedule的容忍度。

同时,当kubelet通过API在其Node上设置该状况时,kubelet也开始终止在本地运行的所有Pod

在体面关闭节点过程中,kubelet分两个阶段来终止Pod:

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

节点体面关闭的特性对应两个kubeletConfiguration选项:

  • shutdownGracePeriod:指定节点应延迟关闭的总持续时间,此时间是Pod体面终止的时间总和,不区分常规Pod和关键Pod
  • shutdownGracePeriodCriticalPods:在节点关闭期间指定用于终止关键 Pod 的持续时间。该值应小于 shutdownGracePeriod

注意:在某些情况下,节点终止过程会被系统取消(或者由管理员手动取消),无论那种情况下,节点都会返回到Ready状态。然而,已经开始终止进程的Pod将不会被kubelet恢复,需要被重新调度。

9、处理节点非体面关闭

节点关闭的操作可能无法被kubelet的节点关闭管理器检测到,是因为该命令不会触发kubelet所使用的的抑制锁定机制,或者是因为用户错误的原因(ShutdownGracePeriodShutdownGracePeriodCriticalPod 配置不正确)

当某节点关闭但是kubelet的节点关闭管理器未检测到这一事件的时候,在那个已关闭节点上, 属于 StatefulSet的pod 将停滞于终止状态,并且不能移动到新的运行节点上这是因为:已关闭节点上的kubelet已不存在,亦无法删除pod,因此 StatefulSet无法创建同名的新pod。

如果 pod 使用了卷,则 VolumeAttachments不会从原来已关闭节点上删除,因此 这些pod所使用的卷也不能挂载到新运行的节点上。所以:那些以StatefulSet形式运行的应用无法正常工作

如果原来的已关闭节点被恢复,kubelet将删除pod,新的pod将会在不同的运行节点上被创建、如果原来的已关闭节点没有被恢复,那些在已关闭节点上的pod将永远滞留在终止状态。

为了缓解上述情况,用户可以 手动将具有NoExecuteNoSchedule效果的node.kubernetes.io/out-of-service 污点添加到节点上,标记其无法提供服务

如果在kube-controller-manager上启用了NodeOutOfServiceVolumeDetach特性门控,并且 节点被通过污点标记为无法提供服务,如果节点pod上没有设置对应的容忍度,那么这样的pod将会被强制删除,并且在该节点上被终止的pod将立即进行卷分离操作。这样就允许那些无法提供服务节点上的pod能在其他节点上快速恢复。

在非体面关闭期间,pod分两个阶段终止:

  1. 强制删除没有匹配的out-of-service容忍度的pod
  2. 立即对此类pod执行分离卷操作

说明:

  • 在添加node.kubernetes.io/out-of-service 污点之前,应该验证节点已经处于关闭或断电状态,而不是在重新启动中
  • 将pod移动到新节点后,用户需要手动移除停止服务的污点,并且用户要检查关闭节点是否已恢复,因为该用户是最初添加污点的用户。

10、交换内存管理

要在节点上启用交换内存,必须启用kubelet的NodeSwap特性门控,同时使用 --fail-swap-on命令行参数或者将failSwapOn配置设置为 false

注意:

  • 当内存交换功能被启用之后,kubernetes数据可以被交换到磁盘

用户还可以选择配置memorySwap.swapBehavior以指定节点使用交换内存的方式。
e.g:

memorySwap:
  swapBehavior: UnlimitedSwap
  • UnlimitedSwap(默认):kubernetes工作负载 可以根据请求使用尽可能多的交换内存,一直达到系统限制为止。
  • LimitedSwap:kubernetes工作负载对交换内存的使用受到限制,只有具有Burstable QoS 的 Pod 可以使用交换空间。

如果启用了特性门 但是没有指定memorySwap的配置,默认情况下kubelet将使用与 UnlimitedSwap设置相同的行为。

采用LimitedSwap时,不属于 Burstable Qos分类的pod(BestEffort / Guaranteed Qos pod)被禁止使用交换内存,为了保持上述的安全性和节点的健康性,在LimitedSwap生效时,不允许这些pod使用交换内存。

在介绍交换限制的计算之前,先统一以下数据:

  • nodeTotalMemory:节点上可用的物理内存的总量
  • totalPodSwapAvailable:节点上可供pod使用的交换内存总量(一些交换内存可能会保留供系统使用)
  • containerMemoryRequest :容器的内存请求

交换限制被配置为:(containerMemoryRequest / nodeTotalMemory) * totalPodsSwapAvailable 的值。

需要注意:位于 Burstable QoS Pod 中的容器可以通过将内存请求设置为与内存限制相同来选择不使用交换空间。 以这种方式配置的容器将无法访问交换内存

Logo

K8S/Kubernetes社区为您提供最前沿的新闻资讯和知识内容

更多推荐