1.Kubernetes Scheduler簡介
Kubernetes 調度器(Scheduler)是Kubernetes的核心組件;用戶或者控制器創建Pod之后,調度器通過 kubernetes 的 watch 機制來發現集群中新創建且尚未被調度到 Node 上的 Pod。調度器會將發現的每一個未調度的 Pod 調度到一個合適的 Node 上來運行。調度器會依據下文的調度原則來做出調度選擇。
kube-scheduler 給一個 pod 做調度選擇包含兩個步驟:過濾、打分
過濾階段:會將所有滿足 Pod 調度需求的 Node 選出來。例如,PodFitsResources 過濾函數會檢查候選 Node 的可用資源能否滿足 Pod 的資源請求。在過濾之后,得出一個 Node 列表,里面包含了所有可調度節點;通常情況下,這個 Node 列表包含不止一個 Node。如果這個列表是空的,代表這個 Pod 不可調度。
我們可以使用多種規則比如:
- 設置cpu、內存的使用要求;
- 增加node的label,並通過pod.Spec.NodeSelector進行強匹配;
- 直接設置pod的nodeName,跳過調度直接下發。
注:k8s 1.2加入了一個實驗性的功能:affinity。意為親和性。這個特性的設計初衷是為了替代nodeSelector,並擴展更強大的調度策略。
2.Scheduler工作原理
- 節點預選(Predicate):排除完全不滿足條件的節點,如內存大小,端口等條件不滿足。
- 節點優先級排序(Priority):根據優先級選出最佳節點
- 節點擇優(Select):根據優先級選定節點
-
首先用戶通過 Kubernetes 客戶端 Kubectl 提交創建 Pod 的 Yaml 的文件,向Kubernetes 系統發起資源請求,該資源請求被提交到
-
Kubernetes 系統中,用戶通過命令行工具 Kubectl 向 Kubernetes 集群即 APIServer 用 的方式發送“POST”請求,即創建 Pod 的請求。
-
APIServer 接收到請求后把創建 Pod 的信息存儲到 Etcd 中,從集群運行那一刻起,資源調度系統 Scheduler 就會定時去監控 APIServer
-
通過 APIServer 得到創建 Pod 的信息,Scheduler 采用 watch 機制,一旦 Etcd 存儲 Pod 信息成功便會立即通知APIServer,
-
APIServer會立即把Pod創建的消息通知Scheduler,Scheduler發現 Pod 的屬性中 Dest Node 為空時(Dest Node=””)便會立即觸發調度流程進行調度。
-
而這一個創建Pod對象,在調度的過程當中有3個階段:節點預選、節點優選、節點選定,從而篩選出最佳的節點
-
節點預選:基於一系列的預選規則對每個節點進行檢查,將那些不符合條件的節點過濾,從而完成節點的預選
-
節點優選:對預選出的節點進行優先級排序,以便選出最合適運行Pod對象的節點
-
節點選定:從優先級排序結果中挑選出優先級最高的節點運行Pod,當這類節點多於1個時,則進行隨機選擇
-
3.Pod調度
Kubernetes中,Pod通常是容器的載體,一般需要通過Deployment、DaemonSet、RC、Job等對象來完成一組Pod的調度與自動控制功能。
3.1 Depolyment/RC自動調度
Deployment或RC的主要功能之一就是自動部署一個容器應用的多份副本,以及持續監控副本的數量,在集群內始終維持用戶指定的副本數量。
[root@uk8s-m-01 study]# vi nginx-deployment.yaml apiVersion: apps/v1beta1 kind: Deployment metadata: name: nginx-deployment-01 spec: replicas: 3 template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.7.9 ports: - containerPort: 80 [root@uk8s-m-01 study]# kubectl get deployments NAME READY UP-TO-DATE AVAILABLE AGE nginx-deployment-01 3/3 3 3 30s [root@uk8s-m-01 study]# kubectl get rs NAME DESIRED CURRENT READY AGE nginx-deployment-01-5754944d6c 3 3 3 75s [root@uk8s-m-01 study]# kubectl get pod | grep nginx nginx-deployment-01-5754944d6c-hmcpg 1/1 Running 0 84s nginx-deployment-01-5754944d6c-mcj8q 1/1 Running 0 84s nginx-deployment-01-5754944d6c-p42mh 1/1 Running 0 84s
3.2 NodeSelector定向調度
當需要手動指定將Pod調度到特定Node上,可以通過Node的標簽(Label)和Pod的nodeSelector屬性相匹配。
# kubectl label nodes <node-name> <label-key>=<label-value>
node節點創建對應的label后,可通過在定義Pod的時候加上nodeSelector的設置實現指定的調度。
[root@uk8s-m-01 study]# kubectl label nodes 172.24.9.14 speed=io node/172.24.9.14 labeled [root@uk8s-m-01 study]# vi nginx-master-controller.yaml kind: ReplicationController metadata: name: nginx-master labels: name: nginx-master spec: replicas: 1 selector: name: nginx-master template: metadata: labels: name: nginx-master spec: containers: - name: master image: nginx:1.7.9 ports: - containerPort: 80 nodeSelector: speed: io [root@uk8s-m-01 study]# kubectl create -f nginx-master-controller.yaml [root@uk8s-m-01 study]# kubectl get pods -o wide NAME READY STATUS RESTARTS AGE IP NODE nginx-master-7fjgj 1/1 Running 0 82s 172.24.9.71 172.24.9.14
3.3 NodeAffinity親和性調度
- 更具表達力,即更精細的力度控制;
- 可以使用軟限制、優先采用等限制方式,即調度器在無法滿足優先需求的情況下,會使用其他次條件進行滿足;
- 可以依據節點上正在運行的其他Pod的標簽來進行限制,而非節點本身的標簽,從而實現Pod之間的親和或互斥關系。
- requiredDuringSchedulingIgnoredDuringExecution:硬規則,必須滿足指定的規則,調度器才可以調度Pod至Node上(類似nodeSelector,語法不同)。
- preferredDuringSchedulingIgnoredDuringExecution:軟規則,優先調度至滿足的Node的節點,但不強求,多個優先級規則還可以設置權重值。
- IgnoredDuringExecution指:如果一個Pod所在的節點在Pod運行期間標簽發生了變化,不再符合該Pod的節點親和性需求,則系統將忽略Node上Label的變化,該Pod能繼續在該節點運行。
示例:條件1:只運行在amd64的節點上;盡量運行在ssd節點上。
[root@uk8s-m-01 study]# vi nodeaffinity-pod.yaml apiVersion: v1 kind: Pod metadata: name: with-node-affinity spec: affinity: nodeAffinity: requiredDuringSchedulingIgnoredDuringExecution: nodeSelectorTerms: - matchExpressions: - key: kubernetes.io/arch operator: In values: - amd64 preferredDuringSchedulingIgnoredDuringExecution: - weight: 1 preference: matchExpressions: - key: disk-type operator: In values: - ssd containers: - name: with-node-affinity image: gcr.azk8s.cn/google_containers/pause:2.0
NodeAffinity操作語法;In、NotIn、Exists、DoesNotExist、Gt、Lt。NotIn和DoesNotExist可以實現互斥功能。
NodeAffinity規則設置注意事項:
- 若同時定義nodeSelector和nodeAffinity,則必須兩個條件都滿足,Pod才能最終運行指定在Node上;;
- 若nodeAffinity指定多個nodeSelectorTerms,則只需要其中一個能夠匹配成功即可;
- 若nodeSelectorTerms中有多個matchExpressions,則一個節點必須滿足所有matchExpressions才能運行該Pod。
3.4 PodAffinity親和性調度
PodAffinity根據節點上正在運行的Pod標簽而不是Node標簽來判斷和調度,要求對節點和Pod兩個條件進行匹配。
規則描述為:若在具有標簽X的Node上運行了一個或多個符合條件Y的Pod,則Pod應該(或者不應該)運行在這個Node上。
X通常為Node節點的機架、區域等概念,Pod是屬於某個命名空間,所以條件Y表達的是一個或全部命名空間中的一個Label Selector。
Pod親和性定義與PodSpec的affinity字段下的podAffinity字段里,互斥性定義於同一層次的podAntiAffinity子字段中。
[root@uk8s-m-01 study]# vi nginx-flag.yaml #創建名為pod-flag,帶有兩個標簽的Pod apiVersion: v1 kind: Pod metadata: name: pod-affinity spec: affinity: podAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: security operator: In values: - S1 topologyKey: kubernetes.io/hostname containers: - name: with-pod-affinity image: gcr.azk8s.cn/google_containers/pause:2.0
[root@uk8s-m-01 study]# vi nginx-affinity-in.yaml #創建定義標簽security=S1,對應如上Pod “Pod-flag”。 apiVersion: v1 kind: Pod metadata: name: pod-affinity spec: affinity: podAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: security operator: In values: - S1 topologyKey: kubernetes.io/hostname containers: - name: with-pod-affinity image: gcr.azk8s.cn/google_containers/pause:2.0 [root@uk8s-m-01 study]# kubectl create -f nginx-affinity-in.yaml [root@uk8s-m-01 study]# kubectl get pods -o wide
提示:由上Pod親和力可知,兩個Pod處於同一個Node上。
[root@uk8s-m-01 study]# vi nginx-affinity-out.yaml #創建不能與參照目標Pod運行在同一個Node上的調度策略 apiVersion: v1 kind: Pod metadata: name: anti-affinity spec: affinity: podAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: security operator: In values: - S1 topologyKey: failure-domain.beta.kubernetes.io/zone podAntiAffinity: requiredDuringSchedulingIgnoredDuringExecution: - labelSelector: matchExpressions: - key: security operator: In values: - nginx topologyKey: kubernetes.io/hostname containers: - name: anti-affinity image: gcr.azk8s.cn/google_containers/pause:2.0 [root@uk8s-m-01 study]# kubectl get pods -o wide #驗證
3.5 Taints和Tolerations(污點和容忍)
Taint:使Node拒絕特定Pod運行;
Toleration:為Pod的屬性,表示Pod能容忍(運行)標注了Taint的Node。
Taint語法:$ kubectl taint nodes node1 key=value:NoSchedule
解釋:為node1加上一個Taint,該Taint的鍵為key,值為value,Taint的效果為NoSchedule。即除非特定聲明可以容忍此Taint,否則不會調度至node1上。
tolerations: - key: "key1" operator: "Equal" value: "value1" effect: "NoSchedule"
或
tolerations: - key: "key1" operator: "Exists" effect: "NoSchedule"
- operator的值是Exists(無須指定value);
- operator的值是Equal並且value相等;
- 空的key配合Exists操作符能夠匹配所有的鍵和值;
- 空的effect匹配所有的effect。
若不指定operator,則默認值為Equal。
taint說明:系統允許在同一個Node上設置多個taint,也可以在Pod上設置多個toleration。Kubernetes調度器處理多個taint和toleration的邏輯順序:首先列出節點中所有的taint,然后忽略pod的toleration能夠匹配的部分,剩下的沒有忽略掉的taint就是對pod的效果。以下是幾種特殊情況:
- 若剩余的taint中存在effect=NoSchedule,則調度器不會把該Pod調度到這一節點上;
- 若剩余的taint中沒有NoSchedule效果,但有PreferNoSchedule效果,則調度器會嘗試不把這個Pod指派到此節點;
- 若剩余taint的效果有NoSchedule,並且這個Pod已經在該節點上運行,則會被驅逐,若沒有在該節點上運行,也不會再被調度到該節點上。
$ kubectl taint node node1 key=value1:NoSchedule $ kubectl taint node node1 key=value1:NoExecute $ kubectl taint node node1 key=value2:NoSchedule tolerations: - key: "key1" operator: "Equal" value: "value" effect: "NoSchedule" tolerations: - key: "key1" operator: "Equal" value: "value1" effect: "NoExecute"
釋義:此Pod聲明了兩個容忍,且能匹配Node1的taint,但是由於沒有能匹配第三個taint的toleration,因此此Pod依舊不能調度至此Node。若該Pod已經在node1上運行了,那么在運行時設置了第3個taint,它還能繼續在node1上運行,這是因為Pod可以容忍前兩個taint。
通常,若node加上effect=NoExecute的taint,那么該Node上正在運行的所有無對應toleration的Pod都會被立刻驅逐,而具有相應toleration的Pod則永遠不會被驅逐。同時,系統可以給具有NoExecute效果的toleration加入一個可選的tolerationSeconds字段,表明Pod可以在taint添加到Node之后還能在此Node運行多久。
tolerations: - key: "key1" operator: "Equal" value: "value" effect: "NoSchedule" tolerationSeconds: 3600
釋義:若Pod正在運行,所在節點被加入一個匹配的taint,則這個pod會持續在該節點運行3600s后被驅逐。若在此期限內,taint被移除,則不會觸發驅逐事件。
- 獨占節點:
給特定的節點運行特定應用。
$ kubectl taint nodes 【nodename】 dedicated=groupName:NoSchedule
同時在Pod中設置對應的toleration配合,帶有合適toleration的Pod允許同時使用其他節點一樣使用有taint的節點。
- 具有特殊硬件設備的節點
集群中部分特殊硬件(如安裝了GPU),則可以把不需要占用GPU的Pod禁止在此Node上調度。
1 $ kubectl taint nodes 【nodename】 special=true:NoSchedule 2 $ kubectl taint nodes 【nodename】 special=true:PreferNoSchedule
- 定義Pod驅逐行為
NoExecute的taint對節點上正在運行的Pod有以下影響:
- 沒有設置toleration的pod會被立刻驅逐;
- 配置了對應toleration的pod,若沒有為tolerationSeconds賦值,則會一直保留在此節點中;
- 配置了對應toleration的pod,且為tolerationSeconds賦值,則在指定時間后驅逐。
3.6 nodeName
apiVersion: v1 kind: Pod metadata: name: nginx spec: containers: - name: nginx image: nginx nodeName: kube-01
注:上面的 pod 將指定運行在 kube-01 節點上。
使用 nodeName
來選擇節點的一些限制:
- 如果指定的節點不存在,
- 如果指定的節點沒有資源來容納 Pod,Pod 將會調度失敗並且其原因將顯示為, 比如 OutOfmemory 或 OutOfcpu。
- 雲環境中的節點名稱並非總是可預測或穩定的