前言:
大部分情況下,kubernetes中的Pod只是容器的載體,通過Deployment、DaemonSet、RC、Job、Cronjob等對象來完成一組Pod的調度與自動控制功能。
Pod調度是由Scheduler組件完成的,可見圖中位置。
Scheduler工作原理
pod創建流程及Scheduler調度步驟:
- 節點預選(Predicate):排除完全不滿足條件的節點,如內存大小,端口等條件不滿足。基於一系列的預選規則對每個節點進行檢查,將那些不符合條件的節點過濾,從而完成節點的預選。
- 節點優先級排序(Priority):根據優先級選出最佳節點,對預選出的節點進行優先級排序,以便選出最合適運行Pod對象的節點。
- 節點擇優(Select):根據優先級選定節點,從優先級排序結果中挑選出優先級最高的節點運行Pod,當這類節點多於1個時,則進行隨機選擇。
1.首先用戶通過 Kubernetes 客戶端 Kubectl 提交創建 Pod 的 Yaml 的文件,向Kubernetes 系統發起資源請求,該資源請求被提交到
Kubernetes 系統中,用戶通過命令行工具 Kubectl 向 Kubernetes 集群即 APIServer 用 的方式發送“POST”請求,即創建 Pod 的請求。
2.APIServer 接收到請求后把創建 Pod 的信息存儲到 Etcd 中,從集群運行那一刻起,資源調度系統 Scheduler 就會定時去監控 APIServer
3.通過 APIServer 得到創建 Pod 的信息,Scheduler 采用 watch 機制,一旦 Etcd 存儲 Pod 信息成功便會立即通知APIServer,
4.APIServer會立即把Pod創建的消息通知Scheduler,Scheduler發現 Pod 的屬性中 Dest Node 為空時(Dest Node=””)便會立即觸發調度流程進行調度。
5.而這一個創建Pod對象,在調度的過程當中有3個階段:節點預選、節點優選、節點選定,從而篩選出最佳的節點
官網解析:https://kubernetes.io/docs/concepts/scheduling-eviction/kube-scheduler/
kube-scheduler 給一個 pod 做調度選擇包含兩個步驟: 1.過濾(節點預選),2.打分(節點優選,節點選定)
調度場景詳解
場景一:Deployment/RC:全自動調度
Deployment/RC主要是自動部署應用的多個副本,並持續監控,以維持副本的數量。默認是使用系統Master的Scheduler經過一系列算法計算來調度,用戶無法干預調度過程與結果。
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
labels:
app: nginx
spec:
replicas: 1
template:
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
restartPolicy: Always
selector:
matchLabels:
app: nginx
場景二:NodeSelector:定向調度
通過Node的標簽和Pod的nodeSelector屬性相匹配,可以達到將pod調度到指定的一些Node上。
#oc label nodes <node-name> env=dev
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
labels:
app: nginx
spec:
replicas: 1
template:
metadata:
name: nginx
labels:
app: nginx
spec:
nodeSelector:
env: 'node02'
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
restartPolicy: Always
場景三:Node親和性調度
目前有兩種親和性表達,NodeAffinity語法支持的操作符包括In/NotIn/Exists/DoesNotExist/Gt/Lt
In:label 的值在某個列表中
NotIn:label 的值不在某個列表中
Exists:某個 label 存在
DoesNotExist: 某個 label 不存在
Gt:label 的值大於某個值(字符串比較)
Lt:label 的值小於某個值(字符串比較
(1) RequiredDuringSchedulingIgnoreDuringExecution
必須滿足指定的規則才可以調度Pod到Node上(與nodeSelector類似),為硬限制
(2)PreferredDuringSchedulingIgnoreDuringExecution
強調優先滿足指定規則,調度器優先選擇合適的Node,但不強求,為軟限制。多個優先級規則還可以設置權重值,以定義執行的先后順序
注意事項
- 同時定義了nodeSelector與nodeAffinity,那必須兩個條件都滿足,Pod才被調度到指定的Node上。
- nodeAffinity指定了多個nodeSelectorTerms規格時(如:require或preferred),那么只需要滿足其中一個就能夠匹配成功就可以完成調度。
- nodeSelectorTerms中有多個matchExpressions,則一個節點必須滿足所有matchExpressions才能運行Pod。
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
restartPolicy: Always
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: env
operator: In
values:
- node02
- node01
preferredDuringSchedulingIgnoredDuringExecution:
- preference:
weight: 1
matchExpressions:
- key: disk
operator: In
values:
- ssd
這條規則表示,pod可以被調度到key為“env”,值為“node01”或“node02”的節點。另外,在滿足該條件的節點中,優先使用具有“disk”標簽,且值為“ssd”的節點。
場景四:POD親和性調度
POD親和性表示POD部署到滿足某些label的pod所在的NODE上.
(1)matchExpressions 表示符合label條件的pod,根據節點上正在運行的其它Pod的標簽來進行限制。
(2)topologyKey 表示作用域key,這里使用 kubernetes.io/hostname表示所有的節點,因為所有的節點默認都會打上這個標簽。
注意:PodAffinity規則設置注意事項
- RequiredDuringSchedulingIgnoreDuringExecution 必須滿足指定的規則才可以調度Pod到Node上(與nodeSelector類似),為硬限制
- PreferredDuringSchedulingIgnoreDuringExecution強調優先滿足指定規則,調度器優先選擇合適的Node,但不強求,為軟限制。多個優先級規則還可以設置權重值,以定義執行的先后順序
- 除了設置Label Selector和topologyKey,還可以指定namespaces列表來進行限制,namespaces定義與Label Selector和topologyKey同級。默認namespaces設置表示為Pod所在的namespaces,如果namespaces設置為“”則表示所有的namespaces。
*在所有關聯requiredDuringSchedulingIgnoredDuringExecution的matchExpressions全部滿足后,才將Pod調度到指定的Node上。
apiVersion: apps/v1beta1
kind: Deployment
metadata:
name: affinity
labels:
app: affinity
spec:
replicas: 3
revisionHistoryLimit: 15
template:
metadata:
labels:
app: affinity
role: test
spec:
containers:
- name: nginx
image: nginx:1.7.9
ports:
- containerPort: 80
name: nginxweb
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution: # 硬策略
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- nginx
topologyKey: kubernetes.io/hostname
這條規則表示,pod需要被調度到某個NODE節點上,該節點屬於kubernetes.io/hostname 這個域,並且上面運行了這樣的 pod:這個pod 有一個app=nginx的 label。
場景五:POD反親和性調度
POD反親和性表示POD不能部署到滿足某些label的pod所在的NODE上.
(1)matchExpressions 表示符合label條件的pod,根據節點上正在運行的其它Pod的標簽來進行限制。
(2)topologyKey 表示作用域key,這里使用 kubernetes.io/hostname表示所有的節點,因為所有的節點默認都會打上這個標簽。
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx
spec:
selector:
matchLabels:
app: nginx
replicas: 3
template:
metadata:
labels:
app: nginx
spec:
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- nginx
topologyKey: "kubernetes.io/hostname"
containers:
- name: nginx-server
image: nginx:latest
這條規則表示,pod不能被調度到某個NODE節點上,該節點屬於kubernetes.io/hostname 這個域,並且上面運行了這樣的 pod:這個pod 有一個app=nginx的 label。
場景六: Taints與Tolerations(污點與容忍)
Taints與前面的Affinity相反,它讓Node拒絕Pod的運行。為node添加一個Taint,效果是NoSchedule(除了NoSchedule還可以取值PreferNoSchedule/NoExecute)。意味着除非Pod明確聲明可以容忍這個Taint,否則不會被調度到該Node上。使用PodToleratesNodeTaints預選策略和TaintTolerationPriority優選函數完成該機制
定義污點和容忍度: 污點定義於nodes.spec.taints容忍度定義於pods.spec.tolerations 語法: key=value:effect
管理節點的污點: 同一個鍵值數據,effect不同,也屬於不同的污點
effect定義排斥等級:
NoSchedule:不能容忍,但僅影響調度過程,已調度上去的pod不受影響,僅對新增加的pod生效。
PreferNoSchedule:柔性約束,節點現存Pod不受影響,如果實在是沒有符合的節點,也可以調度上來
NoExecute:不能容忍,當污點變動時,Pod對象會被驅逐,如果Pod無法容忍NoExecute的Taint,則上面已經運行的Pod會被驅逐。
在Pod上定義容忍度時:
等值判斷 容忍度與污點在key、value、effect三者完全匹配
存在性判斷 key、effect完全匹配,value使用空值
一個節點可配置多個污點,一個Pod也可有多個容忍度
給節點添加污點:
#oc taint nodes <node-name> key1=value1:NoSchedule
#oc taint nodes <node-name> key1=value1:NoExecute
#oc taint nodes <node-name> key2=value2:NoSchedule
刪除節點污點:
kubectl taint node <node-name> <key>[:<effect>]-
kubectl patch nodes <node-name> -p '{"spec":{"taints":[]}}'
kubectl taint node kube-node1 node-type=production:NoSchedule
kubectl get nodes kube-node1 -o go-template={{.spec.taints}}
刪除key為env,effect為NoSchedule的污點:
kubectl taint node kube-node1 env:NoSchedule-
刪除key為env的所有污點:
kubectl taint node kube-node1 env-
刪除所有污點:
kubectl patch nodes kube-node1 -p '{"spec":{"taints":[]}}'
給Pod對象容忍度
spec.tolerations字段添加
tolerationSeconds用於定義延遲驅逐Pod的時長
等值判斷:
tolerations:
- key: "key1"
operator: "Equal" #判斷條件為Equal
value: "value1"
effect: "NoExecute"
tolerationSeconds: 3600
存在性判斷:
tolerations:
- key: "key1"
operator: "Exists" #存在性判斷,只要污點鍵存在,就可以匹配
effect: "NoExecute"
tolerationSeconds: 3600
問題節點標識:
自動為節點添加污點信息,使用NoExecute效用標識,會驅逐現有Pod,K8s核心組件通常都容忍此類污點:
node.kubernetes.io/not-ready 節點進入NotReady狀態時自動添加
node.alpha.kubernetes.io/unreachable 節點進入NotReachable狀態時自動添加
node.kubernetes.io/out-of-disk 節點進入OutOfDisk狀態時自動添加
node.kubernetes.io/memory-pressure 節點內存資源面臨壓力
node.kubernetes.io/disk-pressure 節點磁盤面臨壓力
node.kubernetes.io/network-unavailable 節點網絡不可用
node.cloudprovider.kubernetes.io/uninitialized kubelet由外部雲環境程序啟動時,自動添加,待到去控制器初始化此節點時再將其刪除
實例:
#oc taint nodes node01 key1=value1:NoSchedule
#oc taint nodes node02 key1=value1:NoExecute
#oc taint nodes node03 key2=value2:NoSchedule
apiVersion: v1
kind: Deployment
metadata:
name: myapp-deploy
namespace: default
spec:
replicas: 3
selector:
matchLabels:
app: myapp
release: canary
template:
metadata:
labels:
app: myapp
release: canary
spec:
containers:
- name: myapp
image: ikubernetes/myapp:v1
ports:
- name: http
containerPort: 80
tolerations:
- key: "env"
operator: "Equal"
value: "node02":
effect: "NoExecute"
tolerationSeconds: 3600
這條規則表示,該pod容忍env=node02 且 effect 為 NoExecute的節點。可以進行調度
場景七:DaemonSet調度:在每個Node上調度一個Pod
管理集群中每個Node上僅運行一份Pod的副本實例。
apiVersion: extensions/v1beta1
kind: DaemonSet
metadata:
labels:
component: fluentd
name: logging-fluentd
namespace: logging
spec:
selector:
matchLabels:
component: fluentd
template:
metadata:
labels:
component: fluentd
name: fluentd-elasticsearch
spec:
containers:
image: docker.io/openshift/origin-logging-fluentd:latest
imagePullPolicy: IfNotPresent
name: fluentd-elasticsearch
nodeSelector:
fluentd: true
這條規則表示,pod會在每一個符合調度的node 節點上啟動一個實例。該節點必須存在fluentd=true 的標簽。
結尾:
本文內容到此就結束了,優良的調度是分布式系統的核心。Scheduler調度器做為Kubernetes三大核心組件之一, 承載着整個集群資源的調度功能,其根據特定調度算法和策略,將Pod調度到最優工作節點上,從而更合理與充分的利用集群計算資源,使資源更好的服務於業務服務的需求。