在k8s集群中,能运行pod资源的只有工作节点,master 主要是做为控制平面组件 (api-server, contarner-manage, 调度器), 也依赖于etcd(最好能有冗余能力)
调度器是如何决策哪一个Pod在哪一个节点上运行的,简单来说 当用户创建Pod资源对象时,有一组节点可以选择, 调度器会从集群中的节点挑出一个匹配的,default scheduler通过三级来挑选节点
对于预选,k8s会有很多预选器也会参与挑选节点是否符合Pod的基本要求,对于Predicate来讲,它是一个或者一组程序,会将Kubernetes之上的所有节点拿来,进行一次计算,如果其中有一组程序声明这个节点不符合运行此Pod的条件,那么这就被预选排除了,以此类推,这些左右节点都经过这一组Predicate进行评估之后,留下的都是至少能符合运行此Pod的基本条件;
于是这些节点谁是最好的,因此就需要进入第二步,Priority也是有一组优先函数组成的,这个函数不像Predicate它合不合理,而评估的是这个节点和运行此Pod的评估分数,比如node1进来,进入第一个Priority函数计算得两分,进入第二个Priority函数计算得三分,最终所有的Priority函数的分值的和就是这个node节点的整体得分分值,而后基于得分进行排序,逆序排序;
排完序之后,就看得分最高的有几个,然后会将得分最高的挑选出来,进入Select流程,进行随机挑选;
当我们未定义调度器的时候,直接使用默认值,准入控制器会为我们补齐该字段,
# 查看已创建的Pod调度器默认值
]# kubectl get pods -n dev my-dev-6568b4bdb-b4zmf -o yaml | grep schedulerName
schedulerName: default-scheduler
pod以及节点对象
存储资源
底层资源
亲和性
如果定义多个, 得分分值越高挑选越大
当一个Pod被调度的时候,所有通过预选策略的node都会进行一些硬性条件检查,而后经过优选策略进行软性分值计算,而后通过分值进行排序,接下来进行选择阶段了,最高分胜出;
节点倾向性
nodeName: 节点名称
nodeSelector: 节点挑选, 节点倾向性
Pod亲和性
污点
一般来讲当我们创建Pod时都会被kube-scheduler当中的default-scheduler调取,目前来讲,k8s内部只有一个调度器,但是它支持插件式调度器,允许用户自定义调度器对接到已有的调度程序上;我们可以在外部施加各种条件,来影响调度结果,比如在定义Pod时,在spec字段中加上nodeName或nodeSelector来影响它的调度结果,或指定匹配node节点,如果没有节点被匹配,那它就会被Pending,这种就属于硬性调度机制;
也可以有一些柔性调度机制,比如Affinity,亲和性也分硬亲和和软亲和,硬亲和指的是,如果满足它的亲和性,它就可以把node作为调度节点,如果不满足,就直接排除,而软亲和指的是如果我们经过亲和性检测,发现没有一个节点符合这个亲和性,那么就随机亲和;
当然我们也可以使用污点, 从上面描述的来看可以看出node都是等待着被选择,那么我们也可以赋予node的主动权,给node加上一个污点,如果节点不能容忍这个污点,那么就不会调度上面来,这就给了node主动控制权;
如果在某些特定场景当中,我们期望通过自己的预设来影响它的预先和优选过程,从而使得调度操作符合我们期望,此类的影响方式通常有如下几种:
]# cat nodeName-1.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-node-select
spec:
containers:
- name: pod-node-select
image: ikubernetes/myapp:v1
imagePullPolicy: IfNotPresent
nodeName: slave1 # 将节点指定至slave1的节点上 通过kubectl get nodes查看节点
nodeName: slave11 # 如果节点不存在,那么该pod会一直Pending等待该节点
# pod-node-select-2 0/1 Pending slave3
nodeSelector: 给一部分节点打上特有标签,节点通过nodeSelector匹配
]# kubectl explain pod.spec.nodeSelector # 可查看对应参数
# 通过 kubectl label 添加标签 kubectl label node slave1 disk=ssd
# 通过给一些节点添加标签,然后通过 nodeSelector 选择更具有亲和性一些的节点,比如 全固态跑数据库
]# cat nodeSelecto-1.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-select-1
spec:
containers:
- name: pod-select-1
image: ikubernetes/myapp:v1
imagePullPolicy: IfNotPresent
nodeSelector: # kubectl get node --show-labels, 或通过 kubectl label node 打标
disk: ssd
查看节点亲和性调度参数:
~]# kubectl explain pods.spec.affinity
节点亲和性
# kubectl explain pods.spec.affinity.nodeAffinity
# preferredDuringSchedulingIgnoredDuringExecution 软亲和性, 尽量满足的条件,不满足也可以
preference: 节点选择
weight: 权重 1-100
# requiredDuringSchedulingIgnoredDuringExecution 硬亲和性,必须要满足的条件,不满足一定不运行pending状态
nodeSelectorTerms: 节点选择器
matchExpressions: 匹配正则表达式
operator参数: In,NotIn, Exists, DoesNotExist. Gt, and Lt
matchFields: 匹配字段
# 硬亲和性,必须要满足,不满足就pending
]# cat nodeAffinity-required-1.yaml
apiVersion: v1
kind: Pod
metadata:
name: nodeaffinity-hard-1
spec:
containers:
- name: nodeaffinity-hard-1
image: ikubernetes/myapp:v1
imagePullPolicy: IfNotPresent
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: disk # key为disk
operator: In # disk的value值应当包含 ssd或 pcie
values: # 只要满足这些条件,Pod就会运行在这个节点之上
- ssd # 不满足就会一直处于pending的状态
- pcie
]# cat nodeAffinity-required-2.yaml
apiVersion: v1
kind: Pod
metadata:
name: nodeaffinity-soft-2
spec:
containers:
- name: nodeaffinity-soft-2
image: ikubernetes/myapp:v1
imagePullPolicy: IfNotPresent
affinity:
nodeAffinity:
# 软亲和性,当条件不满足时,使用默认的default-schedule挑选节点
preferredDuringSchedulingIgnoredDuringExecution:
- preference:
matchExpressions:
- key: disk
operator: In
values:
- pcie
weight: 30
Pod亲和性调度,调度器随机将第一个Pod选择一个位置,然后第二个Pod会根据第一个Pod进行调度。Pod亲和性并不强制限制在同一个节点,也可以是相近的节点(或拥有一样标签)
~]# 通过kubectl explain pods.spec.affinity.podAffinity
查看选项
对于Pod资源来讲,在运行过程中因为Pod之间的关系,可能会根据业务需求将其运行在同一个或不能在同一个节点上,像这种高级调度控制器,称之为Pod间的Affinity或Anti-Affinity,这两种调度关系分别为亲和性、反亲和性;
Pod亲和性主要用于描述两个Pod之间能否运行于同一位置,同一位置可能是同一机房,同一节点,同一集群等,因此在定义Pod亲和性时,我们必须有一个机制来人为定义何为同一位置,有一个专门的字段,叫做topologyKey;
如果要使用Pod亲和性来调度,只需要在Pod的spec下面的affinity字段当中使用podAffinity或者使用podAntiAffinity来定义即可,但是Pod的亲和性和反亲和性有一个要求,如果要使用Pod亲和性,假如有三百个节点,每调度一个Pod都需要评估这个Pod和其他Pod是不是在同一个位置,可能会遍历每一个节点查询位置是不是一样的,所以评估过程就被拖慢,因此在较大的规模的集群当中,反而不是特别适合于使用podAffinity,或者不易于使用较细的粒度进行区分同一位置;
podAntiAffinity指的是几个Pod一定不能在同一个位置,Pod的podAntiAffinity严格要求集群当中的每一个节点,都必须设置正确的标签,否则没法评估到底是不是反亲和性的,否则反亲和性就无法工作,因此Pod的亲和性调度,还是有着较大局限性的;
preferredDuringSchedulingIgnoredDuringExecution 软亲和性
requiredDuringSchedulingIgnoredDuringExecution 硬亲和性
labelSelector:指定一组目标Pod资源
namespaces: 指定labelSelector是哪一组名称空间
topologyKey: 位置拓扑键, 相同即是同一位置,只能有一个key
]# cat podAffinity-hard.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-affinity-p-1
labels:
app: pod-affinity-1
spec:
containers:
- name: podaffinity-1
image: ikubernetes/myapp:v1
imagePullPolicy: IfNotPresent
---
apiVersion: v1
kind: Pod
metadata:
name: pod-affinity-m-2
labels:
app: pod-affinity-2
spec:
containers:
- name: podaffinity-1
image: ikubernetes/myapp:v1
imagePullPolicy: IfNotPresent
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values: ["pod-affinity-1"]
topologyKey: kubernetes.io/hostname # 选择相同的逻辑节点或同一区域的物理节点,硬亲和性,指定必须运行在同一个区域节点相匹配亲和性 Pod的机房,通过 kubectl get nodes --show-labels 查看labels
]# kubectl get pods -o wide
NAME READY STATUS IP NODE
pod-affinity-m-2 1/1 Running 10.244.2.6 slave2
pod-affinity-p-1 1/1 Running 10.244.2.5 slave2
demo-2
# slave 1 slave2 运行 tj-pod
# pod2 亲和 tj-pod这个pod , 但是pod2 依赖于 slave1 天津机房
# kubectl labels node slave jf=tj
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-execution
spec:
replicas: 3
selector:
matchLabels:
app: my-execution
template:
metadata:
labels:
app: my-execution
spec:
containers:
- name: my-execution
image: ubuntu:latest
imagePullPolicy: IfNotPresent
command: ["/bin/sh"]
args: ["-c", "while true;do sleep 10;done"]
resources:
limits:
memory: "10Mi"
cpu: "5m"
requests:
memory: "10Mi"
cpu: "5m"
---
apiVersion: v1
kind: Pod
metadata:
name: tj-pod
labels:
name: tj-pod
spec:
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- topologyKey: jf
labelSelector:
matchExpressions:
- key: app # 这里是pod亲和, 需要选择的是pod的标签而不是node的
operator: In
values:
- my-execution
# matchLabels: jf: bj
containers:
- name: tj-pod
image: ubuntu:latest
command:
- sleep
- "3600"
resources:
limits:
memory: "10Mi"
cpu: "5m"
requests:
memory: "10Mi"
cpu: "5m"
# 将两个节点加至同一个区域,测试反亲和性如果在同一个区域, 反亲和节点是否运行
]# kubectl label nodes slave1 zone=bj
]# kubectl label nodes slave2 zone=bj
]# cat podAffinity-anti.yaml
apiVersion: v1
kind: Pod
metadata:
name: pod-affinity-anti-p-1
labels:
app: pod-affinity-anti-1
spec:
containers:
- name: podaffinity-anti-1
image: ikubernetes/myapp:v1
imagePullPolicy: IfNotPresent
---
apiVersion: v1
kind: Pod
metadata:
name: pod-affinity-anti-m-2
labels:
app: pod-affinity-anti-2
spec:
containers:
- name: podaffinity-anti-1
image: ikubernetes/myapp:v1
imagePullPolicy: IfNotPresent
affinity:
podAntiAffinity: # 反亲和性,与定义的Pod运行节点刚好相反的
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values: ["pod-affinity-anti-1"]
topologyKey: zone # 选择为zone的逻辑或物理位置节点
]# kubectl get pods -o wide
NAME READY STATUS IP NODE
pod-affinity-anti-m-2 0/1 Pending <none> <none>
pod-affinity-anti-p-1 1/1 Running 10.244.1.13 slave1
# 将 slave2 的zone label删除, 反亲和性的Pod会立即运行到与之相反的节点。
]# kubectl label nodes slave2 zone-
]# kubectl get pods -o wide
NAME READY STATUS IP NODE
pod-affinity-anti-m-2 1/1 Running 10.244.2.8 slave2
pod-affinity-anti-p-1 1/1 Running 10.244.1.13 slave1
taint的effect定义对Pod排斥效果, 当Pod不能容忍这个污点时,采取的行为
参数 | 说明 |
---|---|
Noschedule | 仅影响调度过程,对现存的Pod对象不产生影响, 如果不容忍就不允许调度过来 |
NoExecute | 不仅影响调度还影响现存Pod对象, 不容忍Pod对象将被驱逐 |
PreferNoschedule | 不容忍会影响调度,但最终还是能被允许 |
Command:
kubectl taint node nodename key=value:effect参数
添加污点
# 给节点打上污点
~]# kubectl taint node slave2 node-type=qa:NoSchedule
# 删除污点
~]# kubectl taint node slave2 node-type-
# 查看节点的污点情况
~]# kubectl get nodes slave2 -o yaml
spec:
podCIDR: 10.244.2.0/24
podCIDRs:
- 10.244.2.0/24
taints:
- effect: NoSchedule
key: node-type
value: qa
# 给节点打上污点
~]# kubectl taint node slave1 node-type=dev:NoExecute
# 查看节点的污点情况
~]# kubectl get nodes slave2 -o yaml
spec:
podCIDR: 10.244.1.0/24
podCIDRs:
- 10.244.1.0/24
taints:
- effect: NoExecute
key: node-type
value: dev
定义Pod污点容忍度
~]# kubectl explain deploy.spec.template.spec.tolerations 容忍污点
effect # 污点级别参数
key: # 节点定义的taints key
operator: # 污点评估值 Exists and Equal
tolerationSeconds:# 容忍时间,定义可以忍受在一段时间内的驱逐 单位: 秒
value: # 节点定义的 taints value
# 先定义一个普通的Pod查看 是否能够运行
]# cat deploy-effect.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: my-myapp-effect
labels:
app: my-effect-first
spec:
replicas: 3
selector:
matchLabels:
app: my-effect-first
template:
metadata:
name: my-myapp-effect
labels:
app: my-effect-first
spec:
containers:
- name: my-myapp-effect
image: ikubernetes/myapp:v1
imagePullPolicy: IfNotPresent
# 当没有定义污点时,节点的NoSchedule 不允许没有定义Pod 容忍度的容器运行
spec:
# Pod内容不变
template:
# Pod内容不变
spec:
# Pod内容不变
tolerations:
- effect: NoSchedule
key: node-type
operator: Equal # 当定义 Equal时 key value必须相等
value: "qa"
]# kubectl get pods -o wide
NAME READY STATUS IP NODE
my-myapp-effect-6964b5756-cdmzs 1/1 Running 10.244.2.9 slave2
my-myapp-effect-6964b5756-j2mpm 1/1 Running 10.244.2.10 slave2
my-myapp-effect-6964b5756-js42g 1/1 Running 10.244.2.11 slave2
tolerations:
- effect: NoExecute
key: node-type
operator: Exists # 只需要 key跟effect能相等,那么就能匹配到对应节点的污点
value: "" # 此处需为空, 通配符匹配
]# kubectl get pods -o wide
NAME READY STATUS IP NODE
my-myapp-effect-65f65f8784-j8k2w 1/1 Running 10.244.1.14 slave1
my-myapp-effect-65f65f8784-s6n4t 1/1 Running 10.244.1.15 slave1
my-myapp-effect-65f65f8784-vftnh 1/1 Running 10.244.1.16 slave1
tolerations:
- effect: "" # 啥都不加 匹配所有
key: node-type # key必须要有
operator: Exists # 只需要 key跟effect能相等,那么就能匹配到对应节点的污点
value: "" # 此处需为空, 通配符匹配
# Pod会随机挑选一个节点运行。
Kubernetes在1.6之后引入了几个表达节点问题的几个污点,他们由Node Controller根据节点的实际状态在需要时自动添加;
key | 说明 |
---|---|
node.kubernetes.io/not-ready | 节点未就绪 |
node.kubernetes.io/unreachable | 节点不可达 |
node.kubernetes.io/unreachable | 磁盘耗尽 |
node.kubernetes.io/out-of-disk | 内存耗尽 |
node.kubernetes.io/disk-pressure | 磁盘耗尽 |
node.kubernetes.io/network-unavailable | 网络不可用 |
node.kubernetes.io/unschedulable | 不可被调度 |
node.kubernetes.io/uninitialized | 未被初始化 |