K8s 笔记 (II)

集群架构

Jacob Xie published on
38 min, 7511 words

Categories: Read

Tags: k8s

节点

k8s 通过放置容器进入 Pods 运行在节点上从而运行负载。一个节点可能是虚拟的或者是物理机器,这取决于集群。每个节点都是通过控制面进行管理,并且包含了运行在 Pods 的服务。

一个节点的组件包含了 kubelet,一个容器运行时,以及一个 kube-proxy。

节点管理

有两种主要的方法用于添加节点至 API 服务:

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

创建节点对象后,控制面会检查该节点是否可用。例如,如果尝试通过以下 JSON 创建一个节点:

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

k8s 创建一个内部的节点对象,接着检查一个在 API 服务上注册过的 kubelet 是否匹配节点的 metadata.name 字段。如果该节点是健康的(例如所有的服务都在运行),那么它可以运行一个 pod。否者该节点会被任何集群的行动所忽略,直到该节点恢复健康。

说明:

k8s 会保留不可用节点的对象以及持续检查该节点是否恢复健康。用户或者控制器需要显式的删除节点对象以便停止健康检查。

名称用于标识节点,在同一时刻下不可以有两个相同名称的节点。k8s 同样也假设拥有同一名称的资源是同一个对象。

当 kubelet 标记 --register-node 为真时(即默认),kubelet 会尝试通过 API 服务进行自注册。这是首选的模式,大多数版本都会这样。

关于自注册,kubelet 有下面几个选项:

  • --kubeconfig:用于向 API 服务器执行身份认证所用的凭据的路径。
  • --cloud-provider:与与驱动进行通信以读取与自身相关的元数据的方式。
  • --register-node:自动向 API 服务注册。
  • --register-with-taints:使用所给的污点列表(逗号分隔的 <key>=<value>:<effect>)注册节点。当 register-node 为 false 时无效。
  • --node-ip:节点 IP 地址。
  • --node-labels:在集群注册节点时所添加的标签。
  • --node-status-update-frequency:制定 kubelet 向控制面发生状态的频率。

也可以使用 kubectl 来手动创建和修改 Node 对象,这时需要设置 --register-node=false

节点状态

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

  • 地址
  • 条件
  • 容量与分配
  • 信息

可以使用 kubectl 查看节点状态以及其他细节:

kubectl describe node <insert-node-name-here>

地址这个字段的使用取决于云服务商或者物理机的配置:

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

conditions 字段描述了所有 Running 节点的状态。例如状态包括:

节点条件描述
ReadyTrue 如果节点是健康的并且准备接受 pods,False 如果节点是不健康的以及未接受 pods,以及 Unknown 如果节点控制器在节点的最后 node-monitor-grace-period (默认为 40 秒)上没有获得相应
DiskPressureTrue 如果磁盘大小存在压力,也就是说空间很小;否者 False
MemoryPressureTrue 如果节点内存存在压力,也就是说节点内存不足;否者 False
PIDPressureTrue 如果进程存在压力,也就是说有太多的进程在此节点上了;否者 False
NetworkUnavailableTrue 如果节点的网络没有被正确的配置;否者 False

说明:

如果使用命令行工具打印已保护(Cordoned)节点的细节,其中的条件字段可能包括 SchedulingDisabled。它不是 k8s API 定义的条件,被保护起来的节点在其规则中被标记为不可调度(Unschedulable)。

在 k8s 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 一直保持着 Unknown 或是 False 状态,并超过了 pod-eviction-timeout(即传给 k8s 控制器管理者 kube-controller-manager 的一个参数),那么节点控制器触发 API 发起的驱逐。默认的驱逐超时时长为 5 分钟。某些情况下当一个节点不可获取时,API 服务不能与节点的 kubelet 进行交互。那么删除节点的决策不能传递给 kubelet 直到 API 服务重新被连接。在此期间,被计划删除的 pods 可能会继续在部分节点上运行。

节点控制器不会强制删除 pods 直到它确认了它们被集群停止运行。用户有可能会看到 pods 运行在一个标记为 TerminatingUnknown 状态的不可获取的节点上。为了以防万一 k8s 在一个节点永久离开集群时,不能由下层基础设施推断出来,集群管理者可能需要手动删除该节点对象。从 k8s 删除节点对象会导致所有运行在节点的 Pod 从 API 服务中删除,同时释放它们的名称。

