一般情況下我們部署的 Pod 是通過集群的自動調(diào)度策略來選擇節(jié)點的只搁,默認情況下調(diào)度器考慮的是資源足夠,并且負載盡量平均突诬,但是有的時候我們需要能夠更加細粒度的去控制 Pod 的調(diào)度,比如我們內(nèi)部的一些服務(wù) gitlab 之類的也是跑在Kubernetes集群上的,我們就不希望對外的一些服務(wù)和內(nèi)部的服務(wù)跑在同一個節(jié)點上了葵第,擔(dān)心內(nèi)部服務(wù)對外部的服務(wù)產(chǎn)生影響;但是有的時候我們的服務(wù)之間交流比較頻繁合溺,又希望能夠?qū)⑦@兩個服務(wù)的 Pod 調(diào)度到同一個的節(jié)點上卒密。這就需要用到 Kubernetes 里面的一個概念:親和性和反親和性。
親和性有分成節(jié)點親和性(nodeAffinity)和 Pod 親和性(podAffinity)棠赛。
nodeSelector
在了解親和性之前哮奇,我們先來了解一個非常常用的調(diào)度方式:nodeSelector膛腐。我們知道label是kubernetes中一個非常重要的概念,用戶可以非常靈活的利用 label 來管理集群中的資源鼎俘,比如最常見的一個就是 service 通過匹配 label 去匹配 Pod 資源哲身,而 Pod 的調(diào)度也可以根據(jù)節(jié)點的 label 來進行調(diào)度。
我們可以通過下面的命令查看我們的 node 的 label:
$ kubectl get nodes --show-labels
NAME STATUS ROLES AGE VERSION LABELS
master Ready master 147d v1.10.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/hostname=master,node-role.kubernetes.io/master=
node02 Ready <none> 67d v1.10.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,course=k8s,kubernetes.io/hostname=node02
node03 Ready <none> 127d v1.10.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,jnlp=haimaxy,kubernetes.io/hostname=node03
現(xiàn)在我們先給節(jié)點node02增加一個com=youdianzhishi的標簽贸伐,命令如下:
$ kubectl label nodes node02 com=youdianzhishi
node "node02" labeled
我們可以通過上面的--show-labels參數(shù)可以查看上述標簽是否生效勘天。當 node 被打上了相關(guān)標簽后,在調(diào)度的時候就可以使用這些標簽了捉邢,只需要在 Pod 的spec字段中添加nodeSelector字段脯丝,里面是我們需要被調(diào)度的節(jié)點的 label 即可。比如伏伐,下面的 Pod 我們要強制調(diào)度到 node02 這個節(jié)點上去巾钉,我們就可以使用 nodeSelector 來表示了:(node-selector-demo.yaml)
apiVersion: v1
kind: Pod
metadata:
labels:
app: busybox-pod
name: test-busybox
spec:
containers:
- command:
- sleep
- "3600"
image: busybox
imagePullPolicy: Always
name: test-busybox
nodeSelector:
com: youdianzhishi
然后我們可以通過 describe 命令查看調(diào)度結(jié)果:
$ kubectl create -f node-selector-demo.yaml
pod "test-busybox" created
$ kubectl describe pod test-busybox
Name: test-busybox
Namespace: default
Node: node02/10.151.30.63
......
QoS Class: BestEffort
Node-Selectors: com=youdianzhishi
Tolerations: node.kubernetes.io/not-ready:NoExecute for 300s
node.kubernetes.io/unreachable:NoExecute for 300s
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal SuccessfulMountVolume 55s kubelet, node02 MountVolume.SetUp succeeded for volume "default-token-n9w2d"
Normal Scheduled 54s default-scheduler Successfully assigned test-busybox to node02
Normal Pulling 54s kubelet, node02 pulling image "busybox"
Normal Pulled 40s kubelet, node02 Successfully pulled image "busybox"
Normal Created 40s kubelet, node02 Created container
Normal Started 40s kubelet, node02 Started container
可以看到 Events 下面的信息,我們的 Pod 通過默認的 default-scheduler 調(diào)度器被綁定到了node02節(jié)點秘案。不過需要注意的是nodeSelector屬于強制性的砰苍,如果我們的目標節(jié)點沒有可用的資源,我們的 Pod 就會一直處于 Pending 狀態(tài)阱高,這就是nodeSelector的用法赚导。
通過上面的例子我們可以感受到nodeSelector的方式比較直觀,但是還夠靈活赤惊,控制粒度偏大吼旧,接下來我們再和大家了解下更加靈活的方式:節(jié)點親和性(nodeAffinity)。
親和性和反親和性調(diào)度
之前了解了 kubernetes 調(diào)度器的一個調(diào)度流程未舟,我們知道默認的調(diào)度器在使用的時候圈暗,經(jīng)過了 predicates 和 priorities 兩個階段,但是在實際的生產(chǎn)環(huán)境中裕膀,往往我們需要根據(jù)自己的一些實際需求來控制 pod 的調(diào)度员串,這就需要用到 nodeAffinity(節(jié)點親和性)、podAffinity(pod 親和性) 以及 podAntiAffinity(pod 反親和性)昼扛。
親和性調(diào)度可以分成軟策略和硬策略兩種方式:
軟策略就是如果你沒有滿足調(diào)度要求的節(jié)點的話寸齐,pod 就會忽略這條規(guī)則,繼續(xù)完成調(diào)度過程抄谐,說白了就是滿足條件最好了渺鹦,沒有的話也無所謂了的策略
硬策略就比較強硬了箫爷,如果沒有滿足條件的節(jié)點的話痊夭,就不斷重試直到滿足條件為止,簡單說就是你必須滿足我的要求过咬,不然我就不干的策略浦箱。
對于親和性和反親和性都有這兩種規(guī)則可以設(shè)置: preferredDuringSchedulingIgnoredDuringExecution和requiredDuringSchedulingIgnoredDuringExecution吸耿,前面的就是軟策略殴边,后面的就是硬策略。
nodeAffinity
節(jié)點親和性主要是用來控制 pod 要部署在哪些主機上珍语,以及不能部署在哪些主機上的锤岸。它可以進行一些簡單的邏輯組合了,不只是簡單的相等匹配板乙。
比如現(xiàn)在我們用一個 Deployment 來管理3個 pod 副本是偷,現(xiàn)在我們來控制下這些 pod 的調(diào)度,如下例子:(node-affinity-demo.yaml)
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:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution: # 硬策略
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: NotIn
values:
- node03
preferredDuringSchedulingIgnoredDuringExecution: # 軟策略
- weight: 1
preference:
matchExpressions:
- key: com
operator: In
values:
- youdianzhishi
上面這個 pod 首先是要求不能運行在 node03 這個節(jié)點上募逞,如果有個節(jié)點滿足com=youdianzhishi的話就優(yōu)先調(diào)度到這個節(jié)點上蛋铆。
下面是我們測試的節(jié)點列表信息:
$ kubectl get nodes --show-labels
NAME STATUS ROLES AGE VERSION LABELS
master Ready master 154d v1.10.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/hostname=master,node-role.kubernetes.io/master=
node02 Ready <none> 74d v1.10.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,com=youdianzhishi,course=k8s,kubernetes.io/hostname=node02
node03 Ready <none> 134d v1.10.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,jnlp=haimaxy,kubernetes.io/hostname=node03
可以看到 node02 節(jié)點有com=youdianzhishi這樣的 label,按要求會優(yōu)先調(diào)度到這個節(jié)點來的放接,現(xiàn)在我們來創(chuàng)建這個 pod刺啦,然后使用descirbe命令查看具體的調(diào)度情況是否滿足我們的要求。
$ kubectl create -f node-affinity-demo.yaml
deployment.apps "affinity" created
$ kubectl get pods -l app=affinity -o wide
NAME READY STATUS RESTARTS AGE IP NODE
affinity-7b4c946854-5gfln 1/1 Running 0 47s 10.244.4.214 node02
affinity-7b4c946854-l8b47 1/1 Running 0 47s 10.244.4.215 node02
affinity-7b4c946854-r86p5 1/1 Running 0 47s 10.244.4.213 node02
從結(jié)果可以看出 pod 都被部署到了 node02纠脾,其他節(jié)點上沒有部署 pod玛瘸,這里的匹配邏輯是 label 的值在某個列表中,現(xiàn)在Kubernetes提供的操作符有下面的幾種:
In:label 的值在某個列表中
NotIn:label 的值不在某個列表中
Gt:label 的值大于某個值
Lt:label 的值小于某個值
Exists:某個 label 存在
DoesNotExist:某個 label 不存在
如果nodeSelectorTerms下面有多個選項的話苟蹈,滿足任何一個條件就可以了糊渊;如果matchExpressions有多個選項的話,則必須同時滿足這些條件才能正常調(diào)度 POD慧脱。
podAffinity
pod 親和性主要解決 pod 可以和哪些 pod 部署在同一個拓撲域中的問題(其中拓撲域用主機標簽實現(xiàn)渺绒,可以是單個主機,也可以是多個主機組成的 cluster菱鸥、zone 等等)宗兼,而 pod 反親和性主要是解決 pod 不能和哪些 pod 部署在同一個拓撲域中的問題,它們都是處理的 pod 與 pod 之間的關(guān)系氮采,比如一個 pod 在一個節(jié)點上了殷绍,那么我這個也得在這個節(jié)點,或者你這個 pod 在節(jié)點上了扳抽,那么我就不想和你待在同一個節(jié)點上篡帕。
由于我們這里只有一個集群,并沒有區(qū)域或者機房的概念贸呢,所以我們這里直接使用主機名來作為拓撲域,把 pod 創(chuàng)建在同一個主機上面拢军。
$ kubectl get nodes --show-labels
NAME STATUS ROLES AGE VERSION LABELS
master Ready master 154d v1.10.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/hostname=master,node-role.kubernetes.io/master=
node02 Ready <none> 74d v1.10.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,com=youdianzhishi,course=k8s,kubernetes.io/hostname=node02
node03 Ready <none> 134d v1.10.0 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,jnlp=haimaxy,kubernetes.io/hostname=node03
同樣楞陷,還是針對上面的資源對象,我們來測試下 pod 的親和性:(pod-affinity-demo.yaml)
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:
- busybox-pod
topologyKey: kubernetes.io/hostname
上面這個例子中的 pod 需要調(diào)度到某個指定的主機上茉唉,至少有一個節(jié)點上運行了這樣的 pod:這個 pod 有一個app=busybox-pod的 label固蛾。
我們查看有標簽app=busybox-pod的 pod 列表:
$ kubectl get pods -o wide -l app=busybox-pod
NAME READY STATUS RESTARTS AGE IP NODE
test-busybox 1/1 Running 164 7d 10.244.4.205 node02
我們看到這個 pod 運行在了 node02 的節(jié)點上面结执,所以按照上面的親和性來說,上面我們部署的3個 pod 副本也應(yīng)該運行在 node02 節(jié)點上:
$ kubectl get pods -o wide -l app=affinity
NAME READY STATUS RESTARTS AGE IP NODE
affinity-564f9d7db9-lzzvq 1/1 Running 0 3m 10.244.4.216 node02
affinity-564f9d7db9-p79cq 1/1 Running 0 3m 10.244.4.217 node02
affinity-564f9d7db9-spfzs 1/1 Running 0 3m 10.244.4.218 node02
如果我們把上面的 test-busybox 和 affinity 這個 Deployment 都刪除艾凯,然后重新創(chuàng)建 affinity 這個資源献幔,看看能不能正常調(diào)度呢:
$ kubectl delete -f node-selector-demo.yaml
pod "test-busybox" deleted
$ kubectl delete -f pod-affinity-demo.yaml
deployment.apps "affinity" deleted
$ kubectl create -f pod-affinity-demo.yaml
deployment.apps "affinity" created
$ kubectl get pods -o wide -l app=affinity
NAME READY STATUS RESTARTS AGE IP NODE
affinity-564f9d7db9-fbc8w 0/1 Pending 0 2m <none> <none>
affinity-564f9d7db9-n8gcf 0/1 Pending 0 2m <none> <none>
affinity-564f9d7db9-qc7x6 0/1 Pending 0 2m <none> <none>
我們可以看到處于Pending狀態(tài)了,這是因為現(xiàn)在沒有一個節(jié)點上面擁有busybox-pod這個 label 的 pod趾诗,而上面我們的調(diào)度使用的是硬策略蜡感,所以就沒辦法進行調(diào)度了,大家可以去嘗試下重新將 test-busybox 這個 pod 調(diào)度到 node03 這個節(jié)點上恃泪,看看上面的 affinity 的3個副本會不會也被調(diào)度到 node03 這個節(jié)點上去郑兴?
我們這個地方使用的是kubernetes.io/hostname這個拓撲域,意思就是我們當前調(diào)度的 pod 要和目標的 pod 處于同一個主機上面贝乎,因為要處于同一個拓撲域下面情连,為了說明這個問題,我們把拓撲域改成beta.kubernetes.io/os览效,同樣的我們當前調(diào)度的 pod 要和目標的 pod 處于同一個拓撲域中却舀,目標的 pod 是不是擁有beta.kubernetes.io/os=linux的標簽,而我們這里3個節(jié)點都有這樣的標簽锤灿,這也就意味著我們3個節(jié)點都在同一個拓撲域中禁筏,所以我們這里的 pod 可能會被調(diào)度到任何一個節(jié)點:
$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE
affinity-7d86749984-glkhz 1/1 Running 0 3m 10.244.2.16 node03
affinity-7d86749984-h4fb9 1/1 Running 0 3m 10.244.4.219 node02
affinity-7d86749984-tj7k2 1/1 Running 0 3m 10.244.2.14 node03
podAntiAffinity
這就是 pod 親和性的用法,而 pod 反親和性則是反著來的衡招,比如一個節(jié)點上運行了某個 pod篱昔,那么我們的 pod 則希望被調(diào)度到其他節(jié)點上去,同樣我們把上面的 podAffinity 直接改成 podAntiAffinity始腾,(pod-antiaffinity-demo.yaml)
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:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution: # 硬策略
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- busybox-pod
topologyKey: kubernetes.io/hostname
這里的意思就是如果一個節(jié)點上面有一個app=busybox-pod這樣的 pod 的話州刽,那么我們的 pod 就別調(diào)度到這個節(jié)點上面來,上面我們把app=busybox-pod這個 pod 固定到了 node03 這個節(jié)點上面來浪箭,所以正常來說我們這里的 pod 不會出現(xiàn)在 node03 節(jié)點上:
$ kubectl create -f pod-antiaffinity-demo.yaml
deployment.apps "affinity" created
$ kubectl get pods -o wide
NAME READY STATUS RESTARTS AGE IP NODE
affinity-bcbd8854f-br8z8 1/1 Running 0 5s 10.244.4.222 node02
affinity-bcbd8854f-cdffh 1/1 Running 0 5s 10.244.4.223 node02
affinity-bcbd8854f-htb52 1/1 Running 0 5s 10.244.4.224 node02
test-busybox 1/1 Running 0 23m 10.244.2.10 node03
這就是 pod 反親和性的用法穗椅。