一、前言
1、 NodeSelector:如果需要限制Pod到指定的Node
上運行,則可以給Node打標籤並給Pod配置NodeSelector。
2、NodeAffinity節點親和性,是Pod上定義的一種屬性,使Pod能夠按我們的要求調度到某個Node上,而Taints則恰恰相反,它可以讓Node拒絕運行Pod,甚至驅逐Pod。Taints(污點)是Node的一個屬性,設置了Taints(污點)後,因爲有了污點,所以Kubernetes是不會將Pod調度到這個Node上的,於是Kubernetes就給Pod設置了個屬性Tolerations(容忍),只要Pod能夠容忍Node上的污點,那麼Kubernetes就會忽略Node上的污點,就能夠(不是必須)把Pod調度過去。因此 Taints(污點)通常與Tolerations(容忍)配合使用。Taints 和 tolerations 用於保證 Pod 不被調度到不合適的 Node 上,Taint應用於Node上,而toleration則應用於Pod上(Toleration是可選的)
3、 Affinity 翻譯成中文是“親和性”,它對應的是 Anti-Affinity,我們翻譯成“互斥”。這兩個詞比較形象,可以把 pod 選擇 node 的過程類比成磁鐵的吸引和互斥,不同的是除了簡單的正負極之外,pod 和 node 的吸引和互斥是可以靈活配置的。
二、NodeSelector
2.1 給節點打標籤
# get node的name
$ kubectl get nodes
# 設置Label
$ kubectl label nodes <node-name> <label-key>=<label-value>
# 例如
$ kubectl label nodes node1 disktype=ssd
# 查看Node的Label
$ kubectl get nodes --show-labels
# 刪除Node的label
$ kubectl label node <node-name> <label-key>-
2.2 給Pod設置NodeSelector
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
env: test
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
nodeSelector:
disktype: ssd # 對應Node的Label
三、Taint
3.1 實驗環境
實驗環境是三節點的集羣,採用kubeadm部署,部署請參考我的另一篇文章
3.2 實驗流程
1、給節點打上污點
node打上污點(可以想象成一個標籤),pod如果不定義容忍這個污點,那麼pod就不會被調度器分配到這個node
匹配規則:
一個 toleration 和一個 taint 相“匹配”是指它們有一樣的 key 和 effect ,並且:
如果 operator
是 Exists
(此時 toleration 不能指定 value
)
如果 operator
是 Equal
,則它們的 value
應該相等
特殊情況:
如果一個 toleration 的 key
爲空且 operator 爲 Exists
,表示這個 toleration 與任意的 key 、 value 和 effect 都匹配,即這個 toleration 能容忍任意 taint。
tolerations:
- operator: "Exists"
如果一個 toleration 的 effect
爲空,則 key
值與之相同的相匹配 taint 的 effect
可以是任意值。
tolerations:
- key: "key"
operator: "Exists"
一個節點可以設置多個taint,一個pod也可以設置多個toleration。Kubernetes 處理多個 taint 和 toleration 的過程就像一個過濾器:從一個節點的所有 taint 開始遍歷,過濾掉那些 pod 中存在與之相匹配的 toleration 的 taint。餘下未被過濾的 taint 的 effect 值決定了 pod 是否會被分配到該節點,特別是以下情況:
- 如果未被過濾的 taint 中存在一個以上 effect 值爲
NoSchedule
的 taint,則 Kubernetes 不會將 pod 分配到該節點。 - 如果未被過濾的 taint 中不存在 effect 值爲
NoSchedule
的 taint,但是存在 effect 值爲PreferNoSchedule
的 taint,則 Kubernetes 會嘗試將 pod 分配到該節點。 - 如果未被過濾的 taint 中存在一個以上 effect 值爲
NoExecute
的 taint,則 Kubernetes 不會將 pod 分配到該節點(如果 pod 還未在節點上運行),或者將 pod 從該節點驅逐(如果 pod 已經在節點上運行)。
目前支持的 taint 類型(也被稱爲effect):
NoSchedule:K8S的node添加這個effect類型污點,新的不能容忍的pod不能再調度過來,但是老的運行在node上不受影響
NoExecute:K8S的node添加這個effect類型污點,新的不能容忍的pod不能調度過來,老的pod也會被驅逐
PreferNoSchedule:儘量不要調度到該節點,但pod會嘗試將pod分配到該節點
effect 值 NoExecute
,它會影響已經在節點上運行的 pod,即根據策略對Pod進行驅逐。
- 如果 pod 不能忍受effect 值爲
NoExecute
的 taint,那麼 pod 將馬上被驅逐 - 如果 pod 能夠忍受effect 值爲
NoExecute
的 taint,但是在 toleration 定義中沒有指定tolerationSeconds
,則 pod 還會一直在這個節點上運行。 - 如果 pod 能夠忍受effect 值爲
NoExecute
的 taint,而且指定了tolerationSeconds
,則 pod 還能在這個節點上繼續運行這個指定的時間長度。
# 查詢節點名字
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
node1 Ready master 28d v1.15.4
node2 Ready <none> 28d v1.15.4
node3 Ready <none> 28d v1.15.4
# 給node1節點打上key值爲project,value值爲ops,驅逐模式爲NoSchedule
$ kubectl taint node node1 project=ops:NoSchedule
# 給node2節點打上key值爲project,value值爲ops,驅逐模式爲NoSchedule
$ kubectl taint node node2 project=ops:NoSchedule
# 給node3節點打上key值爲project,value值爲ops,驅逐模式爲NoSchedule
$ kubectl taint node node3 project=ops:NoSchedule
2、deployment設置容忍
apiVersion: apps/v1Beta1
kind: Deployment
metadata:
name: nginx-deploy
spec:
replicas: 1
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx
images: nginx:laste
ports:
- containerPort: 80
tolerations:
- key: "project"
operator: "Equal"
value: "ops"
effect: "NoSchedule"
可以看到 如果pod打上這個污點,那麼這個pod就會分配到這個node1,其他pod未打污點無法分配,並且old的pod也被驅趕出這個node。
有時候在master節點上也安裝了docker,但是又不想讓master既作爲主節點又做爲node節點,避免讓pod調度到master上,方法如下:
# master節點名稱爲node1
$ kubectl taint node node1 node-role.kubernetes.io/master=node1:NoSchedule
四、親和性
Affinity 翻譯成中文是“親和性”,它對應的是 Anti-Affinity,我們翻譯成“互斥”。這兩個詞比較形象,可以把 pod 選擇 node 的過程類比成磁鐵的吸引和互斥,不同的是除了簡單的正負極之外,pod 和 node 的吸引和互斥是可以靈活配置的。
Affinity的優點:
- 匹配有更多的邏輯組合,不只是字符串的完全相等
- 調度分成軟策略(soft)和硬策略(hard),在軟策略下,如果沒有滿足調度條件的節點,pod會忽略這條規則,繼續完成調度。
目前主要的node affinity:
-
requiredDuringSchedulingIgnoredDuringExecution
表示pod必須部署到滿足條件的節點上,如果沒有滿足條件的節點,就不停重試。其中IgnoreDuringExecution表示pod部署之後運行的時候,如果節點標籤發生了變化,不再滿足pod指定的條件,pod也會繼續運行。 -
requiredDuringSchedulingRequiredDuringExecution
表示pod必須部署到滿足條件的節點上,如果沒有滿足條件的節點,就不停重試。其中RequiredDuringExecution表示pod部署之後運行的時候,如果節點標籤發生了變化,不再滿足pod指定的條件,則重新選擇符合要求的節點。 -
preferredDuringSchedulingIgnoredDuringExecution
表示優先部署到滿足條件的節點上,如果沒有滿足條件的節點,就忽略這些條件,按照正常邏輯部署。 -
preferredDuringSchedulingRequiredDuringExecution
表示優先部署到滿足條件的節點上,如果沒有滿足條件的節點,就忽略這些條件,按照正常邏輯部署。其中RequiredDuringExecution表示如果後面節點標籤發生了變化,滿足了條件,則重新調度到滿足條件的節點。
軟策略和硬策略的區分是有用處的,硬策略適用於 pod 必須運行在某種節點,否則會出現問題的情況,比如集羣中節點的架構不同,而運行的服務必須依賴某種架構提供的功能;軟策略不同,它適用於滿不滿足條件都能工作,但是滿足條件更好的情況,比如服務最好運行在某個區域,減少網絡傳輸等。這種區分是用戶的具體需求決定的,並沒有絕對的技術依賴。
下面是一個官方的示例:
apiVersion: v1
kind: Pod
metadata:
name: with-node-affinity
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/e2e-az-name
operator: In
values:
- e2e-az1
- e2e-az2
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1
preference:
matchExpressions:
- key: another-node-label-key
operator: In
values:
- another-node-label-value
containers:
- name: with-node-affinity
image: gcr.io/google_containers/pause:2.0
這個 pod 同時定義了 requiredDuringSchedulingIgnoredDuringExecution 和 preferredDuringSchedulingIgnoredDuringExecution 兩種 nodeAffinity。第一個要求 pod 運行在特定 AZ 的節點上,第二個希望節點最好有對應的 another-node-label-key:another-node-label-value 標籤。
這裏的匹配邏輯是label在某個列表中,可選的操作符有:
- In: label的值在某個列表中
- NotIn:label的值不在某個列表中
- Exists:某個label存在
- DoesNotExist:某個label不存在
- Gt:label的值大於某個值(字符串比較)
- Lt:label的值小於某個值(字符串比較)
如果nodeAffinity中nodeSelector有多個選項,節點滿足任何一個條件即可;如果matchExpressions有多個選項,則節點必須同時滿足這些選項才能運行pod 。
需要說明的是,node並沒有anti-affinity這種東西,因爲NotIn和DoesNotExist能提供類似的功能。