当节点出现问题时,k8s 控制面会为收到影响的节点们自动的创建污点。当需要分配 pod 给节点时,调度器则会考虑到这些污点。Pod 也可以设置容忍度,使得在设置了特定污点的节点上运行。

容量 capacity 与可分配 allocatable 这两个值描述了节点上的可用资源:CPU,内存,以及可用于调度给节点的最大 pods 数。“容量”的字段代表着一个节点的整体资源;“可分配”的字段代表着一个节点可被消费的整体资源。

信息 info 描述了节点的信息,例如内核版本,k8s 版本(kubelet 与 kube-proxy 的版本),容器运行时的细节,以及节点所使用的操作系统。kubelet 从节点中收集了这些信息并发布进 k8s API。

心跳

心跳,由 k8s 节点发送,帮助集群控制各个节点的可用性,以及对于失败做出相应的动作。对于节点而言,有两种形式的心跳:

  • 更新节点的 .status
  • kube-node-lease 命名空间内租借 lease 对象。每个节点都有一个关联的租借对象。

相比于更新节点的 .status,Lease 是一个轻量级的资源。对于大型集群而言,通过 leases 可以减少更新所带来的性能影响。

kubelet 负责创建与更新节点的 .status,同时也更新这些节点所关联的 lease。

  • kubelet 会在节点状态变化或者配置的时间区间没有更新时,更新节点的 .status。默认的节点更新 .status 的时间区间为 5 分钟,远比 40 秒的不可获取节点的默认时间要长。
  • kubelet 会每隔 10 秒(默认的更新时间区间)创建并更新 lease 对象。lease 的更新独立与节点 .status 的更新。如果 lease 更新失败,kubelet 会使用指数回退机制,从 200 毫秒开始重试,最长重试间隔为 7 秒钟。

节点控制器

节点控制器是 k8s 控制面中用于在多个层面上进行节点管理的组件。其在节点的生命周期中担任了多个角色。首先是当节点被注册是指定 CIDR 区段(如果开启了 CIDR 分配)。其次是维护控制器的内部节点列表与云服务商所提供的可用机器列表同步。如果在云环境下运行,只要某个节点不健康,节点控制器就会询问云服务节点的虚拟机是否仍然可用。如果不可用,节点控制器会将该节点从节点列表中删除。再者是监控节点的健康状况,负责以下:

  • 在节点不可获取的情况下,在节点的 .status 中更新 Ready 的状态并改为 Unknown
  • 如果节点仍然无法访问,对于不可获取的节点上的所有 Pod 触发 API 发起的驱逐操作。默认情况节点控制器在将节点标记为 Unknown 后等待 5 分钟后提交第一个驱逐请求。

资源容量追踪

节点对象追踪节点资源容量的信息:比如可用的内存与 CPU 的数量。通过自注册机制生成的节点对象会在注册期间报告自身容量。如果是手动的添加节点,那么也需要手动的设置节点容量。k8s 调度器保证节点上有足够的资源提供给所有的 pod 使用。它会检查节点上所有容器的请求的总和不会超过节点的容量。中的请求包括由 kubelet 启动的所有容器,但不包括容器运行时直接启动的容器,也不包括不受 kubelet 控制的其它进程。

节点的优雅关闭

特性状态v1.21 [beta]

kubelet 会尝试检测节点系统的关闭以及终止在节点上运行的 pods,并确保 pods 遵从 pod 终止流程。优雅关闭依赖于 systemd,因为利用了 systemd 的抑制器锁机制,在给定的期限内延迟节点关闭。优雅关闭这个特性受 GracefulNodeShutdown 控制门所控制,在 1.21 版本中是默认启用的。注意在默认情况下,下面描述的两个配置选项 shutdownGracePeriodshutdownGracePeriodCriticalPods 的设置都为 0。因此不会激活节点优雅关闭功能。要激活该功能特性,这两个 kubelet 配置选项要适当配置,并设置为非零值。

在优雅关闭节点的过程中 kubelet 分两个阶段来终止 Pod:

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

优雅关闭的特性对应两个 KubeletConfiguration 选项:

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

