在k8s集群建設過程中,一般情況下我們部署的 Pod 是通過集群的自動調度策略來選擇節點的,默認情況下調度器考慮的是資源足夠,並且負載盡量平均。但是有的時候我們需要能夠更加細粒度的去控制 Pod 的調度;有時我們希望對內和對外的兩類業務分別跑在不同的節點上,相互有依賴的兩個pod跑在同一節點上,等情況;這就需要我們更好的控制pod的部署;k8s給我們提供了親和性和反親和性,污點(taint)和Toleration(容忍)等概念。
#示例
[root@k8s-master ~]# kubectl explain pod.spec.affinity
KIND: Pod
VERSION: v1
RESOURCE: affinity <Object>
DESCRIPTION:
If specified, the pod's scheduling constraints
Affinity is a group of affinity scheduling rules.
FIELDS:
nodeAffinity <Object>----------------#node親和性
Describes node affinity scheduling rules for the pod.
podAffinity <Object>----------------#pod親和性
Describes pod affinity scheduling rules (e.g. co-locate this pod in the
same node, zone, etc. as some other pod(s)).
podAntiAffinity <Object>--------#pod反親和性
Describes pod anti-affinity scheduling rules (e.g. avoid putting this pod
in the same node, zone, etc. as some other pod(s)).
節點node親和性
目前主要的node affinity:
requiredDuringSchedulingIgnoredDuringExecution
表示pod必須部署到滿足條件的節點上,如果沒有滿足條件的節點,就不停重試。其中IgnoreDuringExecution表示pod部署之后運行的時候,如果節點標簽發生了變化,不再滿足pod指定的條件,pod也會繼續運行。
requiredDuringSchedulingRequiredDuringExecution
表示pod必須部署到滿足條件的節點上,如果沒有滿足條件的節點,就不停重試。其中RequiredDuringExecution表示pod部署之后運行的時候,如果節點標簽發生了變化,不再滿足pod指定的條件,則重新選擇符合要求的節點。
preferredDuringSchedulingIgnoredDuringExecution
表示優先部署到滿足條件的節點上,如果沒有滿足條件的節點,就忽略這些條件,按照正常邏輯部署。
preferredDuringSchedulingRequiredDuringExecution
表示優先部署到滿足條件的節點上,如果沒有滿足條件的節點,就忽略這些條件,按照正常邏輯部署。其中RequiredDuringExecution表示如果后面節點標簽發生了變化,滿足了條件,則重新調度到滿足條件的節點。
舉例說明
pod.spec.affinity.nodeAffinity
- preferredDuringScheculingIgnoredDuringExecution:軟策略
- requiredDuringSchedulingIgnoredDuringExecution:硬策略
requiredDuringSchedulingIgnoredDuringExecution:硬策略
apiVersion:v1
kind:Pod
metadata:
name:affinity
labels:
app:node-affinity-pod
spec:
containers:
- name:with-node-affinity
image:nginx:v1
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key:kubernetes.io/hostname
operator:NotIn
values:
- k8s-node01
preferredDuringScheculingIgnoredDuringExecution:軟策略
apiVersion:v1
kind:Pod
metadata:
name:affinity
labels:
app:node-affinity-pod
spec:
containers:
- name:with-node-affinity
image:nginx:v1
affinity:
nodeAffinity:
preferredDuringScheculingIgnoredDuringExecution:
- weitht:1
preference:
matchExpressions:
- key:source
operator:In
values:
- hahaha
硬策略和軟策略一起用
apiVersion:v1
kind:Pod
metadata:
name:affinity
labels:
app:node-affinity-pod
spec:
containers:
- name:with-node-affinity
image:nginx:v1
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key:kubernetes.io/hostname
operator:NotIn
values:
- k8s-node01
preferredDuringScheculingIgnoredDuringExecution:
- weitht:1
preference:
matchExpressions:
- key:source
operator:In
values:
- hahaha
鍵值運算關系
運算符 | 作用 |
---|---|
In | lable的值在某個列表中 |
NotIn | label的值不在某個列表中 |
Gt | label的值大於某個值 |
Lt | label的值小於某個值 |
Exists | 某個label存在 |
DoesNotExist | 某個label不存在 |
Pod親和性
podAffinity規則
pod affinity 可以這樣理解:調度的時候選擇(或者不選擇)這樣的節點 N ,這些節點上已經運行了滿足條件 X。條件 X 是一組 label 選擇器,它必須指明作用的 namespace(也可以作用於所有的 namespace),因為 pod 是運行在某個 namespace 中的。
這里的X指的是集群中的節點、機架、區域等概念,通過kubernetes內置節點標簽中的key來進行聲明。這個key的名字為topologyKey,意為表達節點所屬的topology范圍:
- kubernetes.io/hostname
- failure-domain.beta.kubernetes.io/zone
- failure-domain.beta.kubernetes.io/region
要使用親和性,在 affinity 下面添加 podAffinity 字段,
要使用互斥性,在 affinity 下面添加 podAntiAffinity 字段,
requiredDuringSchedulingIgnoredDuringExecution,
preferredDuringSchedulingIgnoredDuringExecution,
requiredDuringSchedulingRequiredDuringExecution,
preferredDuringSchedulingRequiredDuringExecution,
意義和nodeAffinity一樣。
舉例說明
pod.spec.affinity.podAffinity/podAntiAffinity
- preferredDuringSchedulingIgnoredDuringExecution: 軟策略
- requiredDuringSchedulingIgnoredDuringExecution:硬策略
apiVersion:v1
kind:Pod
metadata:
name:pod-3
labels:
app:pod-3
spec:
containers:
- name:pod-3
inamge:nginx:v1
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key:app
operator:In
values:
- pod-1
topologyKey:kubernetes.io/hostname
污點配合容忍度(Taint和toleration)
節點親和性,是pod的一種屬性(偏好或硬性要求),它使得pod被吸引到一類特定的節點上。Taint則相反,它使得節點能夠排斥一類特定的pod
Taint和toleration(容忍)相互配合,可以用來避免pod被分配到不合適的節點上。每個節點上都可以應用一個或多個taint,這表示這些pod可以(但不要求)被調度到具有匹配taint的節點上。
污點
污點的組成
使用kubectl taint 命令可以給節點node設置污點,node被設置污點后,可以讓node拒絕pod的調度執行,甚至可以將本node上已經運行的pod驅逐出去。
任何符合其鍵值規范要求的字符串均可用於定義污點信息:僅可使用字母、數字、連接符、點號和下划線,且僅能以字母或數字開頭,其中鍵名的長度上限為253個字符,值最長為63個字符。實踐中,污點通常用於描述具體的部署規划,它們的鍵名形如node-tppe、node-role、node-project或node-geo等,因此還可在必要時帶上域名以描述其額外的信息,如node-type.linux.io等
通過kubectl查看污點,Taints字段
kubectl describe nodes k8s-master-01
Name: k8s-master-01
Roles: master
Labels: beta.kubernetes.io/arch=amd64
beta.kubernetes.io/os=linux
kubernetes.io/arch=amd64
kubernetes.io/hostname=k8s-master-01
kubernetes.io/os=linux
node-role.kubernetes.io/master=
......
Taints: node-role.kubernetes.io/master:NoSchedule
Unschedulable: false
每個污點有一個key和value作為污點的標簽,其中value可以為空,effect描述污點的作用。當前taint effect支持如下三種選項
effect類別 | 作用 |
---|---|
NoSchedule | 表示k8s不會將pod調度到具有該污點的Node上 |
PreferNotSchedule | 表示k8s將盡量避免將pod調度到具有該污點的node上 |
NotExecute | 表示k8s將不會將pod調度到具有該污點的node上,同時node上已經存在的pod將驅逐出去 |
污點的設置與去除
#設置污點
kubectl taint nodes <node-name> <key>=<value>:<effect>
#kubectl taint nodes node02 node-type=production:NoSchedule
node "node02" tainted
#去除污點(在添加污點的命令后面加"-")
kubectl taint nodes node02 key=value:NoSchedule-
#查詢污點,通過kubectl查看節點說明中的Taints字段
kubectl describe nodes k8s-master-01
Name: k8s-master-01
Roles: master
Labels: beta.kubernetes.io/arch=amd64
beta.kubernetes.io/os=linux
kubernetes.io/arch=amd64
kubernetes.io/hostname=k8s-master-01
kubernetes.io/os=linux
node-role.kubernetes.io/master=
......
Taints: node-role.kubernetes.io/master:NoSchedule
Unschedulable: false
容忍(Tolerations)
設置了污點的Node將根據taint的effect和pod之間產生互斥關系,pod將在一定程度上不會被調度到該Node上。但是我們可以在pod上設置容忍(Toleration),意思是設置了容忍的pod將可以容忍污點存在,可以被調度到存在污點的node上
舉例說明
pod.spec.tolerations
tolerations:
- key: "key1"
operator: "Equal"
value: "value1"
effect: "NoExecute"
tolerationSeconds: 3600
- key: "key1"
operator: "Equal"
value: "value1"
effect: "NoSchedule"
- key: "key1"
operator: "Exists"
effect: "NoSchedule"
#主要有兩種可用的形式:一種是與污點信息完全匹配的等值關系;另一種是判斷污點信息存在性的匹配方式。
#如果operator是Exists 污點存在性匹配容忍,可以忽略value值;
#如果operator是Equal,污點等值關系匹配容忍,它們的key、value、effect要與node上設置的taint一致。
#tolerationSeconds用於描述pod需要被驅逐時,可以在pod上繼續保留運行的時間
#當不指定key值時,表示容忍所有的污點key
tolerations:
- operator:"Exists"
#當不指定effect值時,表示容忍所有的污點effect
tolerations:
- key:"key1"
operator:"Exists"
指定調度節點
pod.spec.nodeName將pod直接調度到指定的node節點上,會跳過scheduler的調度策略,該匹配規則時強制匹配
apiVersion:extensions/v1beta1
kind:Deployment
metadata:
name:web
spec:
replicas:5
template:
metadata:
labels:
app:web
spec:
nodeName:k8s-node01
containers:
- name:web
image:nginx:v1
ports:
- containerPort:80
pod.spec.nodeSelector:通過kubernetes的label-selector機制選擇節點,有調度器策略匹配label,而后調度pod到目標節點,該匹配為強制約束
apiVersion:extensions/v1beta1
kind:Deployment
metadata:
name:web
spec:
replicas:2
template:
metadata:
labels:
app:web
spec:
nodeSelector:
node-key:node-value
containers:
- name:web
image:nginx:v1
ports:
- containerPort:80
使用kubectl label nodes
[root@k8s-master ~]# kubectl label nodes k8s-master role=master
node/k8s-master labeled
使用kubectl get nodes --show-labels 查詢nodes的label
[root@k8s-master ~]# kubectl get nodes --show-labels
NAME STATUS ROLES AGE VERSION LABELS
k8s-master Ready control-plane,master 227d v1.22.1 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-master,kubernetes.io/os=linux,node-role.kubernetes.io/control-plane=,node-role.kubernetes.io/master=,node.kubernetes.io/exclude-from-external-load-balancers=,role=master
k8s-node1 Ready <none> 227d v1.22.1 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-node1,kubernetes.io/os=linux
k8s-node2 Ready <none> 227d v1.22.1 beta.kubernetes.io/arch=amd64,beta.kubernetes.io/os=linux,kubernetes.io/arch=amd64,kubernetes.io/hostname=k8s-node2,kubernetes.io/os=linux