在K8S平臺上,我們很少會直接創建一個Pod,在大多數情況下會通過RC,Deployment,DaemonSet,Job等控制器完成一組Pod副本的創建,調度及全生命週期的自動控制任務。
在k8s 1.9以前,在RC等對象被刪除後,它們所創建的Pod副本都不會被刪除;在k8s 1.9以後,這些Pod副本會被一併刪除。
如果不希望這樣做,可以通過kubectl命令的“--cascade=false”參數來取消這一默認特性:
kubectl delete replicaset my-reset --cascade=false
NodeSelector:定向調度
在一些情況下,我們需要將pod調度到指定的一些Node上,可以通過Node的標籤(Label)和Pod的nodeSelector屬性相匹配。
首先通過kubectl label 命令給目標Node打上一些標籤:
kubectl label nodes node-name label-key=label-vaule
kubectl label nodes 172.20.103.2 test=jinguanhua
然後,在pod的定義中加上nodeSelector的設置:
kubectl create -f redis.yaml
apiVersion: v1
kind: deploy
metadata:
name: redis-master
labels:
name: redis-master
spec:
replicas: 1
selector:
name: redis-master
template:
metadata:
labels:
name: redis-master
spec:
containers:
- name: master
image: kubeguide/redis-master
ports:
- containerPort: 6379
nodeSelector:
test: jinguanhua
如果我們給多個node都定義了相同的標籤,則scheduler會根據調度算法從這組Node中挑選一個可用的Node進行Pod調度。
通過基於Node標籤的調度方式,我們可以把集羣中具有不同特點的Node都貼上不同的標籤,例如“role=test”,“role=backend”,“role=database”等標籤,在部署應用時就可以根據應用的需求設置NodeSelector來進行制定Node範圍的調度。
PS:如果我們指定了Pod的nodeSelector條件,但是在集羣中不存在包含相應標籤的Node,則即使在集羣中還有其他可供使用的node,這個pod也無法被成功調度。
親和性調度
親和性調度功能包括 節點親和性(NodeAffinity)和 Pod親和性(PodAffinity)兩個維度的設置。
節點親和性(NodeAffinity)
NodeAffinity是node親和性的調度策略,是用於替換NodeSelector的全新調度策略。目前有兩種節點親和性表達。
RequiredDuringSchedulingIgnoredDuringExecution:必須滿足指定的規則纔可以調度pod到node上,相當於硬限制。
PreferredDuringSchedulingIgnoredDuringExecution:強調優先滿足指定規則,調度器會嘗試調度pod到node上,但並不強求,相當於軟限制。多個優先級規則還可以設置權重(weight)值,以定義執行的先後順序。
IgnoredDuringExecution的意思是:如果一個pod所在的節點在pod運行期間標籤發生了變更,不再符合該pod的節點親和性需求,則系統將忽略node上label的變化,該pod能繼續在該節點運行。
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.io/google_containers/pause:2.0
從上面的配置中可以看到In操作符,NodeAffinity語法支持的操作符包括In,NotIn,Exists,DoesNotExist,Gt,Lt。雖然沒有節點排斥功能,但是用NotIn和DoesNotExist就可以實現排斥的功能了。
NodeAffinity 規則設置的注意事項如下:
如果同時定義了nodeSelector和nodeAffinity,那麼必須兩個條件都得到滿足,Pod才能最終運行到指定的Node上。
如果nodeAffinity指定了多個nodeSelectorTerms,那麼其中一個能夠匹配成功即可。
如果在nodeSelectorTerms中有多個matchExpressions,則一個節點必須滿足所有matchExpressions才能運行該Pod。
Pod親和性(PodAffinity)與互斥性(podAntiAffinity)調度策略
Pod間的親和與互斥從Kubernetes 1.4版本開始引入。這一功能讓用戶從另一個角度來限制Pod所能運行的節點:根據在節點上正在運行的Pod的標籤而不是節點的標籤進行判斷和調度,要求對節點和Pod兩個條件進行匹配。這種規則可以描述爲:如果在具有標籤X的Node上運行了一個或者多個符合條件Y的Pod,那麼Pod應該(如果是互斥的情況,那麼就變成拒絕)運行在這個Node上。
這裏X指的是一個集羣中的節點、區域(zone)和地域(region)等概念,通過Kubernetes內置節點標籤中的key來進行聲明。這個key的名字爲topologyKey,意爲表達節點所屬的topology範圍。
◎ kubernetes.io/hostname
◎ kubernetes.io/arch
◎ kubernetes.io/os
◎ failure-domain.beta.kubernetes.io/zone
◎ failure-domain.beta.kubernetes.io/region
與節點不同的是,Pod是屬於某個命名空間的,所以條件Y表達的是一個或者全部命名空間中的一個Label Selector。
[root@iZ2ze7mealklhmaorgtx5jZ pro]# kubectl get no cn-beijing.172.17.13.102 --show-labels
NAME STATUS ROLES AGE VERSION LABELS
cn-beijing.172.17.13.102 Ready <none> 574d v1.16.6-aliyun.1 alibabacloud.com/nodepool-id=np019605d02c37420a9e201a4eba2391c7,beta.kubernetes.io/arch=amd64,beta.kubernetes.io/instance-type=ecs.sn1ne.xlarge,beta.kubernetes.io/os=linux,env=product,failure-domain.beta.kubernetes.io/region=cn-beijing,failure-domain.beta.kubernetes.io/zone=cn-beijing-c,kubernetes.io/arch=amd64,kubernetes.io/hostname=cn-beijing.172.17.13.102,kubernetes.io/os=linux
爲了保證業務應用的高可用,有些客戶會要求關鍵應用部署到多個機房,一個機房一旦出問題,其他機房正常工作,從而讓應用保持不間斷連續運行。類似這樣的能力在雲上如何實現呢?阿里雲有Region(地域)和Zone(可用區)的概念。簡單點理解,Region對應城市,例如“華東1”爲杭州,“華北2”爲北京等。Zone爲Region下按照電力和網絡設備等相互獨立的的可用區,不同的可用區可能在一個物理機房中。同一個地域內的不同可用區之間內網是連通的,網絡延遲很小。
和節點親和相同,Pod親和與互斥的條件設置也是requiredDuringSchedulingIgnoredDuringExecution和preferredDuringSchedulingIgnoredDuringExecution。
pod的親和性被定義與PodSpec的affinity字段下的podAffinity子字段中。
pod間的互斥性則被定義於同一層次的podAntiAffinity子字段中。
下面通過實例來說明pod間的親和性和互斥性策略設置
1.參照目標Pod
首先,創建一個名爲pod-flag的Pod,帶有標籤security=S1和app=nginx,後面的例子將使用pod-flag作爲Pod親和與互斥的目標Pod:
apiVersion: v1
kind: Pod
metadata:
name: pod-flag
labels:
security: "S1"
app: "nginx"
spec:
containers:
- name: nginx
image: nginx
2.Pod的親和性調度
下面創建第2個Pod來說明Pod的親和性調度,這裏定義的親和標籤是security=S1,對應上面的Pod“pod-flag”,topologyKey的值被設置爲“kubernetes.io/hostname”:
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.io/google_containers/pause:2.0
創建Pod之後,使用kubectl get pods -o wide命令可以看到,這兩個Pod在同一個Node上運行。有興趣的讀者還可以測試一下,在創建這個Pod之前,刪掉這個節點的kubernetes.io/hostname標籤,重複上面的創建步驟,將會發現Pod一直處於Pending狀態,這是因爲找不到滿足條件的Node了。
3.Pod的互斥性調度
創建第3個Pod,我們希望它不與目標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: app
operator: In
values:
- nginx
topologyKey: kubernetes.io/hostname
containers:
- name: anti-affinity
image: gcr.io/google_containers/pause:2.0
這裏要求這個新Pod與security=S1的Pod爲同一個zone,但是不與app=nginx的Pod爲同一個Node。創建Pod之後,同樣用kubectl get pods -o wide來查看,會看到新的Pod被調度到了同一Zone內的不同Node上。
與節點親和性類似,Pod親和性的操作符也包括In、NotIn、Exists、DoesNotExist、Gt、Lt。
原則上,topologyKey可以使用任何合法的標籤Key賦值,但是出於性能和安全方面的考慮,對topologyKey有如下限制。
◎ 在Pod親和性和RequiredDuringScheduling的Pod互斥性的定義中,不允許使用空的topologyKey。
◎ 如果Admission controller包含了LimitPodHardAntiAffinityTopology,那麼針對RequiredDuringScheduling的Pod互斥性定義就被限制爲kubernetes.io/hostname,要使用自定義的topologyKey,就要改寫或禁用該控制器。
◎ 在PreferredDuringScheduling類型的Pod互斥性定義中,空的topologyKey會被解釋爲kubernetes.io/hostname、failuredomain.beta.kubernetes.io/zone及failuredomain.beta.kubernetes.io/region的組合。
◎ 如果不是上述情況,就可以採用任意合法的topologyKey了。
PodAffinity規則設置的注意事項如下。
◎ 除了設置Label Selector和topologyKey,用戶還可以指定Namespace列表來進行限制,同樣,使用Label Selector對Namespace進行選擇。Namespace的定義和Label Selector及topologyKey同級。省略Namespace的設置,表示使用定義了affinity/anti-affinity的Pod所在的Namespace。如果Namespace被設置爲空值(""),則表示所有Namespace。
◎ 在所有關聯requiredDuringSchedulingIgnoredDuringExecution的matchExpressions全都滿足之後,系統才能將Pod調度到某個Node上。