节点的非优雅关闭

特性状态v1.24 [alpha]

一个节点的关闭可能不会被 kubelet 的节点管理所监控,这有可能是因为命令没有触发 kubelet 使用的抑制器锁机制或是因为一个用户的错误,例如 shutdownGracePeriodshutdownGracePeriodCriticalPods 没有被正确的配置。

当节点的关闭并没有被 kubelet 管理所监控时,StatefulSet 部分的 pods 会停滞在终止的状态中,并且不能移动至新的节点上。这是因为 kubelet 在关闭的节点上不能删除 pods,因此 StatefulSet 不能创建同名的新 pod。如果 pods 还用到了 volume,那么 VolumeAttachments 也不会在原有节点上被删除,因此这些 pods 所使用的 volumes 也不能被挂载到新的运行的节点上。因此 StatefulSet 上运行的应用程序不能正常工作。如果原来的已关闭节点被恢复,kubelet 将删除 Pod,新的 Pod 将在不同的运行节点上创建。如果原来的已关闭节点没有被恢复,那些在已关闭节点上的 Pod 将永远停滞在终止状态。

为了缓解上述状况,用户可以手动将 NoExecute 或者 NoSchedule 效果的 node kubernetes.io/out-of-service 污点添加到节点上,标记其无法提供服务。如果在 kube-controller-manager 上启用了 NodeOutOfServiceVolumeDetach 特性门控,并且节点被标记污点,同时如果节点 Pod 上没有设置对应的容忍度,那么这样的 Pod 将会被强制删除,并且 Pod 的 volume 会被立刻分离。这可以让在无法服务的节点上的 Pods 快速在另一个节点上恢复。

在非优雅关闭节点过程中,Pod 分两个阶段终止:

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

内存交换管理

特性状态v1.22 [alpha]

在 1.22 版本之前 k8s 不支持交换内存,如果在一个节点上检查到交换 kubelet 则默认会启动失败。在 1.22 版本之后,可以逐个节点启用交换内存支持。要在节点上启用交换内存,必须启用 kubelet 的 NodeSwap 特性门控,同时使用 --fail-swap-on 命令行参数或者将 failSwapOn 配置设置为 false。用户还可以选择配置 memorySwap.swapBehavior 来指定交换内存的方式,例如:

memorySwap:
  swapBehavior: LimitedSwap

节点与控制面的通信

本文档说明 API 服务与 k8s 集群的通信路径。目的是为了让用户能够自定义安装,实现对网络配置的加固,使得集群能够在不可信的网络上(或者一个云服务商完全公开的 IP 上)运行。

节点到控制面

k8s 采用的是中心辐射型 Hub-and-Spoke API 模式。所有从节点(或运行的 Pod)发出的 API 调用都终止于 API 服务器。其它控制面组件都没有被设计为可暴露远程服务。API 服务器被配置在一个安全的 HTTPS 端口(通常为 443)上监听远程连接请求,并启用一种或多种形式的客户端身份认证机制。客户端的鉴权机制应该被启用,特别是在允许使用匿名请求或服务账户令牌时。

节点应该被预先分配集群的公共根证书,这样它们可以通过合法的客户认证安全连接到 API 服务。一个良好的实现是以客户端证书的形式将客户端凭据提供给 kubelet。

想要连接到 API 服务器的 Pod 可以使用服务账号安全的进行连接。当 Pod 被实例化时,k8s 自动把公共根证书和一个有效的持有者令牌注入到 Pod 里。kubernetes 服务(位于 default 命名空间内)配置了一个虚拟 IP 地址,用于(通过 kube-proxy)转发请求到 API 服务器的 HTTPS 末端。

控制面组件控制面也通过安全端口与集群的 API 服务器通信。从集群节点和节点上运行的 Pod 到控制面的连接的默认操作模式是安全的,能够在不可信的网络或公网上运行。

控制面到节点

控制面(API 服务)到节点主要有两种通信路径。第一种是从 API 服务到集群上每个节点上的 kubelet 进程;第二种是 API 服务通过自身的 proxy 功能到任意节点,pod 或者服务。

API 服务到 kubelet

用于:

  • 获取 Pod 日志
  • 挂接(通过 kubectl)到运行中的 Pod
  • 提供 kubelet 的端口转发功能

