Pod创建过程
Pod创建架构图
Pod创建流程图
具体创建流程
- 1、首先,用户通过kubectl或web端向apiserve发送创建pod请求。
- 2、apiserve会做出认证/鉴权响应,然后检查信息并把数据存储到ETCD里,创建deploment资源并初始化。
- 3、controller-manager通过list-watch机制,检查发现新到deployment,将资源加入到内部工作队列,然后检查发现资源没有关联的pod和replicaset,启用deployment controller创建replicaset资源,再通过replicaset controller创建pod。
- 4、controller-manager创建完成后将deployment,replicaset,pod资源更新存储到etcd;
- 5、scheduler也是通过list-watch机制,监测发现新的pod,并通过预选及优选策略算法,来计算出pod最终可调度的node节点,并通过apiserver将数据更新至etcd;
- 6、kubelet每隔20s(可以自定义)向apiserver通过NodeName获取自身Node上所要运行的pod清单;通过与自己的内部缓存进行比较,如果有新的资源则触发钩子调用CNI接口给pod创建pod网络,调用CRI接口去启动容器,调用CSI进行存储卷的挂载,然后启动pod容器;
- 7、kube-proxy为新创建的pod注册动态DNS到CoreOS。给pod的service添加iptables/ipvs规则,用于服务发现和负载均衡。
- 8、controller通过control loop(控制循环)将当前pod状态与用户所期望的状态做对比,如果当前状态与用户期望状态不同,则controller会将pod修改为用户期望状态,实在不行会将此pod删掉,然后重新创建pod;
多种Scheduler的多种调度策略
一、简介
Kubernetes 的调度器 Scheduler,主要的任务是把 pod 按照预设的策略分配到集群的节点上。听起来非常简单,但有很多层面都需要我们去一一的深入思考:
- 公平:如何保证每个节点都能被分配资源?
- 资源高效利用:如何能集群所有资源最大化被使用
- 效率:能够尽快地对大批量的 pod 完成调度工作
- 灵活:允许特殊场景的应用调度到特定的节点
Sheduler 是作为单独的程序运行的,启动之后会一直监听Apiserver,获取Podspec.NodeName为空的pod,对每个pod都会创建一个binding,表明该pod应该放到哪个节点上。
二、调度过程
调度分为几个部分:
- 1、首先是过滤掉不满足条件的节点,这个过程称为预选(predicate) ;
- 2、然后对通过的节点按照优先级排序,这个是优选(priority) ;
- 3、最后从中选择优先级最高的节点。如果中间任何一步骤有错误,就直接返回错误。
Predicate 有一系列的算法可以使用:
- PodFitsResources :节点上剩余的资源是否大于pod 请求的资源
- PodFitsHost :如果pod 指定了NodeName,检查节点名称是否和NodeName匹配
- PodFitsHostPorts :节点上已经使用的port是否和pod申请的port冲突
- PodselectorMatches :过滤掉和pod指定的 label 不匹配的节点
- NoDiskConflict :已经mount的volume和pod指定的volume不冲突,除非它们都是只读
如果在predicate 过程中没有合适的节点,pod 会一直在 pending 状态,不断重试调度,直到有节点满足条件。经过这个步骤,如果有多个节点满足条件,就继续 priorities 过程:按照优先级大小对节点排序。
三、Node标签概念
每个node节点默认会有很多标签,标签在日常工作中就类似我们的一个标识;看到标签就能晓得这台node节点的主要用处;
3.1、为节点添加标签
[root@master ~]# kubectl get nodes # 查看节点NAME STATUS ROLES AGE VERSIONmaster Ready control-plane,master 15d v1.23.0node01 Ready 14d v1.23.0node02 Ready 12d v1.23.0 [root@master ~]# kubectl label nodes cn-shanghai.172.25.25.145 apptype=core # 为node节点加上核心应用的标签
[root@master ~]# kubectl get nodes --show-labels # 验证节点标NAME STATUS ROLES AGE VERSION LABELSmaster Ready control-plane,master 15d v1.23.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=master,kubernetes.io/os=linux,node-role.kubernetes.io/control-plane=,node-role.kubernetes.io/master=,node.kubernetes.io/exclude-from-external-load-balancers=node01 Ready 14d v1.23.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,apptype=core,kubernetes.io/arch=amd64,kubernetes.io/hostname=node01,kubernetes.io/os=linuxnode02 Ready 12d v1.23.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=node02,kubernetes.io/os=linux
四、调度策略
4.1、nodeSelect
nodeSelector
是节点选择约束的最简单推荐形式。你可以将 nodeSelector
字段 设置你希望 目标节点 所具有的节点标签。 Kubernetes 只会将 Pod 调度到拥有你所指定的每个标签的节点上。
apiVersion: apps/v1
kind: Deployment
metadata:
name: busybox
spec:
replicas: 3
selector:
matchLabels:
app: busybox
template:
metadata:
labels:
app: busybox
spec:
nodeSelector:
apptype: core ## 选择节点为core的标签
containers:
- name: busybox
image: busybox
imagePullPolicy: IfNotPresent
command:
- /bin/sh
- -c
- sleep 3000
4.2、亲和性与反亲和性
使用亲和性与反亲和性的一些好处有:
- 亲和性、反亲和性语言的表达能力更强。nodeSelector 只能选择 所有固定标签 的节点。
亲和性:
- requiredDuringSchedulingIgnoredDuringExecution: 调度器只有在规则被满足的时候才能执行调度。此功能类似于 nodeSelector, 但其语法表达能力更强。
- preferredDuringSchedulingIgnoredDuringExecution: 调度器会尝试寻找满足对应规则的节点。如果找不到匹配的节点,调度器仍然会在其它节点调度该 Pod。
NodeAffinity(节点亲和性):
- 如果pod标明调度策略规则是 “软需求”,这样调度器在无法找到匹配节点时仍然调度该 Pod。
- 如果pod标明调度策略规则是 “硬需求”,如果node节点不满足需求,pod不会被调度,而是一直处于pending状态。
PodAffinity(亲和性)/PodAntiAffinity(互斥性):
- Pod亲和性主要解决 pod 可以和哪些 pod 部署在同一个拓扑域中的问题;
- Pod互斥性主要是解决 pod 不能和哪些 pod 部署在同一个拓扑域中的问题;
Kubernetes提供的操作符有下面的几种:
调度策略 |
匹配标签 |
操作符 |
拓扑域支持 |
调度目标 |
nodeAffinity |
node节点 |
In, NotIn, Exists,DoesNotExist, Gt, Lt |
否 |
指定主机 |
podAffinity |
pod |
In, NotIn, Exists,DoesNotExist |
是 |
POD与指定POD同一拓扑域 |
podAnitAffinity |
pod |
In, NotIn, Exists,DoesNotExist |
是 |
POD与指定POD不在同一拓扑域 |
Kubernetes提供的操作符有下面的几种:
- In:label 的值在某个列表中
- NotIn:label 的值不在某个列表中
- Gt:label 的值大于某个值
- Lt:label 的值小于某个值
- Exists:某个 label 存在
- DoesNotExist:某个 label 不存在
测试验证
NodeAffinify:
apiVersion: apps/v1
kind: Deployment
metadata:
name: affinity
labels:
app: affinity
spec:
replicas: 1
revisionHistoryLimit: 3
selector:
matchLabels:
app: affinity
template:
metadata:
labels:
app: affinity
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
name: nginxweb
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution: # 硬策略
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- cn-shanghai.172.25.36.200
preferredDuringSchedulingIgnoredDuringExecution: # 软策略
- weight: 1
preference:
matchExpressions:
- key: apptype
operator: In
values:
- core
podAffinity:
apiVersion: apps/v1
kind: Deployment
metadata:
name: affinity
labels:
app: affinity
spec:
replicas: 1
revisionHistoryLimit: 15
selector:
matchLabels:
app: affinity
template:
metadata:
labels:
app: affinity
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
name: nginxweb
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution: # 硬策略
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- busybox
topologyKey: kubernetes.io/hostname
podAntiAffinity:
apiVersion: apps/v1
kind: Deployment
metadata:
name: affinity
labels:
app: affinity
spec:
replicas: 1
revisionHistoryLimit: 15
selector:
matchLabels:
app: affinity
template:
metadata:
labels:
app: affinity
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
name: nginxweb
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution: # 硬策略
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- busybox
topologyKey: kubernetes.io/hostname
实验升级:
- 如果不满足 “Node硬亲和”?
- 如果不满足 “Node软亲和”?
- 如果不满足 “Pod硬亲和”?
- 如果不满足 “Pod软亲和”?
4.3、污点(taints)与容忍(tolerations)
对于nodeAffinity无论是硬策略还是软策略方式,都是调度 pod 到预期节点上,而Taints恰好与之相反,如果一个节点标记为 Taints ,除非 pod 也被标识为可以容忍,否则该 Taints 节点不可以被调度 pod。也就是节点只要有了污点,正常pod都不会调度到这个节点上去。
场景:
- 1、当前很多企业有很多基于GPU的算力集群,这些GPU的节点肯定是不可以让普通pod调度上去,这样就浪费了GPU的资源,所以我们就需要对GPU的节点打上污点,以防止pod被调度;
- 2、用户希望把 Master 节点保留给 Kubernetes 系统组件使用,例如我们使用kubeadm搭建的集群默认就给 master 节点添加了一个污点标记,所以我们看到我们平时的 pod 都没有被调度到 master 上去:
每个污点的组成: key=value:effect
每个污点有一个 key 和 value 作为污点的标签,其中 value 可以为空,effect 描述污点的作用。当前 taint effect 支持如下三个选项:
- NoSchedule :表示 k8s 将不会将 Pod 调度到具有该污点的 Node 上。
- PreferNoSchedule :表示 k8s 将 尽量避免 将 Pod 调度到具有该污点的 Node 上。
- NoExecute :表示 k8s 将不会将 Pod 调度到具有该污点的 Node 上,同时会将 Node 上已经存在的 Pod 驱逐出去。
# 设置污点
[root@master ~]# kubectl taint nodes cn-shanghai.172.25.36.211 devops=cn-shanghai.172.25.36.211:NoSchedule
node/node01 tainted
# 查看污点
[root@master ~]# kubectl describe nodes | grep -P "Name:|Taints"
Name: cn-shanghai.172.25.25.145
Taints: devops=cn-shanghai.172.25.25.145:NoSchedule
# 删除污点
[root@master ~]# kubectl taint nodes cn-shanghai.172.25.36.211 devops=cn-shanghai.172.25.36.211:NoSchedule-
node/node01 untainted
实验:
apiVersion: apps/v1
kind: Deployment
metadata:
name: taint
labels:
app: taint
spec:
replicas: 3
revisionHistoryLimit: 10
selector:
matchLabels:
app: taint
template:
metadata:
labels:
app: taint
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- name: http
containerPort: 80
tolerations:
- key: "devops"
operator: "Exists"
effect: "NoSchedule"
注意点:
对于 tolerations 属性的写法,其中的 key、value、effect 与 Node 的 Taint 设置需保持一致, 还有以下几点说明:
- 如果 operator 的值是 Exists,则 value 属性可省略
- 如果 operator 的值是 Equal,则表示其 key 与 value 之间的关系是 equal(等于)
- 如果不指定 operator 属性,则默认值为 Equal
另外,还有两个特殊值:
- 空的 key 如果再配合 Exists 就能匹配所有的 key 与 value,也是是能容忍所有 node 的所有 污点(Taints)。
- 空的 effect 匹配所有的 effect。
4.4、指定pod运行在固定节点
Pod.spec.nodeName 将 Pod 直接调度到指定的 Node 节点上,会跳过 Scheduler 的调度策略,该匹配规则是强制匹配。
apiVersion: apps/v1
kind: Deployment
metadata:
name: myweb
spec:
selector:
matchLabels:
app: myweb
replicas: 3
template:
metadata:
labels:
app: myweb
spec:
nodeName: cn-shanghai.172.25.25.145 # 指定固定的节点
containers:
- name: myweb
image: nginx
ports:
- containerPort: 80
五、总结
nodeName:调度到固定节点;场景:验证特定节点上的数据/故障复现等;
nodeSelect: 会将 Pod 调度到拥有你所指定的每个标签的节点上;场景:集群中的节点涉及特殊部门/业务线/测试情况;
podAffinity:Pod亲和性主要解决 pod 可以和哪些 pod 部署在同一个拓扑域中的问题;场景:上下游应用存在大量数据交互;
podAntiAffinity:Pod互斥性主要是解决 pod 不能和哪些 pod 部署在同一个拓扑域中的问题;场景:多个计算型类应用不适合调度到同一台节点;
nodeAffinity:指定应用可以调度到指定的节点;场景:核心应用必须要调度到核心的节点;
nodeAntiAffinity:指定应用不可以调度到指定的节点;场景:核心节点不允许被普通的应用调度;
taints:该 Taints 节点不可以被调度 pod;场景:GPU集群/master节点等
tolerations:配置了tolerations的pod是可以被调度到指定的Taints 节点;
当然还有很多场景:
- GPU pod配置nodeAffinity 必须要调度到指定的节点,同时该节点打了Taints不允许其它pod调度;
扩展知识
● https://kubernetes.io/zh-cn/docs/concepts/scheduling-eviction/
● https://kubernetes.io/zh-cn/docs/concepts/workloads/pods/pod-lifecycle/
服务器租用托管,机房租用托管,主机租用托管,https://www.e1idc.com