Kubernetes高級功能
文章目錄
- Kubernetes高級功能
- 一、資源配額
- 1.1、什么是資源配額
- 1.2、資源配額應用
- 1.2.1、針對Namespace設置資源配額
- 1.2.2、針對Pod設置資源配額
- 二、HorizontalPodAutoscaler(HPA)
- 2.1、什么是HorizontalPodAutoscaler
- 2.2、HorizontalPodAutoscaler支持的指標
- 2.3、指標來源
- 2.4、HorizontalPodAutoscaler應用
- 2.4.1、部署Metrics
- 2.4.2、準備測試服務
- 2.4.3、命令行配置HPA
- 2.4.4、編寫yaml文件配置HPA
- 2.4.5、HPA測試
- 三、節點選擇器
- 3.1、通過nodeSelector
- 3.2、通過nodeName
- 四、親和性
- 4.1、Node親和性
- 4.2、Pod親和性
- 4.2.1、Pod親和
- 4.2.2、Pod反親和
- 五、五點容忍
- 5.1、污點
- 5.1.1、添加污點
- 5.1.2、查看污點
- 5.1.3、刪除污點
- 5.2、容忍
- 5.2.1、設置污點
- 5.2.2、運行沒有容忍的Pod
- 5.2.3、運行帶有容忍的Pod
一、資源配額
1.1、什么是資源配額
- 當多個用戶或團隊共享具有固定節點數目的集群時,人們會擔心有人使用超過其基于公平原則所分配到的資源量
- 資源配額是幫助管理員解決這一問題的工具。
- 資源配額,通過ResourceQuota對象來定義,對每個命名空間的資源消耗總量提供限制。它可以限制命名空間中某種類型的對象的總數目上限,也可以限制命名空間中的Pod可以使用的計算資源的總上限。
- 對于cpu和memory資源:ResourceQuota強制該命名空間中的每個(新)Pod為該資源設置限制。如果你在命名空間中為cpu和memory實施資源配額,你或其他客戶端必須為你提交的每個新Pod指定資源的requests或limits。否則,控制平面可能會決絕接納該Pod。
- 對于其他資源:ResourceQuota可以工作,并且會忽略命名空間中的Pod。而無需為該資源設置限制或請求。這意味著,如果資源配額限制了此命名空間的臨時存儲,則可以創建沒有限制/請求臨時存儲的新Pod。你可以使用限制范圍自動設置對這些資源的默認請求。
1.2、資源配額應用
1.2.1、針對Namespace設置資源配額
- 創建的ResourceQuota對象將在test命名空間添加限制,每個容器必須設置內存請求(memory request),內存限額(memory limit),cpu請求(cpu request)和cpu限額(cpu limit),所有容器的內存請求總額不得超過2GiB,所有容器的內存限額總額不得超過4GiB,所有容器的CPU請求總額不得超過2CPU,所有容器的CPU限額不得超過4CPU
[root@master ~]# cat namespace_ResourceQuota.yaml
apiVersion: v1
kind: Namespace
metadata:name: test
---
apiVersion: v1
kind: ResourceQuota
metadata:name: mem-cpu-quotanamespace: test
spec:hard:# 啟動Pod時所有Pod請求的CPU個數不得超過2個requests.cpu: "2"# 啟動Pod時所有Pod請求的內存總和不得超過2Grequests.memory: "2Gi"# 限制所有Pod的CPU請求總和不得超過4個limits.cpu: "4"# 限制所有Pod的內存請求總和不得超過4Glimits.memory: "4Gi"# 部署資源
[root@master ~]# kubectl apply -f namespace_ResourceQuota.yaml
namespace/test created
resourcequota/mem-cpu-quota created# 可以通過describe查看test命名空間中我們設置的資源配額限制
[root@master ~]# kubectl describe ns test
Name: test
Labels: kubernetes.io/metadata.name=test
Annotations: <none>
Status: ActiveResource QuotasName: mem-cpu-quotaResource Used Hard-------- --- ---limits.cpu 0 4limits.memory 0 4Girequests.cpu 0 2requests.memory 0 2GiNo LimitRange resource.
1.2.2、針對Pod設置資源配額
- 對于有資源限制的命名空間,下面的Pod,創建Pod時候必須設置資源限額。否則創建失敗
- requests:代表容器啟動請求的資源限制,分配的資源必須要達到此要求。
- limits:代表最多可以請求多少資源
- 單位m:CPU的計量單位叫毫核(m)。一個節點的CPU核心數量乘以1000,得到的就是節點的總的CPU總數量。如,一個節點有兩個核,那么該節點的CPU總量為2000m。
# 該容器啟動時請求500/2000的核心(%25)
[root@master ~]# cat pod_resources.yaml
apiVersion: v1
kind: Pod
metadata:name: test-nginxnamespace: testlabels:app: nginx
spec:containers:- name: nginxports:- containerPort: 80image: nginximagePullPolicy: IfNotPresent# 定義了容器請求和限制的資源量resources:# 定義容器請求資源量requests:# 容器啟動時請求100MiB的內存memory: "100Mi"# 啟動啟動時請求500mCPU(即0.5個CPU核心)cpu: "500m"# 定義容器限制資源量limits:# 容器可使用的最大內存限制為2GiB memory: "2Gi"# 啟動可使用的最大CPU限制為2個CPU核心cpu: "2" # 部署資源
[root@master ~]# kubectl apply -f pod_resources.yaml
pod/test-nginx created
二、HorizontalPodAutoscaler(HPA)
2.1、什么是HorizontalPodAutoscaler
-
HorizontalPodAutoscaler簡稱HAP,用來自動化的去擴縮容,防止以外的業務量增大導致管理員措手不及,Kubernetes為我們提供了這樣一個資源對象:HorizontalPodAutoscaler(Pod水平自動伸縮),簡稱HPA。HPA通過監控分析RC或Deployment控制的所有Pod的負載變化情況來確定是否需要調整Pod的副本數量,這是HPA最基本的原理。
-
HorizontalPodAutoscaler(簡稱HAP)自動更新工作負載資源(例如Deployment或StatefulSet),目的是自動擴縮工作負載以滿足需求。
-
水平擴縮意味著對增加的負載的響應是部署更多的Pod。這與“垂直擴縮”不同,對于Kubernetes,垂直擴縮意味著將更多資源(例如:內存或CPU)分配給已經為工作負載運行的Pod。
-
如果負載減少,并且Pod的數量高于配置的最小值,HorizontalPodAutoscaler會指示工作資源(Deployment、StatefulSet、或其他類資源)縮減
2.2、HorizontalPodAutoscaler支持的指標
- HPA支持的指標可以使用kubectl api-versions | grep autoscal命令查詢
[root@master ~]# kubectl api-versions | grep autoscal
autoscaling/v1
autoscaling/v2
autoscaling/v2beta1
autoscaling/v2beta2# autoscaling/v1:只支持基于CPU的縮放
# autoscaling/v2:支持Resource Metrics(資源指標,如pod的CPU。內存)和Custom Metrics(自定義指標)的縮放
# autoscaling/v2beta1:支持Resource Metrics(資源指標,如Pod的CPU,內存)和Custom Metrics(自定義指標)和ExternalMetrics(額外指標)的縮放,但是目前也僅僅是出于beta階段
# autoscaling/v2beta2(穩定版本):其中包括對基于內存和自定義指標擴縮的支持
2.3、指標來源
- HPA會像資源監控系統獲取Pod的資源使用情況,資源監控系統是容器編排系統必不可少的自建,它為用戶提供了快速了解系統資源分配和利用狀態的有效突進,同時也是系統編排賴以實現的基礎要件。
- 老的版本使用Heapster進行資源各項資源指標數據的采集,從Kubernetes1.11開始Heapster被廢棄不在使用,metrics-server替代了Heapster
- K8S從1.8版本卡死hi,CPU、內存的等資源的信息可以通過Metrics API來獲取,用戶可以直接獲取這些metrics信息(例如通過執行kubectl top),HAP使用這些metaics信息來實現動態的伸縮
? Metrics API:
- 通過Metrics API我們可以獲取到指定node或者pod的當前資源使用情況,API本身不存儲任何信息,所以我們不可以通過API來獲取資源的歷史使用情況
- Mterics API的獲取路徑位于:/apis/metrics.k8s.io/
- 獲取Metrics API的前提條件是metrics server要在K8S集群中成功部署
- 更多有關metrics資源請參考:https://github.com/kubernetes/metrics
? Metrics server:
- Metrics server是K8S集群資源使用情況的集合器
- 從1.8版本開始,Metrics server默認可以通過kubectl-up.sh腳本以deployment的方式進行部署,也可以通過yaml文件的方式進行部署
- metrics server收集所有node節點的metrics信息
2.4、HorizontalPodAutoscaler應用
2.4.1、部署Metrics
# 加載配置文件以后需要等待1分鐘左右,使其配置加載成功,再使用top查詢node節點的資源使用情況
[root@master ~]# kubectl apply -f components.yaml
serviceaccount/metrics-server created
clusterrole.rbac.authorization.k8s.io/system:aggregated-metrics-reader created
clusterrole.rbac.authorization.k8s.io/system:metrics-server created
rolebinding.rbac.authorization.k8s.io/metrics-server-auth-reader created
clusterrolebinding.rbac.authorization.k8s.io/metrics-server:system:auth-delegator created
clusterrolebinding.rbac.authorization.k8s.io/system:metrics-server created
service/metrics-server created
deployment.apps/metrics-server created
apiservice.apiregistration.k8s.io/v1beta1.metrics.k8s.io created# 使用kubectl top命令可以查詢資源使用情況
[root@master ~]# kubectl top node
NAME CPU(cores) CPU% MEMORY(bytes) MEMORY%
master 83m 4% 842Mi 22%
node1 20m 1% 316Mi 8%
node2 22m 1% 322Mi 8%
2.4.2、準備測試服務
- 注意在所有node節點上上傳鏡像文件cpu_stress_v3.tar.gz,使用docker load加載一下
[root@master ~]# cat stress.yaml
apiVersion: apps/v1
kind: Deployment
metadata:name: stress
spec:replicas: 1selector:matchLabels:app: stresstemplate:metadata:labels:app: stressspec:containers:- name: stressimage: cpu_stress:v3imagePullPolicy: IfNotPresentports:- containerPort: 80# 定義一個資源請求和限制resources:requests:cpu: "100m"limits:cpu: "500m"
---
apiVersion: v1
kind: Service
metadata:name: stress
spec:ports:- port: 80targetPort: 80selector: app: stress# 部署資源
[root@master ~]# kubectl apply -f stress.yaml
deployment.apps/stress created
service/stress created
2.4.3、命令行配置HPA
# --cpu-percent:指定pod的cpu使用率維持在50%左右,超過就擴容小于就縮容
# --min:指定Pod數量最少多少
# --max:指定Pod數量最多多少
# 以西為的deployment資源stress進行配置
[root@master ~]# kubectl autoscale deployment stress --cpu-percent=50 --min=1 --max=10
horizontalpodautoscaler.autoscaling/stress autoscaled# 查看hpa
[root@master ~]# kubectl get hpa
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
stress Deployment/stress 0%/50% 1 10 1 74s
2.4.4、編寫yaml文件配置HPA
# scaleTargetRef:指定要縮放的目標,在這里是“stress”這個Dployment
# minReplicas:1縮放的最小的Pod的數量
# maxReplicas:10縮放的最大的Pod的數量
[root@master ~]# cat stress_hap.yaml
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:name: stress
spec:scaleTargetRef:apiVersion: apps/v1kind: Deployment # 目標資源類型為Deploymentname: stress # 目標Deployment的名稱為stressminReplicas: 1 # 表示Pod的縮放最小數量maxReplicas: 10 # 表示Pod的增加最大數量metrics:- type: Resource # 指定要縮放所用的資源類型,這里是資源利用率指標resource:name: cpu # 指定資源類型,這里是CPUtarget:type: Utilization # 表示基于CPU利用率百分比來自動擴縮容averageUtilization: 50 # 平均利用率為50%。當利用率超過這個目標值時會縮放Pod的數量# 部署資源(可能會出現一個警告的信息,沒有關系不影響)
[root@master ~]# kubectl apply -f stress_hap.yaml
horizontalpodautoscaler.autoscaling/stress created[root@master ~]# kubectl get hpa
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
stress Deployment/stress 0%/50% 1 10 1 3m56s
2.4.5、HPA測試
[root@master ~]# cat test.yaml
apiVersion: apps/v1
kind: Deployment
metadata:name: cpustress
spec:replicas: 1selector:matchLabels: app: cpustresstemplate:metadata:labels:app: cpustressspec:containers:- name: cpustressimage: alpineimagePullPolicy: IfNotPresentcommand:- "sh"- "-c"- "sed -i 's/dl-cdn.alpinelinux.org/mirrors.ustc.edu.cn/g' /etc/apk/repositories && apk update && apk add curl && while true; do curl stress/stress?duration=30&load=70 ;sleep 32;done"# 部署資源
[root@master ~]# kubectl apply -f test.yaml
deployment.apps/cpustress created# 查看HPA情況
[root@master ~]# kubectl get hpa
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
stress Deployment/stress 62%/50% 1 10 10 12m# 查看Pod的是否增加
[root@master ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
cpustress-649d7f6485-6dxrr 1/1 Running 0 3m
stress-548b54ff89-457cx 1/1 Running 0 2m1s
stress-548b54ff89-4hstr 1/1 Running 0 2m1s
stress-548b54ff89-877d9 1/1 Running 0 2m1s
stress-548b54ff89-9hg62 1/1 Running 0 2m16s
stress-548b54ff89-b9qnl 1/1 Running 0 23m
stress-548b54ff89-bblxr 1/1 Running 0 2m16s
stress-548b54ff89-fnwt5 1/1 Running 0 106s
stress-548b54ff89-k2dkw 1/1 Running 0 2m1s
stress-548b54ff89-mdklt 1/1 Running 0 106s
stress-548b54ff89-xn4tc 1/1 Running 0 2m16s# 停止壓力測試
[root@master ~]# kubectl delete -f test.yaml
deployment.apps "cpustress" deleted# 等待一段時間會發現Pod的數量降下來了,可能需要幾分鐘
[root@master ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
stress-548b54ff89-b9qnl 1/1 Running 0 66m
三、節點選擇器
3.1、通過nodeSelector
- nodeSelector是節點選擇約束的最簡單的推薦形式。你可以將nodeSelector字段添加到Pod的規約中設置你希望目標節點所具有的節點標簽。Kubernetes只會將Pod踢調度到擁有你所指定的每個標簽的節點上。
# 該示例是運行Pod在具有disk=ceph標簽的節點上
[root@master ~]# cat pod_nodeSelector.yaml
apiVersion: v1
kind: Pod
metadata:name: podnodeselectornamespace: defaultlabels:app: nginx
spec:nodeSelector:disk: cephcontainers:- name: podnodeselectorports:- containerPort: 80image: nginximagePullPolicy: IfNotPresentresources:requests:memory: "100Mi"cpu: "500m"limits:memory: "1Gi"cpu: "1" # 部署資源
[root@master ~]# kubectl apply -f pod_nodeSelector.yaml
pod/podnodeselector created# 可以看到沒有節點帶有disk=ceph標簽,所以Pod是Pending狀態
[root@master ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
podnodeselector 0/1 Pending 0 56s
stress-548b54ff89-b9qnl 1/1 Running 0 73m
[root@master ~]# kubectl get node -l disk=ceph
No resources found# 給node1節點打標簽,然后Pod就自動運行在有指定標簽的節點了
[root@master ~]# kubectl label node node1 disk=ceph
node/node1 labeled
[root@master ~]# kubectl get node -l disk=ceph
NAME STATUS ROLES AGE VERSION
node1 Ready <none> 6d18h v1.23.0
[root@master ~]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
podnodeselector 1/1 Running 0 2m4s 10.244.2.8 node1 <none> <none>
3.2、通過nodeName
- nodeName是比性和性或者nodeSelector更為直接的形式。nodeName是Pod規約中的一個字段。如果nodeName字段不為空,調度器會忽略該Pod,而指定節點上的kubelet會嘗試將Pod放到該節點上。使用nodeName規則的優先級會高于使用nodeSelector或親和性與非親和性的規則。
? 使用nodeName來選擇節點的方式有一些局限性
- 如果所指定的節點不存在,則Pod無法運行,而且在某些情況下會被自動刪除。
- 如果所指定的節點無法提供用來運行Pod所需的資源,Pod會失敗,而其失敗原因中會給出是否因為內存或CPU不足而造成無法運行
- 在云環境中的節點名稱并不總是可預測的,也不總是穩定的
[root@master ~]# cat nodeName.yaml
apiVersion: v1
kind: Pod
metadata:name: podnodenamenamespace: defaultlabels:app: nginx
spec:nodeName: node1containers:- name: podnodenameimage: nginximagePullPolicy: IfNotPresent# 部署資源
[root@master ~]# kubectl apply -f nodeName.yaml
pod/podnodename created# 查看是否調度到指定節點
[root@master ~]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
podnodename 1/1 Running 0 31s 10.244.2.9 node1 <none> <none>
四、親和性
- Affinity翻譯成中文是“親和性”,它對應的是Anti-Affinity,我們翻譯成“互斥”。這兩個詞比較形象,可以把pod選擇node的過程比成磁鐵的吸引和互斥,不同的是除了簡單的正負極之外,pod和node的吸引和互斥是可以靈活配置的。
? Affinity的優點
- 匹配有更多的邏輯組合,不只是字符串的完成相等
- 調度分為軟策略和硬策略,在軟策略下,如果沒有滿足調度條件的節點,node會忽略這條規則,繼續完成調度
? 目前主要的node affinity:
-
requiredDuringSchedulingIgnoredDuringExecution:表示Pod必須部署到滿足條件的節點上,如果沒有滿足條件的節點,就不停重試。其中IgnoreDuringExecution表示Pod部署之后運行的時候,如果節點標簽發生了變化,不再滿足Pod指定的條件,Pod也會繼續運行
-
requiredDuringSchedulingRequiredDuringExecution:表示Pod必須部署到滿足條件的節點上,如果沒有滿足條件的節點。就不聽重試。其中RequitredDuringExecution表示Pod部署之后運行的時候,如果節點標簽發生了變化,不再滿足Pod的指定的條件,則重新選擇符合要求的節點
-
preferredDuringSchedulingRequiredDuringExecution:表示優先部署到滿足的節點上,如果沒有滿足條件的節點,就忽略這些條件,按照正常邏輯部署,其中RequitredDuringExecution表示如果后面節點標簽發生了變化,滿足了條件,則重新調度到滿足條件的節點
4.1、Node親和性
- node節點親和性調度:nodeAffinity
- 使用requiredDuringSchedulingIgnoredDuringExecution硬親和性節點有disktype=ssd標簽或disktype=hhd標簽即可被調度,若是都沒有Pod則是Pending狀態
[root@master ~]# cat podAffinity.yaml
apiVersion: v1
kind: Pod
metadata:name: pod-node-affinity-demonamespace: defaultlabels:app01: nginx
spec:containers:- name: nginxports:- containerPort: 80image: nginximagePullPolicy: IfNotPresentaffinity:nodeAffinity:requiredDuringSchedulingIgnoredDuringExecution:nodeSelectorTerms:- matchExpressions:- key: disktypeoperator: Invalues:- ssh- hhd# 部署資源
[root@master ~]# kubectl apply -f podAffinity.yaml
pod/pod-node-affinity-demo created# 查看pod狀態時Pending,因為沒有節點帶有disktyp=ssd標簽或者disktype=hhd標簽
[root@master ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
pod-node-affinity-demo 0/1 Pending 0 61s
[root@master ~]# kubectl get node -l disktype=ssd
No resources found
[root@master ~]# kubectl get node -l disktype=hhd
No resources found# 打標簽以后發現Pod就正常運行了,并且是運行在打標簽的節點上
[root@master ~]# kubectl label node node1 disktype=ssh
node/node1 labeled
[root@master ~]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
pod-node-affinity-demo 1/1 Running 0 5m6s 10.244.2.10 node1 <none> <none>
4.2、Pod親和性
? Pod自身的親和性和性調度有兩種表示形式:
- podaffinity:Pod和Pod更傾向于膩在一起,把相近的pod結合到相近的位置,如同一區域,同一機架,這樣的話‘pod和pod之間更好通信,比方說有兩個機房,這兩個機房部署的集群有1000臺主機,那么我們希望把nginx和tomcat都部署同一個地方的node節點上,可以提高通信效率
- poddunaffinity:pod和pod更傾向于不膩在一起,如果部署兩臺程序,那么這兩套程序更傾向于反親和性,這樣相互之間不會有影響
- 第一個pod隨機選擇一個節點,作為評判后續的Pod是否到達這個Pod所在的節點上運行方式,這就成為Pod親和性;我們怎么判斷哪些節點是相同位置,哪些節點不同位置;我們在定義pod親和性時需要有一個提前,哪些pod在同一位置,哪些pod不在同一位置,這個位置是怎么定義的,標準是什么?以節點名稱為標準,這個節點相同表示是同一個位置,節點名稱不相同的表示不是一個位置
? topplogyKey:
- 位置拓撲的鍵,這個是必須字段
- 怎么判斷是不是同一個位置
- rack=rack1
- row=row1
- 使用rack的鍵是同一個位置
- 使用row的鍵是同一個位置
? labelsSelector:
- 我們要判斷pod跟別的pod親和,跟哪個pod親和,需要靠labelSelector,通過labelSelector選擇一組作為親和對象的pod資源
? namspace:
- labelSelector:需要選擇一組資源,那么這組資源是在哪個名稱空間中呢,通過namespace指定,如果不指定namespace,那么就是當前創建的Pod 的名稱空間
4.2.1、Pod親和
- Pod親和就是后啟動的Pod要和前面啟動的Pod調度在一個節點上,使用podAffinity字段定義
[root@master ~]# cat podAffinity.yaml
apiVersion: v1
kind: Pod
metadata:name: nginx01namespace: defaultlabels:app01: nginx01
spec:containers:- name: mynginxports:- containerPort: 80image: nginximagePullPolicy: IfNotPresent
---
apiVersion: v1
kind: Pod
metadata:name: nginx02namespace: defaultlabels:app02: nginx02
spec:containers:- name: mynginxports:- containerPort: 80image: nginximagePullPolicy: IfNotPresentaffinity:podAffinity:requiredDuringSchedulingIgnoredDuringExecution:- labelSelector:matchExpressions:- key: app01operator: Invalues:- nginx01topologyKey: kubernetes.io/hostname # 每個節點都有kubernetes.io/hostname標簽,這個標簽通常是主機名,topologKey制定了這個標簽意思是限定在一個節點上# 部署資源
[root@master ~]# kubectl apply -f podAffinity.yaml
pod/nginx01 created
pod/nginx02 created[root@master ~]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx01 1/1 Running 0 33s 10.244.1.16 node2 <none> <none>
nginx02 1/1 Running 0 33s 10.244.1.15 node2 <none> <none>
4.2.2、Pod反親和
- Pod反親和就是后啟動的Pod要和前面啟動的Pod不調度在一個節點上,使用podAntiAffinity字段定義
[root@master ~]# cat podAntiAffinity.yaml
apiVersion: v1
kind: Pod
metadata:name: nginx01namespace: defaultlabels:app01: nginx01
spec:containers:- name: mynginxports:- containerPort: 80image: nginximagePullPolicy: IfNotPresent
---
apiVersion: v1
kind: Pod
metadata:name: nginx02namespace: defaultlabels:app02: nginx02
spec:containers:- name: mynginxports:- containerPort: 80image: nginximagePullPolicy: IfNotPresentaffinity:podAntiAffinity:requiredDuringSchedulingIgnoredDuringExecution:- labelSelector:matchExpressions:- key: app01operator: Invalues:- nginx01topologyKey: kubernetes.io/hostname # 部署資源
[root@master ~]# kubectl apply -f podAntiAffinity.yaml
pod/nginx01 created
pod/nginx02 created[root@master ~]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx01 1/1 Running 0 36s 10.244.1.19 node2 <none> <none>
nginx02 1/1 Running 0 36s 10.244.2.11 node1 <none> <none>
五、五點容忍
- 節點親和性是Pod的一種屬性,它使Pod被吸引到一類特定的節點(這可能處于一種偏好,也可能是硬性要求)。污點(Taint)則相反——它使節點能夠排斥一類特定的Pod。
- 容忍度(Toeration)是應用于Pod上的。容忍度允許調度器調度帶有對應污點的Pod容忍度允許調度并不保存調度:作為其功能的一部分,調度器也會評估其他參數
- 污點和容忍度(Toleration)相互配合,可以用來避免Pod被分配到不合適的節點上。每個節點都可以應用一個或多個污點,這表示對于那些不能容器這些污點的Pod。是不會被節點接受的
5.1、污點
-
我們給節點打一個污點,不容器的pod就運行不上來了,污點就是定義在節點上的鍵值屬性數據,可以決定拒絕那些pod
-
使用kubeadm安裝的Kubernetes集群的master節點默認具有node-role.kubernetes.io/master:NoSchedule污點
每個污點有一個key和value作為污點的標簽,effect描述污點的作用。當前faint effect支持如下效果:
-
NoSchedule:表示K8S將不會把Pod調度到具有該污點的Node節點上
-
PreferNoSchedule:表示K8S將盡量避免把Pod調度到具有該污點的Node節點上
-
NoExecyute:表示K8S將不會把Pod調度到具有該污點的Node節點上,同時會將Node上已經存在的Pod驅逐出去
5.1.1、添加污點
# 給節點 node1 增加一個污點,它的鍵名是 key1,鍵值是 value1,效果是NoSchedule
[root@master ~]# kubectl taint nodes node1 key1=value1:NoSchedule
node/node1 tainted
5.1.2、查看污點
# 查詢 node1 節點污點,找到Taints
[root@master ~]# kubectl describe node node1 | grep Taints
Taints: key1=value1:NoSchedule
5.1.3、刪除污點
# 去除節點 node1 的污點,它的鍵名是 key1,鍵值是value1,效果是NoSchedule
[root@master ~]# kubectl taint node node1 key1=value1:NoSchedule-
node/node1 untainted
5.2、容忍
- 默認情況下,Pod是不會運行在具有污點的節點上,但是我們可以配置容忍,讓Pod運行在這個節點
5.2.1、設置污點
[root@master ~]# kubectl get node
NAME STATUS ROLES AGE VERSION
master Ready control-plane,master 6d19h v1.23.0
node1 Ready <none> 6d19h v1.23.0
node2 Ready <none> 6d19h v1.23.0
[root@master ~]# kubectl taint node node1 node-type=test:NoSchedule
node/node1 tainted
[root@master ~]# kubectl taint node node2 node-type=production:NoSchedule
node/node2 tainted
5.2.2、運行沒有容忍的Pod
[root@master ~]# cat nginx-taint.yaml
apiVersion: v1
kind: Pod
metadata:name: nginxnamespace: defaultlabels:app: nginx
spec:containers:- name: nginximage: nginxports:- name: httpcontainerPort: 80# 部署資源
[root@master ~]# kubectl apply -f nginx-taint.yaml
pod/nginx created[root@master ~]# kubectl get pod
NAME READY STATUS RESTARTS AGE
nginx 0/1 Pending 0 29s# 使用describe查詢
[root@master ~]# kubectl describe pod nginx
Name: nginx
Namespace: default
Priority: 0
Node: <none>
Labels: app=nginx
Annotations: <none>
Status: Pending
IP:
IPs: <none>
Containers:nginx:Image: nginxPort: 80/TCPHost Port: 0/TCPEnvironment: <none>Mounts:/var/run/secrets/kubernetes.io/serviceaccount from kube-api-access-48d2z (ro)
Conditions:Type StatusPodScheduled False
Volumes:kube-api-access-48d2z:Type: Projected (a volume that contains injected data from multiple sources)TokenExpirationSeconds: 3607ConfigMapName: kube-root-ca.crtConfigMapOptional: <nil>DownwardAPI: true
QoS Class: BestEffort
Node-Selectors: <none>
Tolerations: node.kubernetes.io/not-ready:NoExecute op=Exists for 300snode.kubernetes.io/unreachable:NoExecute op=Exists for 300s
Events:Type Reason Age From Message---- ------ ---- ---- -------
#################################################################### Warning FailedScheduling 51s default-scheduler 0/3 nodes are available: 1 node(s) had taint {node-role.kubernetes.io/master: }, that the pod didn't tolerate, 1 node(s) had taint {node-type: production}, that the pod didn't tolerate, 1 node(s) had taint {node-type: test}, that the pod didn't tolerate.
####################################################################
5.2.3、運行帶有容忍的Pod
[root@master ~]# cat nginx-taint.yaml
apiVersion: v1
kind: Pod
metadata:name: nginxnamespace: defaultlabels:app: nginx
spec:containers:- name: nginximage: nginxports:- name: httpcontainerPort: 80# 容忍key是node-type,value是production,污點級NoSchedule的污點tolerations:- key: "node-type"operator: "Equal"value: "production"effect: "NoSchedule"# 部署資源
[root@master ~]# kubectl apply -f nginx-taint.yaml
pod/nginx configured# 因為該Pod定義了容忍node-type=production:NoSchedule污點所以可以在node2節點運行
[root@master ~]# kubectl get pod -o wide
NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
nginx 1/1 Running 0 4m31s 10.244.1.20 node2 <none> <none>
# 只要對應的鍵是存在的,exists,其值被自動定義成通配符
tolerations:
- key: "node-type"operator: "Exists"value: ""effect: "NoSchedule
# 有一個node-type的鍵,不管值是什么,不管是什么效果,都能容忍
tolerations:
- key: "node-type"operator: "Exists"value: ""effect: ""