这些连接终止于 kubelet 的 HTTPS 末端。默认情况下,API 服务器不检查 kubelet 的服务证书。这使得此类连接容易受到中间人攻击,在非授信网络或公开网络上运行也是不安全的。为了对连接进行认证,使用 --kubelet-certificate-authority 标志给 API 服务器提供一个根证书包,用于 kubelet 的服务证书。最后应该启用 kubelet 用户认证和/或鉴权来保护 kubelet API。

API 服务到节点,pods 和服务

从 API 服务器到节点,Pod 或服务的默认连接为纯 HTTP 方式,既没有认证,也没有加密。这些连接可通过给 API URL 中的节点,Pod 或服务器名称添加前缀 https: 来运行在安全的 HTTPS 连接上。不过这些连接既不会验证 HTTPS 末端提供的证书,也不会提供客户端证书。因此连接虽然是加密的,仍然无法提供任何完整性的保证。这些连接目前还不能安全的在非授信网络或公共网络上运行。

Konnectivity 服务

特性状态v1.18 [beta]

作为 SSH 隧道的替代方案,Konnectivity 服务提供 TCP 层的代理,支持从控制面到集群的通信。Konnectivity 服务包含两个部分:Konnectivity 服务器和 Konnectivity 代理, 分别运行在控制面网络和节点网络中。 Konnectivity 代理建立并维持到 Konnectivity 服务器的网络连接。 启用 Konnectivity 服务之后,所有控制面到节点的通信都通过这些连接传输。

控制器

在自动化中,控制回路是一个非终止的循环用于调节系统的状态。例如一个房间里的恒温控制器就是一个控制回路的例子。当设置温度时,即告诉恒温器期望状态,而室内实际温度则是当前状态。恒温器则会通过关闭或打开设备,使当前状态调整靠近至期望状态。k8s 中,控制器监控集群的状态,让后在需要的地方进行或请求更改。每个控制器都会尝试使当前的集群状态接近期望的状态。

控制器模式

控制器追踪至少一种 k8s 的资源类型。这些对象都有一个代表期望状态的 spec 字段。这些资源的控制器负责使当前状态接近理想状态。控制器可能自身就携带了这些行为;通常来说在 k8s 中,控制器将会发送信息至 API 服务。

通过 API 服务控制

Job 控制器是 k8s 内建的控制器,其通过与 API 服务的互动来管理状态。Job 是运行在一个或多个 Pod 上的 k8s 资源,用于执行一个任务然后停止。(一旦被调度,Pod 对象会变成一个 kubelet 的期望状态的一部分)。当 Job 控制器在集群中看到一个新的任务则会确保若干节点的 kubelet 运行正确数量的 Pods 来完成任务。Job 控制器自身不会运行任何 Pods 或者容器,而是告诉 API 服务来创建或者移除 Pods。控制面中的其他组件会根据这些信息进行工作,最终使得任务被完成。在创建一个新的 job 后,期望状态则是 Job 完成后的状态。Job 控制器则会使当前状态不断接近期望状态,通过:创建为 Job 要完成工作所需要的 Pods 使得 Job 的状态接近完成。控制器也会更新配置对象,例如:一旦 Job 的工作完成了,Job 控制器会更新 Job 对象的状态为 Finished。(这就像温度调节器关闭了一个灯,以此来告诉你房间的温度现在达到设定的值了)。

直接控制

不同于 Job,一些控制器需要直接修改集群外的东西。例如,如果使用控制回路来确认集群中有足够多的节点,那么控制器需要在当前集群外的东西来确认是否需要设置新的节点。用于交互外部状态的控制器通过 API 服务寻找它们的期望状态,接着直接与外部系统交流并使当前状态靠近期望状态。(实际上在集群里有一个进行水平扩展节点的控制器)。这里有很重要的一点,控制器做出了一些改变使得事物更接近期望的状态,之后将当前状态报告给集群的 API 服务器。其他控制回路可以观察到汇报数据的变化,并采取各自的行动。在温度计的例子中,如果房间很冷,那么某个控制器可能会启动一个防冻的加热器。对于 k8s 集群而言,控制面间接与 IP 地址管理工具,存储服务,云驱动 APIs 以及其他服务协作,通过扩展 k8s 来实现。

