Kubernetes 漫游:kube-scheduler
概述
什么是 kube-scheduler ?
Kubernetes 集群的核心组件之一,它负责为新创建的 Pods 分配节点。它根据多种因素进行决策,包括:
- 资源需求和限制:考虑每个 Pod 请求的资源量(如 CPU 和内存)以及节点上可用的资源。
- 亲和性和反亲和性规则:根据 Pod 的亲和性设置选择最适合的节点。
- 健康检查:确保选择的节点健康且能够运行 Pod。
- 负载均衡:尽量平衡集群中各个节点的负载。
使用
limits 和 reuqests
在部署对象中的 spec 中常常会见到关于 limits
和 requests
的声明 ,例如:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
resources:
limits:
memory: 1Gi
cpu: 1
requests:
memory: 256Mi
cpu: 100m
这里的 limits 和 requests 是与 Pod 容器资源管理相关的两个关键概念:
- Limits:指定容器运行时能够使用的最大资源量
- Requests:指定容器启动时最低需要的资源量
limits 和 requests 跟 scheduler 有什么关系 ?
在集群中 kube-scheduler 一直是默默无闻的幕后工作者,它主要工作内容如下:
- 当你创建一个 Deployment,如这个
nginx
,是由 kube-scheduler 决策将其调度到哪个 Node 上运行的 - kube-scheduler 会监听 apiserver 获取集群全局视图,然后根据 Pod 的资源请求(requests 和 limits)分析
- 最终 kube-scheduler 会结合资源请求和集群的实际情况来调度 Pod
总之,kube-scheduler 会保证 Pod 会调度到满足其运行资源需求的 Node 节点上。
LimitRange
描述
LimitRange 是资源描述对象,主要用于限制命名空间内资源的使用。它可以设置默认的资源请求和限制,以及资源使用的最大和最小值。它可以确保每个 Pod 或容器在资源使用上遵循特定的策略,从而避免单个 Pod 或容器占用过多资源。使用示例如下:
创建一个 YAML 文件保存 LimitRange 内容,例如:mem-limit-range.yaml
:
apiVersion: v1
kind: LimitRange
metadata:
name: mem-limit-range
spec:
limits:
- default:
memory: 512Mi
defaultRequest:
memory: 256Mi
type: Container
应用到集群:
$ kubectl apply -f mem-limit-range.yaml
查看创建的 LimitRange 对象:
$ kubectl describe limitrange mem-limit-range
输出:
Name: mem-limit-range
Namespace: default
Type Resource Min Max Default Request Default Limit Max Limit/Request Ratio
---- -------- --- --- --------------- ------------- -----------------------
Container memory - - 256Mi 512Mi -
说明:
- Kind:设置为 LimitRange,用于限制命名空间内资源的使用。
- Metadata:设置资源的名称
- Spec:
- Limits:
- default:指定没有明确资源限制的容器的默认内存限制为 512Mi
- defaultRequest:指定没有明确资源请求的容器的默认内存请求。这里设置为 256Mi
- type:应用这些限制的资源类型,在这里是
Container
验证
定义一个没有声明资源请求的部署对象,文件命名为: nginx-without-resource.yaml
,如下:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
应用部署到集群:
$ kubectl apply -f nginx-without-resource.yaml
等 Pod 创建后,可以通过检查它们的配置来确认 LimitRange
是否生效。
$ kubectl describe pod [POD_NAME]
输出:
Containers:
#.. ignore
Limits:
memory: 512Mi
Requests:
memory: 256Mi
initContainers
initContainers 用于在主应用容器启动之前执行一些预备任务。常见于以下场景:
- 准备工作:设置需要的配置文件、数据库迁移、等待其他服务就绪等。
- 安全性:权限提升操作,如改变文件权限或者执行特定的安全检查。
- 服务依赖性:等待其他服务或数据库可用。
initContainers 在执行完其任务后会停止,且必须成功完成才能启动主容器。非常适合用于启动前的初始化任务。
示例:
在部署对象中声明 initContainers 属性:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
initContainers:
- name: init-myservice
image: busybox:1.28
command: ['sh', '-c', 'echo The app is running! && sleep 10']
containers:
- name: nginx
image: nginx
将部署对象应用到集群:
$ kubectl apply -f init-container.yaml
当 Pod 启动后,可以通过查看事件日志验证容器的加载顺序:
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 2m20s default-scheduler Successfully assigned default/nginx-deployment-6445f86ddc-fmmzw to docker-desktop
Normal Pulling 2m20s kubelet Pulling image "busybox:1.28"
Normal Pulled 116s kubelet Successfully pulled image "busybox:1.28" in 23.099396719s (23.099404677s including waiting)
Normal Created 116s kubelet Created container init-myservice
Normal Started 116s kubelet Started container init-myservice
Normal Pulling 106s kubelet Pulling image "nginx"
Normal Pulled 88s kubelet Successfully pulled image "nginx" in 18.382000675s (18.382006008s including waiting)
Normal Created 88s kubelet Created container nginx
Normal Started 88s kubelet Started container nginx
可以看到 initContainers 声明的容器已经加载,然后查看特定的日志,来检查 Pod 日志输出:
$ kubectl logs [POD_NAME] -c init-myservice
输出:
The app is running!
验证完成。
initContainers 和 kube-scheduler 的关系 ?
如果 initContainers 没有声明资源需求,默认也会使用 LimitRange 声明的默认资源,这也意味着,initContainers 也是由 kube-scheduler 来调度创建的。所以在 initContainers 中加上资源需求也会影响着 kube-scheduler 的调度决策。
nodeSelector
在部署对象中,nodeSelector
属性的作用是用于把指定 Pod 调度到具有特定标签的节点上。如果没有满足要求的 Node 节点,则 Pod 会持续等待,示例:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
nodeSelector:
disktype: ssd
在这个例子中 nodeSelector 属性值为:disktype: ssd
。这表明这个 Pod 应该被调度到标签为 disktype=ssd
的 Node 节点上。kube-scheduler 在调度时,会选择合适的节点以运行这个 Pod 时。
先将部署对象应用到集群中:
$ kubectl apply -f node-selector.yaml
然后查看 Pod 状态:
$ kubectl get pod
输出:
NAME READY STATUS RESTARTS AGE
nginx-deployment-f5bc98d57-pmq9v 0/1 Pending 0 2m17s
可以看到创建的 Pod 一直保持在 "Pending" 状态。通过事件日志查看具体原因:
$ kubectl describe pod [POD_NAME]
输出:
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedScheduling 4m38s default-scheduler 0/1 nodes are available: 1 node(s) didn't match Pod's node affinity/selector. preemption: 0/1 nodes are available: 1 Preemption is not helpful for scheduling..
从事件日志可以看出,这个 Pod 不能被调度,因为没有节点满足其设定的节点选择条件。因为我的集群中确实没有任何标记为 disktype: ssd
的节点在运行。
Affinity 亲和性
NodeSelector 的演进版本,提供了更复杂的选择规则。除了简单的匹配,它们还支持更丰富的条件表达式,如 "存在"、"不等于"、"在集合中" 等,并且支持对 Pod 之间(Pod Affinity/Anti-Affinity)以及 Pod 与节点之间(Node Affinity)的亲和性/反亲和性设置。在 Kubernetes 后续版本中 Affinity 也逐渐替代了 NodeSelector。
podAffinity
podAffinity 用于定义 Pods 之间的亲和性。使得某个 Pod 被调度到与其他特定标签的 Pod 相同的节点上。
使用场景:当希望一组服务紧密地协同工作时,比如一个应用的不同组件需要低延迟通讯。
示例:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-anti
spec:
replicas: 2
selector:
matchLabels:
app: anti-nginx
template:
metadata:
labels:
app: anti-nginx
spec:
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: a
operator: In
values:
- b
topologyKey: kubernetes.io/hostname
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- anti-nginx
topologyKey: kubernetes.io/hostname
containers:
- name: with-pod-affinity
image: nginx
部署文件展示亲和性(Affinity)设置:
- PodAffinity:要求调度的 Pod 必须与具有特定标签(键
a
,值b
)的 Pod 在相同的节点上。 - PodAntiAffinity:要求调度的 Pod 不能与具有相同标签(键
app
,值anti-nginx
)的 Pod 在相同的节点上。
将上面部署文件应用到集群后,查看 Pods 的分布情况:
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-anti-5656fcbb98-62mds 0/1 Pending 0 5s <none> <none> <none> <none>
nginx-anti-5656fcbb98-wxphs 0/1 Pending 0 5s <none> <none> <none> <none>
可以 Pod 因为亲和性规则无法调度一直处于等待状态,查看特定 Pod 的事件日志可以验证:
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedScheduling 27s default-scheduler 0/1 nodes are available: 1 node(s) didn't match pod affinity rules. preemption: 0/1 nodes are available: 1 Preemption is not helpful for scheduling..
利用 Pod 亲和性和反亲和性规则来控制 Pod 的调度位置,以实现特定的调度需求和负载分布。
nodeAffinity
用于定义 Pod 与节点之间的亲和性。控制 Pod 被调度到具有特定标签或属性的节点上。
适用场景:当您需要根据硬件特性(如 GPU、高性能存储)或其他自定义标签(如环境标签)调度 Pod 时。
示例:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: disktype
operator: In
values:
- ssd
containers:
- name: nginx
image: nginx
部署文件的亲和性(Affinity)设置:
nodeAffinity
被设置为要求 Pod 被调度到具有disktype: ssd
标签的节点上。
将上面部署文件应用到集群后,查看 Pod 的运行情况:
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx-deployment-565d7797dc-jf5nk 0/1 Pending 0 14s <none> <none> <none> <none>
可以 Pod 因为亲和性规则无法调度一直处于等待状态,查看特定 Pod 的事件日志可以验证:
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedScheduling 89s default-scheduler 0/1 nodes are available: 1 node(s) didn't match Pod's node affinity/selector. preemption: 0/1 nodes are available: 1 Preemption is not helpful for scheduling..
preferredDuringSchedulingIgnoredDuringExecution
和之前的 requiredDuringScheduling 调度类型不同,preferredDuringScheduling 表明其是一个偏好性的调度,调度器会根据偏好优先选择满足对应规则的节点来调度Pod。但如果找不到满足规则的节点,调度器则会选择其他节点来调度Pod。
示例:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: disktype
operator: In
values:
- ssd
containers:
- name: nginx
image: nginx
配置说明:这里使用的是 preferredDuringSchedulingIgnoredDuringExecution
类型,这意味着调度器会尽量但不强制将 Pod 调度到具有 disktype: ssd
标签的节点上。
将上面部署文件应用到集群后,查看 Pod 的运行情况:
NAME READY STATUS RESTARTS AGE
nginx-deployment-69c654d896-7qh8t 1/1 Running 0 28s
可以看到虽然我本地没有满足亲和性规则的 Node 节点,但是 Pod 依然可以调度起来了。
总结:
podAffinity
关注的是 Pod 之间的关系不同nodeAffinity
更关注 Pod 与节点特性之间的关系- requiredDuringScheduling:硬亲和,强制型调度规则,必须满足亲和性设置,否则不能调度
- preferredDuringScheduling:软亲和,偏好型调度规则,首先找到满足设置的节点,没有则会调度到其他节点
Taints 污点
Taints 和 Tolerations 是 Kubernetes 中用于控制 Pod 调度到特定节点的一种机制,相比 Affinity 亲和性 **相似性 **的机制,Taints 的规则是属于 排斥性 的机制,用来“排斥”不满足特定条件的 Pod。
Taints 有三种效果:
NoSchedule
(不会调度新 Pod)PreferNoSchedule
(尽量避免调度新 Pod)NoExecute
(新 Pod 不会调度且已存在 Pod 可能会被迁移)
Taints 常见的应用场景:
- 对于集群中不想共享的 Node,可以加上 Taints 标签表示独享
- 用于多租户 Kubernetes 计算资源隔离
- Kubernetes 本身使用 Taints 机制驱除不可用的 Node
使用示例:
给节点添加 Taint,防止所有 Pod 自动调度到该节点,除非它们具有匹配的 Tolerations:
$ kubectl taint nodes docker-desktop for-special-user=cadmin:NoSchedule
先定义一个没有任何 Tolerations 的 Pod 来验证:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
将它应用到集群,查看 Pod 状态会一直处于 Pending:
NAME READY STATUS RESTARTS AGE
nginx-deployment-77b4fdf86c-wm5f9 0/1 Pending 0 23s
从事件日志可以看到是 Taints 在发挥作用:
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedScheduling 56s default-scheduler 0/1 nodes are available: 1 node(s) had untolerated taint {for-special-user: cadmin}. preemption: 0/1 nodes are available: 1 Preemption is not helpful for scheduling..
然后再 Pod 定义中添加 Tolerations,允许它被调度到带有特定 Taint 的节点上:
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deployment
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
tolerations:
- key: "for-special-user"
operator: "Equal"
value: "docker-desktop"
effect: "NoSchedule"
这个部署文件设置了一个 容忍度 (Tolerations) 规则:允许 Pod 被调度到标记为 for-special-user=docker-desktop
并且具有 NoSchedule
效果的节点上。
将它应用到集群,查看 Pod 状态:
NAME READY STATUS RESTARTS AGE
nginx-deployment-dd7d69c9c-77qlf 1/1 Running 0 31s
Pod 已经正常调度,这也是 Taints 发挥作用。
如果节点不在需要 Tanints 作为排除,可以移除 :
$ kubectl taint nodes docker-desktop for-special-user=cadmin:NoSchedule-
输出:
node/docker-desktop untainted
PriorityClass
PriorityClass
用于定义 Pod 的调度优先级。常见的场景包括:
- 确保关键服务优先调度:对于关键组件,如数据库、核心应用服务,可以设置更高的优先级。
- 管理资源争用:在资源有限的环境中,通过设置不同的优先级,管理不同 Pod 的调度顺序。
使用 PriorityClass
的步骤:
创建 PriorityClass:
apiVersion: scheduling.k8s.io/v1
kind: PriorityClass
metadata:
name: high-priority
value: 1000000
globalDefault: false
description: "This priority class should be used for XYZ service pods only."
说明:
- value:这是一个整数,表示该 PriorityClass 的优先级。较高的数值表示更高的优先级。
- globalDefault:表示为集群中所有没有指定优先级的 Pod 的默认优先级。
- 在 Pod 中指定 PriorityClass:
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
priorityClassName: high-priority
containers:
- name: mycontainer
image: myimage
通过 priorityClassName
应用刚才创建的 PriorityClass,从而确保该 Pod 具有更高的调度优先级。
自定义 scheduler
默认的调度器是面向通用的使用场景设计的,如果默认的 Kubernetes 调度器无法满足需求,也可以通过自定义的调度器来满足更加个性化的需求,示例:
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
schedulerName: my-custom-scheduler
containers:
- name: mycontainer
image: myimage
社区也有很多成熟开源的自定义调度器,例如:
- 腾讯 TKE 的调度器
- 华为 volcano 调度器
另外也可以参考 kube-scheduler
源码实现一个自己的调度器。
Kubernetes 漫游:kube-scheduler的更多相关文章
- Kubernetes Scheduler浅析
概述 Kubernetes 调度器(Scheduler)是Kubernetes的核心组件:用户或者控制器创建Pod之后,调度器通过 kubernetes 的 watch 机制来发现集群中新创建且尚未被 ...
- kubernetes 安装手册(成功版)
管理组件采用staticPod或者daemonSet形式跑的,宿主机os能跑docker应该本篇教程能大多适用安装完成仅供学习和实验 本次安裝的版本: Kubernetes v1.10.0 (1.10 ...
- Kubernetes 1.5 配置dns
在kubernetes1.2的时候,采用了skydns + kube2dns +etcd的方式来部署dns.而从1.3开始,则部署方式有了一点儿变化,将skydns和kube2dns封装到了一个容器镜 ...
- 二进制方式部署Kubernetes 1.6.0集群(开启TLS)
本节内容: Kubernetes简介 环境信息 创建TLS加密通信的证书和密钥 下载和配置 kubectl(kubecontrol) 命令行工具 创建 kubeconfig 文件 创建高可用 etcd ...
- Kubernetes v1.10.x HA 全手动安装教程(TL;DR)
转自 https://www.kubernetes.org.cn/3814.html 本篇延续过往手动安装方式来部署 Kubernetes v1.10.x 版本的 High Availability ...
- Kubernetes监控实践
一.Kubernetes介绍 Kubernetes(K8s)是一个开源平台,能够有效简化应用管理.应用部署和应用扩展环节的手动操作流程,让用户更加灵活地部署管理云端应用. 作为可扩展的容错平台,K8s ...
- 二进制方式搭建Kubernetes集群
环境准备: 演练暂时用单节点一台master和一台node节点来进行部署搭建(kubernetes 1.19版本) 角色 IP 组件 master 10.129.246.114 kube-apiser ...
- kubernetes调度概念与工作流程
Overview [1] kubernetes集群中的调度程序 kube-scheduler 会 watch 未分配节点的新创建的Pod,并未该Pod找到可运行的最佳(特定)节点.那么这些动作或者说这 ...
- 基于Containerd安装部署高可用Kubernetes集群
转载自:https://blog.weiyigeek.top/2021/7-30-623.html 简述 Kubernetes(后续简称k8s)是 Google(2014年6月) 开源的一个容器编排引 ...
- Centos 7.9 基于二进制文件部署kubernetes v1.25.5集群
简述 Kubernetes(简称为:k8s)是Google在2014年6月开源的一个容器集群管理系统,使用Go语言开发,用于管理云平台中多个主机上的容器化的应用,Kubernetes的目标是让部署容器 ...
随机推荐
- 为react项目添加开发/提交规范(前端工程化、eslint、prettier、husky、commitlint、stylelint)
因历史遗留原因,接手的项目没有代码提醒/格式化,包括 eslint.pretttier,也没有 commit 提交校验,如 husky.commitlint.stylelint,与其期待自己或者同事的 ...
- ctfshow--web入门--XXE
ctfshow--web入门--XXE web373 源码 <?php error_reporting(0); libxml_disable_entity_loader(false); //允许 ...
- LabVIEW图形化TensoRT工具包的安装下载分享
前言 Hello,大家好,我是virobotics(仪酷智能)今天我们一起来看一下如何安装[LabVIEWTensoRT工具包]. 一.LabVIEW图形化TensoRT工具包简介 工具包特点: 图形 ...
- 用 ChatGPT 做一个 Chrome 扩展 | 京东云技术团队
用ChatGPT做了个Chrome Extension 最近科技圈儿最火的话题莫过于ChatGPT了. 最近又发布了GPT-4,发布会上的Demo着实吸睛. 笔记本上手画个网页原型,直接生成网页.网友 ...
- Python基础语法--课程笔记
Smiling & Weeping ----我的心是旷野的鸟,在你的眼睛里找到了它的天空 定义和使用类: 1.声明类: class类名: 成员变量,成员函数 2.定义类的对象: 对象名 = 类 ...
- 达梦数据库-DW-国产化--九五小庞
武汉达梦数据库股份有限公司成立于2000年,是国内领先的数据库产品开发服务商,国内数据库基础软件产业发展的关键推动者.公司为客户提供各类数据库软件及集群软件.云计算与大数据等一系列数据库产品及相关技术 ...
- salesforce零基础学习(一百三十一)Validation 一次的bypass设计
本篇参考: https://admin.salesforce.com/blog/2022/how-i-solved-it-bypass-validation-rules-in-flows 背景:作为系 ...
- TDengine 用户案例合集 | 智能环保项目的时序数据处理难点与优化实践
智能环保系统通常涉及大量的传感器和监测设备,以收集环境数据并对其进行分析和处理,这些数据通常是时序数据,即在一段时间内按时间顺序生成的数据,规模庞大且要求快速准确地进行分析和处理.也因此时序数据处理是 ...
- 简单的Oracle增删改查笔记
- 判断两个数a,b,输出较大数的平方值。所谓平方值就是两个相同的数相乘的积。
平方值 描述 判断两个数a,b,输出较大数的平方值.所谓平方值就是两个相同的数相乘的积. 输入 两个数a和b 输出 输出较大数的平方值. 输入样例 1 1 2 输出样例 1 4 a,c = map ...