k8s——容器啟動、退出動作+list watch機制+node節點與pod親和/反親和的排程
一、啟動、退出動作
vim demo1.yaml ========================================================== apiVersion: v1 kind: Pod metadata: name: lifecycle-demo spec: containers: - name: lifecycle-demo-container image: soscscs/myapp:v1 lifecycle: postStart: exec: command: ["/bin/sh", "-c", " echo '333333' >> /var/log/nginx/message"] preStop: exec: command: ["/bin/sh", "-c", " echo '222222' >> /var/log/nginx/message"] volumeMounts: - name: message-log mountPath: /var/log/nginx/ readOnly: false initContainers: - name: init-myservice image: soscscs/myapp:v1 command: ["/bin/sh", "-c", "echo '111111' >> /var/log/nginx/message"] volumeMounts: - name: message-log mountPath: /var/log/nginx/ readOnly: false volumes: - name: message-log hostPath: path: /data/volumes/nginx/log/ type: DirectoryOrCreate ========================================================== kubectl apply -f demo1.yaml kubectl get pods -o wide 在node01上節點上檢視 cat /data/volumes/nginx/log/message
二、k8s的List-Watch的機制
1.使用者通過kubectl或其他API客戶端提交請求給APIServer來建立一個 Pod物件副本
2.APIServer 嘗試著將Pod物件的相關元資訊存入etcd中,待寫入操作執行完成,APIServer即會返回確認資訊至客戶端
3.當etcd接受建立Pod資訊以後,會發送一個Create事件給APIServer
4.由於Controller Manager一直在監聽(Watch,通過http的8080埠)APIServer中的事件。此時APIServer接受到了Create事件,又會發送給Controller Manager
5.Controller Manager在接到Create事件以後,呼叫其中的 Replication Controller 來保證Node上面需要建立的副本數量
6.在Controller Manager建立Pod副本以後,APIServer會在etcd中記錄這個Pod的詳細資訊。例如Pod的副本數,Container的資訊
7.同樣的etcd會將建立Pod的資訊通過事件傳送給APIServer
8.由於Scheduler在監聽(Watch)APIServer,並且它在系統中起到了“承上啟下”的作用,“承上”是指它負責接收建立的Pod事件,為其安排 Node;“啟下”是指安置工作完成後,Node上的kubelet程序會接管後繼工作,負責Pod生命週期中的“下半生”。 換句話說,Scheduler的作用是將待排程的Pod按照排程演算法和策略繫結到叢集中Node上
9.Scheduler排程完畢以後會更新Pod的資訊,此時的資訊更加豐富了。除了知道Pod的副本數量,副本內容。還知道部署到哪個Node上面了。並將上面的Pod資訊更新至API Server,由APIServer更新至etcd中,儲存起來
10.etcd將更新成功的事件傳送給APIServer,APIServer也開始反映此 Pod物件的排程結果
11.kubelet是在Node上面執行的程序,它也通過List-Watch的方式監聽(Watch,通過https的6443埠)APIServer傳送的Pod更新的事件。kubelet會嘗試在當前節點上呼叫Docker啟動容器,並將Pod以及容器的結果狀態回送至APIServer
12.APIServer將Pod狀態資訊存入etcd中。在etcd確認寫入操作成功完成後,APIServer將確認資訊傳送至相關的kubelet,事件將通過它被接受
注: kubectl發命令,要擴充Pod副本數量,那麼上面的流程又會觸發一遍,kubelet會根據最新的Pod的部署情況調整Node的資源。又或者Pod 副本數量沒有發生變化,但是其中的映象檔案升級了,kubelet也會自動獲取最新的映象檔案並且載入
三、排程過程
3.1 排程策略
1.Sheduler是作為單獨的程式執行的,啟動之後會一直監聽APIServer,獲取spec.nodeName為空的pod,對每個pod都會建立一個binding,表明該pod應該放到哪個節點上
2.排程分為幾個部分:首先是過濾掉不滿足條件的節點,這個過程稱為預算策略(predicate);然後對通過的節點按照優先順序排序,這個是優選策略(priorities);最後從中選擇優先順序最高的節點。如果中間任何一步驟有錯誤,就直接返回錯誤
3.2 預算策略常見的演算法
1.PodFitsResources:節點上剩餘的資源是否大於pod請求的資源
2.PodFitsHost:如果pod指定了NodeName,檢查節點名稱是否和 NodeName匹配
3.PodFitsHostPorts:節點上已經使用的port是否和pod申請的port衝突
4.PodSelectorMatches:過濾掉和pod指定的label不匹配的節點
5.NoDiskConflict:已經mount的volume和pod指定的volume不衝突,除非它們都是隻讀
3.3 優先順序的確立
1.如果在predicate過程中沒有合適的節點,pod會一直在pending狀態,不斷重試排程,直到有節點滿足條件。 經過這個步驟,如果有多個節點滿足條件,就繼續 priorities過程:按照優先順序大小對節點排序
2.優先順序由一系列鍵值對組成,鍵是該優先順序項的名稱,值是它的權重(該項的重要性)。有一系列的常見的優先順序選項包括:
1)LeastRequestedPriority:通過計算CPU和Memory的使用率來決定權重,使用率越低權重越高。也就是說,這個優先順序指標傾向於資源使用比例更低的節點
2)BalancedResourceAllocation:節點上 CPU 和 Memory 使用率越接近,權重越高。這個一般和上面的一起使用,不單獨使用。比如 node01 的 CPU 和 Memory 使用率 20:60,node02 的 CPU 和 Memory 使用率 50:50,雖然 node01 的總使用率比 node02 低,但 node02 的 CPU 和 Memory 使用率更接近,從而排程時會優選 node02
3)ImageLocalityPriority:傾向於已經有要使用映象的節點,映象總大小值越大,權重越高
3.通過演算法對所有的優先順序專案和權重進行計算,得出最終的結果
四、指定排程節點
4.1 指定nodeName
#pod.spec.nodeName 將 Pod 直接排程到指定的 Node 節點上,會跳過 Scheduler 的排程策略,該匹配規則是強制匹配
vim demo2.yaml
==========================================================
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: myapp
spec:
replicas: 3
template:
metadata:
labels:
app: myapp
spec:
nodeName: node01
containers:
- name: myapp
image: nginx
ports:
- containerPort: 80
==========================================================
kubectl apply -f demo2.yaml
kubectl get pods -owide
kubectl describe pod myapp-86c89df7fc-6glj6
4.2 指定nodeSelector
pod.spec.nodeSelector:通過 kubernetes 的 label-selector 機制選擇節點,由排程器排程策略匹配 label,然後排程 Pod 到目標節點,該匹配規則屬於強制約束
//給對應的 node 設定標籤分別為gxd=111和gxd=222
kubectl label nodes node01 gxd=111
kubectl label nodes node02 gxd=222
//檢視標籤
kubectl get nodes --show-labels
//修改成nodeSelector排程方式
vim demo3.yaml
==========================================================
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: myapp1
spec:
replicas: 3
template:
metadata:
labels:
app: myapp1
spec:
nodeSelector:
gxd: "111"
containers:
- name: myapp1
image: nginx
ports:
- containerPort: 80
==========================================================
kubectl apply -f demo3.yaml
kubectl get pods -o wide
#檢視詳細事件(通過事件可以發現要先經過scheduler排程分配)
kubectl describe pod myapp1-55c6cc597c-8xw9x
//修改一個 label 的值,需要加上 --overwrite 引數
kubectl label nodes node02 gxd=a --overwrite
kubectl get nodes --show-labels
//刪除一個 label,只需在命令列最後指定 label 的 key 名並與一個減號相連即可:
kubectl label nodes node02 gxd-
指定標籤查詢 node 節點
kubectl get node -l gxd=111
五、親和性
5.1 分類
官方文件:https://kubernetes.io/zh/docs/concepts/scheduling-eviction/assign-pod-node/
1.節點親和性
pod.spec.nodeAffinity
●preferredDuringSchedulingIgnoredDuringExecution:軟策略
●requiredDuringSchedulingIgnoredDuringExecution:硬策略
2.Pod 親和性
pod.spec.affinity.podAffinity/podAntiAffinity
●preferredDuringSchedulingIgnoredDuringExecution:軟策略
●requiredDuringSchedulingIgnoredDuringExecution:硬策略
5.2 鍵值運算關係
1.In:label 的值在某個列表中
2.NotIn:label 的值不在某個列表中
3.Gt:label 的值大於某個值
4.Lt:label 的值小於某個值
5.Exists:某個 label 存在
6.DoesNotExist:某個 label 不存在
5.3 node節點親和性+硬策略例項
vim demo4.yaml
==========================================================
apiVersion: v1
kind: Pod
metadata:
name: affinity
labels:
app: node-affinity-pod
spec:
containers:
- name: with-node-affinity
image: nginx
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: gxd #指定node的標籤
operator: NotIn #設定Pod安裝到kubernetes.io/hostname的標籤值不在values列表中的node上
values:
- "111"
==========================================================
kubectl apply -f demo4.yaml
kubectl get pods -o wide
如果硬策略不滿足條件,Pod 狀態一直會處於 Pending 狀態
把標籤值改為gxd=222,所有節點都不滿足,建立pod檢視狀態
5.4 node節點親和性+軟策略例項
vim demo5.yaml
==========================================================
apiVersion: v1
kind: Pod
metadata:
name: affinity
labels:
app: node-affinity-pod
spec:
containers:
- name: with-node-affinity
image: nginx
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 1 #如果有多個軟策略選項的話,權重越大,優先順序越高
preference:
matchExpressions:
- key: gxd
operator: In
values:
- "111"
==========================================================
kubectl apply -f demo5.yaml
kubectl get pods -o wide
5.5 node節點親和性+軟策略+硬策略例項
vim demo6.yaml
==========================================================
apiVersion: v1
kind: Pod
metadata:
name: affinity
labels:
app: node-affinity-pod
spec:
containers:
- name: with-node-affinity
image: nginx
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution: #先滿足硬策略,排除有kubernetes.io/hostname=node02標籤的節點
nodeSelectorTerms:
- matchExpressions:
- key: kubernetes.io/hostname
operator: NotIn
values:
- node02
preferredDuringSchedulingIgnoredDuringExecution: #再滿足軟策略,優先選擇有gxd=111標籤的節點
- weight: 1
preference:
matchExpressions:
- key: gxd
operator: In
values:
- "111"
==========================================================
kubectl apply -f demo6.yaml
kubectl get pods -o wide
六、pod親和性與反親和性
6.1 建立一個標籤為app=myapp01的Pod
vim demo7.yaml
==========================================================
apiVersion: v1
kind: Pod
metadata:
name: myapp01
labels:
app: myapp01
spec:
containers:
- name: with-node-affinity
image: nginx
=========================================================
kubectl apply -f pod3.yaml
kubectl get pods --show-labels -o wide
6.2 使用Pod親和性排程
vim demo8.yaml
==========================================================
apiVersion: v1
kind: Pod
metadata:
name: myapp02
labels:
app: myapp02
spec:
containers:
- name: myapp02
image: nginx
affinity:
podAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: app
operator: In
values:
- myapp01
topologyKey: kubernetes.io/hostname
==========================================================
kubectl apply -f demo8.yaml
kubectl get pods --show-labels -o wide
==========================================================
#僅當節點和至少一個已執行且有鍵為“app”且值為“myapp01”的標籤 的 Pod 處於同一拓撲域時,才可以將該 Pod 排程到節點上。 (更確切的說,如果節點 N 具有帶有鍵 kubernetes.io/hostname 和某個值 V 的標籤,則 Pod 有資格在節點 N 上執行, 以便叢集中至少有一個節點具有鍵 kubernetes.io/hostname 和值為 V 的節點正在執行具有鍵“app”和值 “myapp01”的標籤的 pod。)
#topologyKey 是節點標籤的鍵。如果兩個節點使用此鍵標記並且具有相同的標籤值,則排程器會將這兩個節點視為處於同一拓撲域中。 排程器試圖在每個拓撲域中放置數量均衡的 Pod。
#如果kubernetes.io/hostname對應的值不一樣就是不同的拓撲域。比如 Pod1 在kubernetes.io/hostname=node01的 Node 上,Pod2 在kubernetes.io/hostname=node02的 Node 上,Pod3 在kubernetes.io/hostname=node01的 Node 上,則 Pod2 和 Pod1、Pod3 不在同一個拓撲域,而Pod1 和 Pod3在同一個拓撲域
6.2 Pod反親和性排程
vim demo9.yaml
==========================================================
apiVersion: v1
kind: Pod
metadata:
name: myapp03
labels:
app: myapp03
spec:
containers:
- name: myapp03
image: nginx
affinity:
podAntiAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: 100
podAffinityTerm:
labelSelector:
matchExpressions:
- key: app
operator: In
values:
- myapp01
topologyKey: kubernetes.io/hostname
==========================================================
kubectl apply -f demo9.yaml
kubectl get pods --show-labels -o wide
==========================================================
#如果節點處於 Pod 所在的同一拓撲域且具有鍵“app”和值“myapp01”的標籤, 則該 pod 不應將其排程到該節點上。 (如果 topologyKey 為 kubernetes.io/hostname,則意味著當節點和具有鍵 “app”和值“myapp01”的 Pod 處於相同的區域,Pod 不能被排程到該節點上。)
七、總結
7.1 親和
1.node節點親和:排程到滿足 Node 節點 的標籤條件的Node節點 nodeAffinity
硬策略:必須滿足條件 requiredDuringSchedulingIgnoredDuringExecution
軟策略:儘量滿足條件,滿足不了也沒關係 preferredDuringSchedulingIgnoredDuringExecution
2.pod親和:排程到滿足pod的標籤條件所對應的node節點 podAffinity
3.pod反親和:不排程到滿足pod的標籤條件所對應的node節點
排程策略 | 匹配標籤 | 操作符 | 拓撲域支援 | 排程目標 |
---|---|---|---|---|
nodeAffinity | 主機 | In, NotIn, Exists,DoesNotExist, Gt, Lt | 否 | 指定主機 |
podAffinity | Pod | In, NotIn, Exists,DoesNotExist | 是 | Pod與指定Pod同一拓撲域 |
podAntiAffinity | Pod | In, NotIn, Exists,DoesNotExist | 是 | Pod與指定Pod不在同一拓撲域 |
7.2 node節點硬策略配置
spec:
affinity:
nodeAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
nodeSelectorTerms:
- matchExpressions:
- key: KEY_NAME
operator: In/NotIn/Exists/DoesNotExist/Gt/Lt
values:
- KEY_VALUE
7.3 node節點軟策略配置
spec:
affinity:
nodeAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: WEIGHT_VALUE
preference:
matchExpressions:
- key: KEY_NAME
operator: In/NotIn/Exists/DoesNotExist
values:
- KEY_VALUE
7.4 pod節點(親和/反親和)硬策略配置
spec:
affinity:
podAffinity/podAnitAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchExpressions:
- key: KEY_NAME
operator: In/NotIn/Exists/DoesNotExist/Gt/Lt
values:
- KEY_VALUE
topologyKey: kubernetes.io/hostname
7.5 pod節點(親和/反親和)軟策略配置
spec:
affinity:
podAffinity/podAnitAffinity:
preferredDuringSchedulingIgnoredDuringExecution:
- weight: WEIGHT_VALUE
podAffinityTerm:
labelSelector:
matchExpressions:
- key: KEY_NAME
operator: In/NotIn/Exists/DoesNotExist
values:
- KEY_VALUE
topologyKey: kubernetes.io/hostname