期望状态与当前状态

k8s 采用系统的云原生视图,可以处理持续的变化。在任务执行时,集群随时都可能被修改,控制回路则会自动修复故障。这以为着集群永远不会达到稳定的状态。只要集群中的控制器在运行并且进行有效的修改,整体状态的稳定便是无关紧要的。

设计

作为设计的一个原则,k8s 使用了大量的控制器,它们每一个都管理集群状态的一个特定方面。通常而言,一个特定的控制回路(控制器)使用一种资源作为其预期状态,同时管理控制另一种类型的资源向它的预期状态演化。例如,一个 Job 控制器追踪 Job 对象 (用于发现新工作)以及 Pod 对象(用于运行 Jobs,并观察工作何时结束)。这个情况下,其余的事物创建 Jobs,而 Job 控制器创建 Pods。使用简单的控制器而不是一组互相连接的单体控制回路是很有用的。控制器会失败,所以 k8s 的设计正式考虑到了这一点。

说明:

可以有多个控制器来创建或者更新相同类型的对象。在后台 k8s 控制器确保它们只关心与其控制资源相关联的资源。

例如,你可以创建 Deployment 和 Job;它们都可以创建 Pod。Job 控制器不会删除 Deployment 所创建的 Pod,因为有信息(标签)让控制器可以区分这些 Pod。

运行控制器的方法

k8s 内置了一组控制器运行在 kube-controller-manager 内。这些内置的控制器提供了重要的核心功能。Deployment 控制器和 Job 控制器是 k8s 内置控制器的典型例子。k8s 允许运行一个稳定的控制面,这样即使某些内置控制器失败了,控制面的其他部分会接替它们的工作。有些控制器运行在控制面之外,用于扩展 k8s。如果愿意的话,用户可以编写一个新的控制器。运行该控制器作用于一系列的 Pods,或者运行在 k8s 之外。最合适的方案取决于控制器所要执行的功能是什么。

容器运行时接口

容器运行时接口 Container Runtime Interface (CRI) 是一个插接接口,使得 kubelet 能够使用不同种类的容器运行时。用户需要在集群的每个节点上都运行一个容器运行时,这样 kubelet 可以加载 Pods 以及其容器。容器运行时接口 CRI 是 kubelet 与容器运行时通讯的主要协议,同时定义了集群组件与容器运行时通讯的主要 gRPC 协议。

API

特性状态v1.23 [stable]

当通过 gRPC 连接到容器运行时的时候,kubelet 作为客户端。运行时和镜像服务端点必须在容器运行时中可用,可以使用命令行标志的 --image-service-endpoint--container-runtime-endpoint 在 kubelet 中单独配置。

升级

升级 k8s 时,kubelet 会尝试在组件重启时自动选择最新的 CRI 版本。如果失败,则会回退。如果因为容器运行时已经升级而需要 gRPC 重拨,那么容器运行时还必须支持最初选择的版本,不然重拨会失败。这就需要重新启动 kubelet 了。

垃圾收集

垃圾收集是一个概括性的概念用于描述 k8s 各种机制下的集群资源清理。例如:

  • 失败的 pods
  • 完成的 jobs
  • 没有属主的对象
  • 无用的容器以及容器的镜像
  • 动态制备的,StorageClass 回收策略为 Delete 的 持久化卷 (PersistentVolumes)
  • 失效或者过期的证书登录请求 CertificateSigningRequests CSRs
  • 以下场景下删除的节点:
    • 在云上的集群使用云控制管理
    • 本地集群使用一个类似于云控制器的插件
  • 节点租约对象

属主与依赖

k8s 的很多对象通过属主引用 owner references来连接彼此。属主引用告诉控制面哪些对象依赖其它对象。k8s 通过属主引用给予了控制面以及其他 API 客户端用于在删除一个对象之前清理其相关资源的能力。多数情况下,k8s 会自动管理自身的引用。

一些资源同样也会使用异于标签和选择器机制的所有权。例如假设一个服务创建了 EndpointSlice 对象,使用了标签允许控制面来决定哪个 EndpointSlice 对象服务于该服务。除了标签,每个被服务托管的 EndpointSlice 对象还有一个属主引用属性。属主引用帮助 k8s 中的不同组件避免干预并非由它们控制的对象。

