k8s集群调度-CSDN博客
阿里云国内75折 回扣 微信号:monov8 |
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6 |
概述
Kubernetes 是通过 List-Watch **** 的机制进行每个组件的协作保持数据同步的每个组件之间的设计实现了解耦。
用户是通过 kubectl 根据配置文件向 APIServer 发送命令在 Node 节点上面建立 Pod 和 Container。
APIServer 经过 API 调用权限控制调用资源和存储资源的过程实际上还没有真正开始部署应用。这里 需要 Controller Manager、Scheduler 和 kubelet 的协助才能完成整个部署过程。
在 Kubernetes 中所有部署的信息都会写到 etcd 中保存。实际上 etcd 在存储部署信息的时候会发送 Create 事件给 APIServer而 APIServer 会通过监听Watchetcd 发过来的事件。其他组件也会监听WatchAPIServer 发出来的事件。
Pod 是 Kubernetes 的基础单元Pod 启动典型创建过程如下 工作机制 ****
- 这里有三个 List-Watch分别是 Controller Manager运行在 MasterScheduler运行在 Masterkubelet运行在 Node。 他们在进程已启动就会监听WatchAPIServer 发出来的事件。
- 用户通过 kubectl 或其他 API 客户端提交请求给 APIServer 来建立一个 Pod 对象副本。
- APIServer 尝试着将 Pod 对象的相关元信息存入 etcd 中待写入操作执行完成APIServer 即会返回确认信息至客户端。
- 当 etcd 接受创建 Pod 信息以后会发送一个 Create 事件给 APIServer。
- 由于 Controller Manager 一直在监听Watch通过https的6443端口APIServer 中的事件。此时 APIServer 接受到了 Create 事件又会发送给 Controller Manager。
- Controller Manager 在接到 Create 事件以后调用其中的 Replication Controller 来保证 Node 上面需要创建的副本数量。一旦副本数量少于 RC 中定义的数量RC 会自动创建副本。总之它是保证副本数量的 ControllerPS扩容缩容的担当。
- 在 Controller Manager 创建 Pod 副本以后APIServer 会在 etcd 中记录这个 Pod 的详细信息。例如 Pod 的副本数Container 的内容是什么。
- 同样的 etcd 会将创建 Pod 的信息通过事件发送给 APIServer。
- 由于 Scheduler 在监听WatchAPIServer并且它在系统中起到了“承上启下”的作用“承上”是指它负责接收创建的 Pod 事件为其安排 Node“启下”是指安置工作完成后Node 上的 kubelet 进程会接管后继工作负责 Pod 生命周期中的“下半生”。 换句话说Scheduler 的作用是将待调度的 Pod 按照调度算法和策略绑定到集群中 Node 上。
- Scheduler 调度完毕以后会更新 Pod 的信息此时的信息更加丰富了。除了知道 Pod 的副本数量副本内容。还知道部署到哪个 Node 上面了。并将上面的 Pod 信息更新至 API Server由 APIServer 更新至 etcd 中保存起来。
- etcd 将更新成功的事件发送给 APIServerAPIServer 也开始反映此 Pod 对象的调度结果。
- kubelet 是在 Node 上面运行的进程它也通过 List-Watch 的方式监听Watch通过https的6443端口APIServer 发送的 Pod 更新的事件。kubelet 会尝试在当前节点上调用 Docker 启动容器并将 Pod 以及容器的结果状态回送至 APIServer。
- APIServer 将 Pod 状态信息存入 etcd 中。在 etcd 确认写入操作成功完成后APIServer将确认信息发送至相关的 kubelet事件将通过它被接受。
#注意在创建 Pod 的工作就已经完成了后为什么 kubelet 还要一直监听呢原因很简单假设这个时候 kubectl 发命令要扩充 Pod 副本数量那么上面的流程又会触发一遍kubelet 会根据最新的 Pod 的部署情况调整 Node 的资源。又或者 Pod 副本数量没有发生变化但是其中的镜像文件升级了kubelet 也会自动获取最新的镜像文件并且加载。
调度过程 ***
Scheduler 是 kubernetes 的调度器主要的任务是把定义的 pod 分配到集群的节点上。其主要考虑的问题如下
- 公平如何保证每个节点都能被分配资源
- 资源高效利用集群所有资源最大化被使用
- 效率调度的性能要好能够尽快地对大批量的 pod 完成调度工作
- 灵活允许用户根据自己的需求控制调度的逻辑
Sheduler 是作为单独的程序运行的启动之后会一直监听 APIServer获取 spec.nodeName 为空的 pod对每个 pod 都会创建一个 binding表明该 pod 应该放到哪个节点上。
调度分为几个部分首先是过滤掉不满足条件的节点这个过程称为预算策略predicate然后对通过的节点按照优先级排序这个是优选策略priorities最后从中选择优先级最高的节点。如果中间任何一步骤有错误就直接返回错误。
Predicate 有一系列的常见的算法可以使用 **
- PodFitsResources节点上剩余的资源是否大于 pod 请求的资源nodeName检查节点名称是否和 NodeName 匹配。。
- PodFitsHost如果 pod 指定了 NodeName检查节点名称是否和 NodeName 匹配。
- PodFitsHostPorts节点上已经使用的 port 是否和 pod 申请的 port 冲突。
- PodSelectorMatches过滤掉和 pod 指定的 label 不匹配的节点。
- NoDiskConflict已经 mount 的 volume 和 pod 指定的 volume 不冲突除非它们都是只读。
如果在 predicate 过程中没有合适的节点pod 会一直在 pending 状态不断重试调度直到有节点满足条件。 经过这个步骤如果有多个节点满足条件就继续 priorities 过程按照优先级大小对节点排序。
优先级由一系列键值对组成键是该优先级项的名称值是它的权重该项的重要性。有一系列的常见的优先级选项包括
- LeastRequestedPriority通过计算CPU和Memory的使用率来决定权重使用率越低权重越高。也就是说这个优先级指标倾向于资源使用比例更低的节点。
- BalancedResourceAllocation节点上 CPU 和 Memory 使用率越接近权重越高。这个一般和上面的一起使用不单独使用。比如 node01 的 CPU 和 Memory 使用率 20:60node02 的 CPU 和 Memory 使用率 50:50虽然 node01 的总使用率比 node02 低但 node02 的 CPU 和 Memory 使用率更接近从而调度时会优选 node02。
- ImageLocalityPriority倾向于已经有要使用镜像的节点镜像总大小值越大权重越高。
通过算法对所有的优先级项目和权重进行计算得出最终的结果。
常见的调度约束示例
- 节点选择器Node Selector通过标签选择器在Pod配置中指定要求Pod只能调度到具有特定标签的节点上。
- 亲和性与反亲和性Affinity and Anti-Affinity使用亲和性规则来指定Pod应该调度到哪些节点上或使用反亲和性规则来指定Pod不应该调度到哪些节点上。
- 资源限制Resource Limits通过设置资源需求和限制例如CPU和内存来影响Pod的调度和分配。
- 互斥锁Taints and Tolerations通过为节点添加“污点”Taint然后在Pod配置中设置“容忍”Toleration以确保只有满足特定条件的节点能够调度Pod。
- 优先级与抢占Priority and Preemption通过设置Pod的优先级以及在资源紧张时可能发生的Pod抢占规则来调整Pod的调度顺序。
这些调度约束可以根据业务需求和集群配置进行灵活的设置以实现对Pod调度的控制和优化。
实例
指定调度节点
pod.spec.nodeName 将 Pod 直接调度到指定的 Node 节点上会跳过 Scheduler 的调度策略该匹配规则是强制匹配
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp
spec:
replicas: 3
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
nodeName: node02
containers:
- name: myapp
image: nginx
ports:
- containerPort: 80
~
创建完成
由上可看出全部都在节点node02
查看详细事件发现未经过 scheduler 调度分配
pod.spec.nodeSelector通过 kubernetes 的 label-selector 机制选择节点由调度器调度策略匹配 label然后调度 Pod 到目标节点该匹配规则属于强制约束
kubectl label --help
Usage:
kubectl label [--overwrite] (-f FILENAME | TYPE NAME) KEY_1=VAL_1 ... KEY_N=VAL_N [--resource-version=version] [options]
kubectl get node
给对应的 node 设置标签分别为 kgc=a 和 kgc=b
修改成 nodeSelector 调度方式
apiVersion: apps/v1
kind: Deployment
metadata:
labels:
app myapp1
name: myapp1
spec:
replicas: 3
selector:
matchLabels:
app: myapp1
template:
metadata:
labels:
app: myapp1
spec:
nodeSelector:
kgc: a
containers:
- name: myapp1
image: nginx
ports:
- containerPort: 80
~
创建
kubectl get pod -o wide
查看详细事件通过事件可以发现要先经过 scheduler 调度分配
修改一个 label 的值需要加上 --overwrite 参数
kubectl label nodes node01 kgc=c --overwrite
删除一个 label只需在命令行最后指定 label 的 key 名并与一个减号相连即可
kubectl label nodes node02 kgc-
指定标签查询 node 节点
kubectl get node -l kgc=c