運維實戰 容器部分 Kubernetes排程
- 需求簡介
- 具體排程方法
-
- nodeName
- nodeSelector
- 親和與反親和
-
- 節點親和
- Pod親和
- Taints
-
- Taints設定的取值
- Tolerations相關設定
需求簡介
- 生産環境有對
排程規劃的真實需求, 比如端口沖突的業務不能部署在同一實體機如何實作, 比如某些業務盡可能部署在同一實體機如何實作Pod
- 排程器通過
的K8S
機制來發現叢集中新建立且尚未被排程到watch
上的Node
. 排程器會将發現的每一個未排程的Pod
排程到一個合适的Pod
上來運作.Node
- 叢集預設使用
作為排程器, 可以自行編寫排程元件替換原有的kube-scheduler
kube-scheduler
- 也可以在資源清單中指定使用的排程政策
- 做排程配置設定時需要考慮許多要素, 如: 單獨和整體的資源請求, 硬體/軟體/政策限制, 親和以及反親和要求, 資料局限性, 負載間的幹擾等等
具體排程方法
nodeName
-
是最簡單的節點限制方法, 通常來說不推薦使用nodeName
- 通過在資源清單中指定
,Node
會被自動部署到該Pod
上, 但如果Node
不存在, 叢集也會嘗試這麼做, 因而導緻Node
Pending
局限性
- 指定的節點不存在時不會隻能解決
- 節點存在, 但不滿足實體需求(如資源/空間不足), 排程也會失敗
- 在生産環境中
的名稱并不總是穩定/可預測的Node
-
檔案内容nodeName.yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- name: nginx
image: nginx
nodeName: server3
- 測試結果
[[email protected] Schedule]# kubectl apply -f nodeName.yaml
Pod/nginx created
[[email protected] Schedule]# kubectl get Pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx 1/1 Running 0 10s 10.244.141.226 server3 <none> <none>
- 如果叢集中沒有符合條件的
, 比如上面的Node
改成server3
server10
apiVersion: v1
kind: Pod
metadata:
name: nginx
spec:
containers:
- name: nginx
image: nginx
nodeName: server10
- 則會出現排程失敗, 并不會隻能解決
- 因為叢集中不存在
而你又要求排程到server10
上, 就會一直server10
Pending
[[email protected] Schedule]# kubectl delete Pod nginx
Pod "nginx" deleted
[[email protected] Schedule]# kubectl get Pod -o wide
No resources found in default namespace.
[[email protected] Schedule]# kubectl apply -f nodeName.yaml
Pod/nginx created
[[email protected] Schedule]# kubectl get Pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx 0/1 Pending 0 1s <none> server10 <none> <none>
nodeSelector
想必你也注意到了,
nodeName
并不能指定一類機器, 而隻能指定固定機器
如果我們想定義一類具有同樣特點的機器, 如這些機器都使用固态硬碟, 可以通過對節點打
tag
的方式來實作
與之對應,
nodeSelector
是通過
tag
進行排程篩選的機制, 也是節點選擇限制的最簡單推薦形式
-
檔案内容nodeSelector.yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
env: test
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
nodeSelector:
disktype: ssd
- 測試流程
[[email protected] Schedule]# kubectl apply -f nodeSelector.yaml
Pod/nginx created
[[email protected] Schedule]# kubectl get Pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx 0/1 Pending 0 9s <none> <none> <none> <none>
- 此時, 所有結點上都沒有
标簽是以disktype: ssd
Pending
- 對
附加server3
的标簽後, 排程正确實作disktype=ssd
[[email protected] Schedule]# kubectl label nodes server3 disktype=ssd
node/server3 labeled
[[email protected] Schedule]# kubectl get Pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx 1/1 Running 0 67s 10.244.141.227 server3 <none> <none>
親和與反親和
- 實作了 “硬要求” 和 “軟需求” 并存, 如"必須滿足A, 盡量滿足B(B不滿足也可以)"這類需求, 這極大擴充了表達限制的類型
- 親和和反親和不止支援節點标簽, 也支援
标簽, 如Pod
隻能放在B服務
不存在的A服務
上這種需求Node
節點親和
參數 | 含義 |
---|---|
requiredDuringSchedulingIgnoredDuringExecution | 必須滿足 |
preferredDuringSchedulingIgnoredDuringExecution | 傾向滿足 |
雖然這個參數很長, 但實際上是由兩部分構成的, 前半部分表示
軟/硬
後半部分的
IgnoreDuringExecution
表示如果在
Pod
運作期間
Node
的标簽發生變化, 導緻親和性政策不能滿足, 則繼續運作目前的
Pod
, 而不直接驅離
nodeaffinity
還支援多種規則比對條件的配置
參數 | 含義 |
---|---|
In | 的值在清單内 |
NotIn | 的值不在清單内 |
Gt | 的值大于設定的值, 不支援 親和性 |
Lt | 的值小于設定的值, 不支援 親和性 |
Exists | 設定的 存在 |
DoesNotExist | 設定的 不存在 |
- 測試用
檔案内容node-affinity.yaml
apiVersion: v1
kind: Pod
metadata:
name: node-affinity
spec:
containers:
- name: nginx
image: nginx
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: disktype
operator: In
values:
- ssd
- 這裡的需求是 滿足
的節點,disktype=ssd
+key
+operator
共同完成了這一指名values
- 測試流程, 可以看到測試用的
被排程到了node-affinity
上server3
[[email protected] Schedule]# kubectl apply -f nodeAffinity_required.yaml
Pod/node-affinity created
[[email protected] Schedule]# kubectl get Pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
node-affinity 1/1 Running 0 5s 10.244.141.228 server3 <none> <none>
傾向滿足
的案例
apiVersion: v1
kind: Pod
metadata:
name: node-affinity
spec:
containers:
- name: nginx
image: nginx
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: NotIn
values:
- server3
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: disktype
operator: In
values:
- ssd
在這個資源清單中存在兩條要求:
- 必須滿足 不能排程到
上server3
- 傾向滿足
包含Node
的disktype=ssd
tag
這樣, 即使
server4
上并沒有這個
tag
, 也可以排程到
server4
上了
Pod親和
-
主要解決PodAffinity
可以和哪些Pod
部署在同一個拓撲域中的問題(拓撲域用主機标簽實作, 可以是單個主機, 也可以是多個主機組成的Pod
,cluster
等.) 與之效能相反的zone
主要解決PodAntiAffinity
不能和哪些Pod
部署在同一個拓撲域中的問題. 它們處理的是Pod
叢集内部Kubernetes
和Pod
之間的關系.Pod
-
間親和與反親和在與更進階别的集合(例如Pod
,ReplicaSets
,StatefulSets
等)一起使用時, 它們可能更加有用. 可以輕松配置一組應位于相同定義拓撲(例如, 節點)中的工作負載.Deployments
-
間親和與反親和需要大量的處理, 這可能會顯著減慢大規模叢集中的排程. \Pod
測試樣例
- 建立一個自主的包含
服務的nginx
Pod
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
- 建立一個包含
親和需求的資源清單Pod
apiVersion: v1
kind: Pod
metadata:
name: mysql
labels:
app: mysql
spec:
containers:
- name: mysql
image: mysql
env:
- name: "MYSQL_ROOT_PASSWORD"
value: "westos"
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- nginx
topologyKey: kubernetes.io/hostname
[[email protected] Schedule]# kubectl apply -f nodeName.yaml
Pod/nginx created
[[email protected] Schedule]# kubectl get Pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATESnginx 1/1 Running 0 11s 10.244.141.230 server3 <none> <none>
[[email protected] Schedule]# kubectl apply -f PodAffinity.yaml
Pod/demo created
[[email protected] Schedule]# kubectl get Pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATESdemo 1/1 Running 0 6s 10.244.22.25 server4 <none> <none> nginx
1/1 Running 0 54s 10.244.141.230 server3 <none> <none>
可以看到, 兩個
Pod
分别被排程到了2個不同的
Node
Taints
NodeAffinity
節點親和性的目的是讓
Pod
可以按照我們的需求排程到一個或一類
Node
上;
Taints
與之相反, 它能讓
Node
拒絕運作
Pod
, 甚至驅離已經在該
Node
上運作的
Pod
Taints
(污點)是
Node
的一個屬性, 設定了
Taints
後,
K8S
叢集就不會把
Pod
排程到這個
Node
上了
如果想讓
Pod
排程到有
Taints
的節點, 就需要給
Pod
設定
Tolerations
(容忍)屬性
主節點上天生具有
Taints
, 是以才有了預設不會排程到主節點上的說法
- 相關指令
##為node1增加一個NoSchedule(不允許排程)的污點
kubectl taint nodes node1 key=value:NoSchedule
##查詢server1上的污點情況
kubectl describe nodes server1 |grep Taints
##删除node1上的NoSchedule(不允許排程)污點屬性
$ kubectl taint nodes node1 key:NoSchedule-
- 一個标準的
控制器部署Deployment
的清單nginx
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-server
spec:
selector:
matchLabels:
app: nginx
replicas: 3
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
- 主節點預設不允許排程
[[email protected] Schedule]# kubectl describe nodes server2 |grep TaintsTaints:
node-role.kubernetes.io/master:NoSchedule
- 為Server4增加驅離屬性
[[email protected] Schedule]# kubectl taint node server4 key1=v1:NoExecute
node/server4 tainted
[[email protected] Schedule]# kubectl get Pod -o wide
- 如果設定正确, 你将隻會在
上看到server3
, 因為Pod
和server2
都不能用于部署server4
- 增加容忍設定的版本
apiVersion: apps/v1
kind: Deployment
metadata:
name: web-server
spec:
selector:
matchLabels:
app: nginx
replicas: 3
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
tolerations:
- key: "key1"
operator: "Equal"
value: "v1"
effect: "NoExecute"
Taints設定的取值
參數 | 含義 |
---|---|
NoSchedule | 不會被排程到标記節點 |
PreferNoSchedule | NoSchedule 的軟政策版本 |
NoExecute | 不會排程到标記節點, 并且該節點内的 如無對應的 設定還會被驅逐 |
Tolerations相關設定
Tolerations
中定義的
key
,
value
,
effect
, 要與
node
上設定的
taint
保持一緻, 但并不是都要填寫
- 當
為operator
時, 可以省略Exists
value
- 當
為operator
時,Equal
與key
之間的關系必須相等value
- 如果不指定
屬性, 則預設值為operator
Equal
- 當不指定
, 再配合key
就能比對所有的Exists
與key
, 可以容忍所有污點value
- 當不指定
, 則比對所有的effect
effect
tolerations:
- key: "key"
operator: "Equal"
value: "value"
effect: "NoSchedule"
對滿足key=value 且污點政策為NoSchedule的節點進行容忍
tolerations:
- operator: "Exists"
effect: "NoSchedule"
容忍所有污點并不驅離