企業運維實戰--k8s學習筆記9.k8s排程(上)
- 前言--排程器簡介
- k8s排程
-
- NodeName
- nodeSelector 親和
-
- 節點親和
- pod親和
- Taints污點與容忍
前言–排程器簡介
排程器通過 kubernetes 的 watch 機制來發現叢集中新建立且尚未被排程到 Node 上的 Pod。排程器會将發現的每一個未排程的 Pod 排程到一個合适的 Node 上來運作。
kube-scheduler 是 Kubernetes 叢集的預設排程器,并且是叢集控制面的一部分。如果你真的希望或者有這方面的需求,kube-scheduler 在設計上是允許你自己寫一個排程元件并替換原有的 kube-scheduler。
在做排程決定時需要考慮的因素包括:單獨和整體的資源請求、硬體/軟體/政策限制、親和以及反親和要求、資料局域性、負載間的幹擾等等。
k8s排程
NodeName
NodeName 是節點選擇限制的最簡單方法,它優先于其他的節點選擇方法。換言之,NodeName都無法解決的排程需求,則其他排程方法也無法做到。
缺點與限制:
- 如果指定的節點不存在。
- 如果指定的節點沒有資源來容納 pod,則pod 排程失敗。
- 雲環境中的節點名稱并非總是可預測或穩定的。
稍後實驗會對邊示範。
nodeSelector 親和
nodeSelector 是節點選擇限制的最簡單推薦形式。給選擇的節點添加标簽,通過标簽來進行排程。
親和與反親和
-
nodeSelector 提供了一種非常簡單的方法來将 pod
限制到具有特定标簽的節點上。親和/反親和功能極大地擴充了你可以表達限制的類型。
- 你可以發現規則是“軟”/“偏好”,而不是硬性要求,是以,如果排程器無法滿足該要求,仍然排程該 pod。
- 你可以使用節點上的 pod 的标簽來限制,而不是使用節點本身的标簽,來允許哪些 pod 可以或者不可以被放置在一起。
節點親和
包含兩部分:
requiredDuringSchedulingIgnoredDuringExecution 必須滿足
preferredDuringSchedulingIgnoredDuringExecution 傾向滿足
示例:
建立工作目錄并進入,編寫資源清單
mkdir schedu
cd schedu/
vim pod.yaml
cat pod.yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
env: test
spec:
containers:
- name: nginx
image: nginx
imagePullPolicy: IfNotPresent
nodeSelector:
disktype: ssd
拉起容器并檢視
kubectl apply -f pod.yaml
kubectl get pod
此時未給任何node節點添加标簽,pod節點處于Pending狀态,
稍後添加标簽後,pod将在被添加的node拉起
添加标簽後,檢視pod節點狀态
kubectl label nodes server3 disktype=ssd
kubectl get pod -o wide
删除标簽後不會消失,因為容器已經運作
kubectl label nodes server3 disktype-
kubectl get node --show-labels
kubectl get pod
測試結束後删除節點pod
kubectl delete -f pod.yaml
節點親和性pod示例
vim pod1.yaml
apiVersion: v1
kind: Pod
metadata:
name: node-affinity
spec:
containers:
- name: nginx
image: nginx
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution: #必須滿足
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: In
values:
- server3
- server4
preferredDuringSchedulingIgnoredDuringExecution: #傾向滿足
- weight: 1
preference:
matchExpressions:
- key: disktype
operator: In
values:
- ssd
先注釋掉傾向滿足,發現親和到server4
kubectl apply -f pod1.yaml
kubectl get pod -o wide
打開傾向滿足,删除節點,重新拉起容器,還在server4
vim pod1.yaml
kubectl delete -f pod1.yaml
kubectl apply -f pod1.yaml
kubectl get pod -o wide
為server3添加标簽ssd,删除節點重新開機拉起容器,服務親和到server3
kubectl label nodes server3 disktype=ssd
kubectl delete -f pod1.yaml
kubectl apply -f pod1.yaml
kubectl get pod -o wide
pod親和
pod親和,mysql容器親和nginx pod
示例:
vim pod2.yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
---
apiVersion: v1
kind: Pod
metadata:
name: mysql
labels:
app: mysql
spec:
containers:
- name: mysql
image: mysql:5.7
env:
- name: "MYSQL_ROOT_PASSWORD"
value: "westos"
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- nginx
topologyKey: kubernetes.io/hostname
kubectl apply -f pod2.yaml
kubectl get pod -o wide
可以看到mysql與nginx在同一個node節點server4上部署,這不是巧合,而是資源清單的親和部署。
反親和:
vim pod2.yaml
apiVersion: v1
kind: Pod
metadata:
name: nginx
labels:
app: nginx
spec:
containers:
- name: nginx
image: nginx
---
apiVersion: v1
kind: Pod
metadata:
name: mysql
labels:
app: mysql
spec:
containers:
- name: mysql
image: mysql:5.7
env:
- name: "MYSQL_ROOT_PASSWORD"
value: "westos"
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- nginx
topologyKey: kubernetes.io/hostname
與親和檔案的比較,不同之處
重新拉起容器,檢視mysql節點并不在nginx服務的同個節點上,實作服務與資料分離。
kubectl delete -f pod2.yaml
kubectl apply -f pod2.yaml
kubectl get pod -o wide
Taints污點與容忍
NodeAffinity節點親和性,是Pod上定義的一種屬性,使Pod能夠按我們的要求排程到某個Node上,而Taints則恰恰相反,它可以讓Node拒絕運作Pod,甚至驅逐Pod。
Taints(污點)是Node的一個屬性,設定了Taints後,是以Kubernetes是不會将Pod排程到這個Node上的,于是Kubernetes就給Pod設定了個屬性Tolerations(容忍),隻要Pod能夠容忍Node上的污點,那麼Kubernetes就會忽略Node上的污點,就能夠(不是必須)把Pod排程過去。(可通過字面意思類比了解)
總結:
可以使用指令 kubectl taint 給節點增加一個 taint:
kubectl taint nodes node1 key=value:NoSchedule #建立
kubectl describe nodes server1 |grep Taints #查詢
kubectl taint nodes node1 key:NoSchedule- #删除
其中[effect] 可取值: [ NoSchedule | PreferNoSchedule | NoExecute ]
NoSchedule:POD 不會被排程到标記為 taints 節點。
PreferNoSchedule:NoSchedule 的軟政策版本。
NoExecute:該選項意味着一旦 Taint 生效,如該節點内正在運作的 POD 沒有對應 Tolerate 設定,會直接被逐出。
示例:
server2為k8smaster主機,預設會不加入叢集排程,
檢視server2污點
kubectl describe nodes server2|grep Taint
測試1:Nodename可以無視任何污點
編輯資源清單建立pod,采用nodename指定node節點
vim pod.yaml
cat pod.yaml
拉起容器
kubectl apply -f pod.yaml
kubectl get pod
檢視節點所在node
kubectl get pod -o wide
測試結果表明,雖然server2為master且設定了污點,但是nodename可以無視污點。
測試完成删除測試pod
kubectl delete -f pod.yaml
為server2設定标簽,使用标簽方式測試污點
kubectl label nodes server2 roles=master
kubectl get nodes --show-labels
編輯資源清單,使用标簽方式選擇node
vim pod.yaml
cat pod.yaml
拉起容器,發現pod節點不能成功running
kubectl apply -f pod.yaml
kubectl get pod -o wide
測試證明,标簽選擇無法覆寫污點。
添加容忍
vim pod.yaml
cat pod.yaml
添加容忍,NoSchedule:POD 不會被排程到标記為 taints 節點。
kubectl taint nodes server3 key=value:NoSchedule
此時server3是有污點的
kubectl describe nodes server3|grep Taint
首先注釋容忍,拉起容器,發現容器在server4端運作,說明污點生效。
vim pod.yaml
cat pod.yaml
kubectl apply -f pod.yaml
kubectl get pod -o wide
删除pod節點,重新打開容忍,
kubectl delete -f pod.yaml
vim pod.yaml
cat pod.yaml
通過标簽選擇server3,
kubectl apply -f pod.yaml
kubectl get pod
測試完成後取消NoSchedule的值
NoExecute:該選項意味着一旦 Taint 生效,如該節點内正在運作的 POD 沒有對應 Tolerate 設定,會直接被逐出。被驅逐到其他node節點。
kubectl taint nodes server3 key=value:NoExecute
驅逐後 ,所有server3上再無pod,驅逐是一個過程,需要一定的時間。
kubectl get pod -o wide
測試完成,取消NoExecute的值
關閉server3的所有排程
kubectl cordon server3
kubectl get node
重新開啟server3的排程
kubectl uncordon server3
kubectl get node
關閉server3的排程,但不關閉部分必要pod
kubectl drain server3
kubectl get node
删除node
kubectl delete node server3
node節點重新開機服務即可恢複node資訊
kubectl get node
故,删除node步驟為:先驅逐pod,再删除node。
token資訊檢視和建立方法,隻有23h的儲存時間
kubeadm token list
kubeadm token create
kubeadm token list