说明:

在设计上,跨命名空间的属主引用是不被允许的。命名空间的依赖可以指定集群作用域或者命名空间作用域的属主。命名空间作用域的属主必须存在于依赖对象所在的同一命名空间。如果没有,属主引用则被视为缺失,当检查发现属主不存在时,依赖对象则会被删除。

级联删除

k8s 检查并删除不再拥有属主引用的对象,像是删除一个 ReplicaSet 后留下的 pods。当删除一个对象,可以通过一个称为级联删除 cascading deletion的步骤来控制 k8s 是否自动删除对象的依赖。有两种级联删除的方式:

  • 前台级联删除
  • 后台级联删除

同样的也可以控制垃圾收集如何与何时删除拥有属主引用的资源。

前台级联删除

在前台级联删除中,删除属主对象时会进入一个正在删除的状态。这个状态下,在属主对象上会出现:

  • k8s API 服务设置对象的 metadata.deletionTimestamp 字段为对象要删除的时间点。
  • k8s API 服务同样设置 metadata.finalizers 字段成 foregroundDeletion
  • 通过 k8s API,对象一直保持可见,直到删除过程完成。

在属主对象进入正在删除的状态之后,控制器会删除其依赖。删除完所有的依赖对象后,控制器删除属主对象。这时,对象在 k8s API 上不再可见。

在前台级联删除时,唯一会阻塞属主删除的依赖都会拥有 ownerReference.blockOwnerDeletion=true 字段。

后台级联删除

在后台级联删除中,k8s API 服务会立刻删除属主对象,接着管理器在后台清除其依赖对象。默认情况下,k8s 使用后台级联删除,除非用户手动使用前台删除或者选择孤儿化依赖对象。

孤儿依赖

当 k8s 删除一个属主对象,被留下的依赖被称为孤儿对象。默认情况下,k8s 会删除依赖对象。

未使用的镜像和垃圾收集

kubelet 会每五分钟在未使用的镜像上以及每一分钟在未使用的容器上执行垃圾收集。用户应当避免使用外部的垃圾收集工具,这将会破坏 kubelet 的行为,移除理应保留的容器。

要配置对未使用容器和镜像的垃圾收集选项,可以使用一个配置文件,给予 KubeletConfiguration 资源类型来调整与垃圾收集相关的 kubelet 行为。

容器镜像生命周期

k8s 通过镜像管理器来管理所有镜像的生命周期。镜像管理器作为 kubelet 的一部分,工作时与 cadvisor 协同。kubelet 在做出垃圾收集的决定时会考虑到磁盘使用的约束:

  • HighThresholdPercent
  • LowThresholdPercent

磁盘使用超过配置 HighThresholdPercent 值时会触发垃圾收集,垃圾收集器会基根据镜像上次被使用的时间进行顺序删除,首先删除最老的镜像。kubelet 会持续删除镜像,直到磁盘使用到达 LowThresholdPercent 值。

容器垃圾收集

kubelet 会根据以下用户可以定义的变量来进行对未使用的容器垃圾收集:

  • MinAge:kubelet 可以垃圾收集某个容器时该容器的最小时长。设置 0 标识禁止使用此规则。
  • MaxPerPodContainer:每个 Pod 可以包含的已死亡的容器个数上线。设置小于 0 的值禁止使用此规则。
  • MaxContainers:集群中可以存在的已死亡的容器个数上限。设置小于 0 的值禁止使用此规则。

除了上述变量,kubelet 垃圾收集无标识以及被删除的容器,通常由最老的开始。

当保持每个 Pod 的最大数量容器(MaxPerPodContainer)会使全局的已死亡容器个数超出上限(MaxContainers)时,MaxPerPodContainerMaxContainers 可能存在潜在的冲突。这种情况下,kubelet 会调整 MaxPerPodContainer 来解决冲突。最坏的情况是将 MaxPerPodContainer 降为 1,并驱逐最老的容器。此外,当属于某已删除的 Pod 的容器的年龄超过 MinAge 时,它们也会被删除。

说明:

kubelet 仅会回收由它管理的容器。

配置垃圾收集

用户可以通过配置特定于管理资源的控制器来调整资源的垃圾收集行为: