架构14-资源与调度
1、资源模型
(1)概述
- 在 Kubernetes 中,资源模型是一个非常重要的概念,它涉及如何管理和分配集群中的资源,以确保 Pod 能够在最合适的节点上运行。
- 资源模型不仅包括物理资源,如处理器、内存、存储和网络资源,还包括各种抽象资源,如策略、依赖、权限等。
(2)广义资源 vs 狭义资源
- **广义资源:**Kubernetes 系统中所有你能接触的方方面面,都被抽象成了资源。例如:
- **工作负荷资源:**Pod、ReplicaSet、Service 等。
- **存储资源:**Volume、PersistentVolume、Secret 等。
- **策略资源:**SecurityContext、ResourceQuota、LimitRange 等。
- **身份资源:**ServiceAccount、Role、ClusterRole 等。
- **狭义资源:**特指能够与真实物理底层硬件对应起来的资源,如处理器资源、内存资源、磁盘存储资源等。
(3)物理资源
- 资源单位
- 处理器资源:
- 默认计量单位是"逻辑处理器的个数"。
- 如果不明确标注单位,直接写 0.5,默认单位是 Core,即 0.5 个处理器。
- 也可以明确使用 Millcores 为单位,例如 500 m,同样代表 0.5 个处理器,因为 1 Core = 1000 Millcores。
- 内存资源:
- 默认计量单位是 Bytes。
- 为了实际设置的方便,Kubernetes 还支持以 Ei、Pi、Ti、Gi、Mi、Ki 以及 E、P、T、G、M、K 为单位。
- 例如,Mi 表示 Mebibytes(1024×1024 Bytes),M 表示 Megabytes(1000×1000 Bytes)。
- 资源类型
- **可压缩资源:**如处理器资源,当资源不足时,Pod 只会处于"饥饿状态",运行变慢,但不会被系统杀死。
- **不可压缩资源:**如内存资源,当资源不足或超过容器声明的最大限度时,Pod 会被系统直接杀掉(Out-Of-Memory, OOM)。
(4)资源需求与配额
- **资源需求:**通过
spec.containers[].resources.requests
字段设置,用于告诉调度器 Pod 需要多少资源。
- **资源配额:**通过
spec.containers[].resources.limits
字段设置,用于告诉 cgroups Pod 最多可以使用多少资源。
2、服务质量与优先级
(1)概述
- 在 Kubernetes 中,为了更好地管理和分配集群资源,确保重要服务的稳定性和资源利用率的最大化,引入了服务质量(Quality of Service, QoS)和优先级(Priority)两个重要概念。
(2)服务质量(QoS)
- 服务质量是 Pod 的一个隐含属性,用于衡量 Kubernetes 在资源紧张时优先保障哪些 Pod 的运行。
- Kubernetes 目前提供了三个级别的服务质量,由高到低分别为:
- Guaranteed
- **定义:**Pod 中所有容器都设置了
limits
和 requests
,且两者的值相等。
- **特点:**这类 Pod 的资源需求非常明确,Kubernetes 会尽力保证它们的资源需求得到满足。除非 Pod 使用超过了它们的
limits
所描述的不可压缩资源,或者节点的内存压力大到 Kubernetes 已经杀光所有等级更低的 Pod 了,否则它们都不会被系统自动杀死。
- **适用场景:**适合数据库应用等有状态的应用,或者是一些重要的、要保证不能中断的业务。
- Burstable
- **定义:**Pod 中有部分容器的
requests
值小于 limits
值,或者只设置了 requests
而未设置 limits
。
- **特点:**这类 Pod 有一定的灵活性,可以在资源充足时使用更多的资源,但在资源紧张时可能会被系统降低优先级。
- **适用场景:**适合大多数中间件服务,如缓存服务、消息队列等。
- BestEffort
- **定义:**Pod 中没有任何容器设置了
limits
和 requests
。
- **特点:**这类 Pod 可以使用节点上所有可用的计算资源,但也是最不稳定的风险来源。在资源紧张时,它们最容易被系统杀掉。
- **适用场景:**适合临时的、不那么重要的任务,如批处理任务、临时测试环境等。
(3)优先级(Priority)
- 优先级允许系统管理员自行决定 Pod 的优先级,通过类型为
PriorityClass
的资源来实现。优先级不仅影响 Pod 的调度顺序,还会影响 Kubernetes 的抢占机制。
- 调度影响
- **高优先级 Pod:**在多个 Pod 同时被调度时,高优先级的 Pod 会优先被调度。
- **低优先级 Pod:**越晚被调度的 Pod,越大概率地会因节点资源已被占用而不能成功。
- 抢占机制(Preemption)
- **定义:**当一个设置了明确优先级的 Pod 调度失败时,Kubernetes 会在系统中寻找出一批牺牲者(Victims),把它们杀掉以便给更高优先级的 Pod 让出资源。
- **原则:**在优先级低于待调度 Pod 的所有已调度的 Pod 里,按照优先级从低到高排序,从最低的杀起,直至腾出的资源可以满足待调度 Pod 的成功调度为止,或者已经找不到更低优先级的 Pod 为止。
3、驱逐机制
(1)概述
- 在 Kubernetes 中,驱逐机制是一种重要的资源管理手段,用于确保节点上的资源在紧张时能够合理分配,防止因为资源耗尽而导致整个节点或关键服务崩溃。
- 驱逐机制由
kubelet
负责执行,kubelet
是部署在每个节点上的集群管理程序,能够实时监控节点的资源使用情况。
(2)驱逐机制的触发条件
- 驱逐机制主要针对不可压缩资源,如内存、磁盘空间、文件系统 inode 数量等。当这些资源即将耗尽时,
kubelet
会触发驱逐操作。具体的触发条件如下:
- 内存:
- 磁盘空间:
- 文件系统 inode 数量:
- 容器运行时镜像存储空间:
- 这些阈值可以通过
kubelet
的命令行参数进行调整,例如:
shell
复制代码
--eviction-hard=memory.available<100Mi,nodefs.available<10%,nodefs.inodesFree<5%,imagefs.available<15%
(3)驱逐机制的类型
- 软驱逐
- 软驱逐通常配置一个较低的警戒线,当资源使用率达到这个警戒线时,系统会进入一段观察期。如果资源在观察期内恢复正常,就不会启动驱逐操作。如果资源持续超过警戒线一段时间,系统会触发 Pod 的优雅退出(Graceful Shutdown),通知 Pod 进行必要的清理工作,然后自行结束。如果在优雅退出期结束后,Pod 仍未自行终止,系统会强制杀掉 Pod。
- 例如:
shell
复制代码
--eviction-soft=memory.available<200Mi
--eviction-soft-grace-period=memory.available=30s
--eviction-max-pod-grace-period=120
- 硬驱逐
- 硬驱逐通常配置一个较高的终止线,一旦资源使用率达到这个终止线,系统会立即强制杀掉 Pod,不理会优雅退出。
- 例如:
shell
复制代码
--eviction-hard=memory.available<100Mi
(4)驱逐机制的执行流程
- 资源监控:
kubelet
持续监控节点的资源使用情况。
- **触发条件判断:**当资源使用率达到软驱逐或硬驱逐的阈值时,触发驱逐操作。
- 选择驱逐目标:
kubelet
会选择服务质量等级(QoS)较低的 Pod 进行驱逐。
- **优雅退出:**对于软驱逐,系统会通知 Pod 进行优雅退出。
- **强制终止:**如果 Pod 在优雅退出期内未自行终止,系统会强制杀掉 Pod。
- **资源释放:**被驱逐的 Pod 被终止后,其占用的资源会被释放。
(5)驱逐机制的注意事项
- **资源抖动:**资源使用率可能会出现短暂的波动,因此软驱逐机制可以帮助减少因资源抖动导致的频繁驱逐。
- **资源预留:**驱逐机制不仅要考虑当前资源的释放,还要为新 Pod 的调度和旧 Pod 的运行预留足够的资源。
- **参数配置:**合理的配置驱逐参数可以避免资源浪费和不必要的服务中断。
- **特殊 Pod 处理:**对于由
DaemonSet
等管理的 Pod,需要特别注意驱逐后的重新调度问题,避免出现"阴魂不散"的情况。
4、 默认调度器
(1)概述
- Kubernetes 的默认调度器是负责将新创建的 Pod 分配到合适的节点上运行的关键组件。调度器的设计旨在高效地处理大规模集群中的资源分配问题,同时确保服务的稳定性和资源的充分利用。
(2)调度流程
- 调度器的工作流程可以分为两个主要的控制循环:Informer Loop 和 Scheduler Loop 。
- Informer Loop
- **作用:**持续监视 etcd 中与调度相关资源(主要是 Pod 和 Node)的变化情况。
- 具体操作:
- **Pod 变化:**当有新 Pod 生成时,将其入队(Enqueue)到调度队列中。
- **Node 变化:**当有新的节点加入集群或已有的节点资源信息发生变动时,更新调度缓存中的信息。
- **Scheduler Loop **
- **作用:**从调度队列中取出 Pod,使用 Predicate 和 Priority 算法进行节点选择和评分,最终确定目标节点。
- 具体步骤:
- **出队:**从调度队列中取出一个 Pod。
- **Predicate 筛选:**使用一组节点过滤器(Filter)筛选出符合要求的节点。
- **通用过滤策略:**检查节点是否满足 Pod 声明中需要的资源。
- **卷过滤策略:**检查节点挂载的 Volume 是否存在冲突。
- **节点过滤策略:**检查节点的污点与容忍度机制。
- **Priority 评分:**对筛选出的节点进行评分,选择得分最高的节点。
- **LeastRequestedPriority:**选择处理器和内存空闲资源最多的节点。
- **BalancedResourceAllocation:**选择资源分配最均衡的节点。
- **绑定:**更新 Pod 的 nodeName 字段为目标节点的名字,通知目标节点的 kubelet 创建 Pod。
(3)调度缓存
- **作用:**作为两个控制循环的共享状态,避免调度器每次调度时主动轮询所有集群节点,提高调度器的执行效率。
- **局限:**不能完全避免因节点信息同步不及时导致的资源变化情况,因此在 kubelet 创建 Pod 前还需要进行二次确认(Admit 操作)。
(4)乐观绑定
- **作用:**提高调度器的效率,避免等待 kubelet 完成 Pod 创建后再宣告调度成功。
- 具体操作:
- **同步更新:**在调度缓存中更新 Pod 的 nodeName 字段。
- **异步更新:**在 etcd 中更新 Pod 的 nodeName 字段。
- **失败处理:**如果调度失败,由 Informer 根据 Pod 的变动,将调度成功但未创建成功的 Pod 清空 nodeName 字段,重新同步回调度缓存中。
(5)扩展性
- **Scheduler Framework:**通过暴露扩展点(如 Predicate、Priority 等),允许用户自定义调度逻辑。
- **实现方式:**通过 Golang 的 Plugin 机制实现,需静态编译,属于高级的 Kubernetes 管理技能。
(6)关键概念
- **服务质量(QoS):**Pod 的隐含属性,分为 Guaranteed、Burstable 和 BestEffort 三级。
- **优先级(Priority):**通过 PriorityClass 资源实现,影响 Pod 的调度顺序和抢占机制。
- **驱逐机制(Eviction):**当节点资源不足时,根据 QoS 和优先级选择牺牲的 Pod,以保证重要服务的稳定。