多可用區(qū)同時(shí)快速?gòu)椥詳U(kuò)容
多可用區(qū)均衡是數(shù)據(jù)類型業(yè)務(wù)在高可用場(chǎng)景下常用的部署方式。當(dāng)業(yè)務(wù)壓力增大時(shí),有多可用區(qū)均衡調(diào)度策略的應(yīng)用希望可以自動(dòng)擴(kuò)容出多個(gè)可用區(qū)的實(shí)例來滿足集群的調(diào)度水位。本文介紹如何在多可用區(qū)實(shí)現(xiàn)快速?gòu)椥詳U(kuò)容。
前提條件
已選擇多個(gè)可用區(qū),并在每個(gè)可用區(qū)創(chuàng)建好vSwitch,需要在哪些可用區(qū)彈出就需要這些可用區(qū)至少有一個(gè)vSwitch。關(guān)于創(chuàng)建可用區(qū)和vSwtich的具體操作,請(qǐng)參見創(chuàng)建ACK托管集群。
背景信息
容器服務(wù)節(jié)點(diǎn)自動(dòng)伸縮組件可通過預(yù)調(diào)度判斷服務(wù)能否部署在某個(gè)伸縮組上,然后將擴(kuò)容實(shí)例個(gè)數(shù)的請(qǐng)求發(fā)給指定伸縮組,最終由ESS伸縮組生成實(shí)例。但這種在一個(gè)伸縮組上配置多個(gè)可用區(qū)vSwtich的模型特點(diǎn),會(huì)導(dǎo)致以下問題:
當(dāng)多可用區(qū)業(yè)務(wù)Pod因集群資源不足無法調(diào)度時(shí),節(jié)點(diǎn)自動(dòng)伸縮服務(wù)會(huì)觸發(fā)該伸縮組擴(kuò)容,但是無法將需要擴(kuò)容的可用區(qū)與實(shí)例的關(guān)系傳遞到ESS彈性伸縮組,因此可能會(huì)連續(xù)彈出某一個(gè)地域的多個(gè)實(shí)例,而非在多個(gè)vSwitch同時(shí)彈出,這樣無法滿足在多可用區(qū)同時(shí)擴(kuò)容的需求。
解決方案
為了解決同時(shí)擴(kuò)容多可用區(qū)節(jié)點(diǎn)的問題,容器服務(wù)ACK引入了ack-autoscaling-placeholder組件,通過少量的資源冗余方式,將多可用區(qū)的彈性伸縮問題轉(zhuǎn)變?yōu)椴l(fā)節(jié)點(diǎn)池的定向伸縮問題。具體操作,請(qǐng)參見基于ack-autoscaling-placeholder實(shí)現(xiàn)容器秒級(jí)伸縮。
具體原理如下:
首先為每個(gè)可用區(qū)創(chuàng)建一個(gè)節(jié)點(diǎn)池,并分別在各個(gè)節(jié)點(diǎn)池打上可用區(qū)的標(biāo)簽。
通過配置可用區(qū)標(biāo)簽nodeSelector的方式,使用ack-autoscaling-placeholder為每個(gè)可用區(qū)創(chuàng)建占位Pod,默認(rèn)的占位Pod具有比較低權(quán)重的PriorityClass,應(yīng)用Pod的優(yōu)先級(jí)高于占位Pod。
這樣業(yè)務(wù)應(yīng)用Pod Pending后,會(huì)搶占各個(gè)可用區(qū)占位Pod,帶有可用區(qū)nodeSelector的多可用區(qū)占位Pod處于Pending后,節(jié)點(diǎn)自動(dòng)伸縮組件感知到的調(diào)度策略就從多個(gè)可用區(qū)的antiAffinity變成了可用區(qū)的nodeSelector,從而可以輕松處理發(fā)出擴(kuò)容區(qū)域的節(jié)點(diǎn)的請(qǐng)求。
以下圖兩個(gè)可用區(qū)為例,介紹利用現(xiàn)有架構(gòu)上能滿足多可用區(qū)同時(shí)擴(kuò)容的方法。
利用ack-autoscaling-placeholder作為業(yè)務(wù)應(yīng)用和節(jié)點(diǎn)自動(dòng)伸縮組件之間的橋梁,為每個(gè)可用區(qū)創(chuàng)建占位Pod,占位Pod的調(diào)度優(yōu)先級(jí)需要低于實(shí)際業(yè)務(wù)應(yīng)用的調(diào)度優(yōu)先級(jí)。
應(yīng)用Pod Pending后會(huì)迅速搶占占位Pod,并部署在各個(gè)可用區(qū)的已有節(jié)點(diǎn)上,同時(shí)被搶占的占位Pod會(huì)處于Pending狀態(tài)。
由于占位Pod是帶有可用區(qū)nodeSelector調(diào)度策略的,節(jié)點(diǎn)自動(dòng)伸縮組件就可以并發(fā)擴(kuò)容到對(duì)應(yīng)的可用區(qū)。
步驟一:為可用區(qū)創(chuàng)建節(jié)點(diǎn)池并配置自定義節(jié)點(diǎn)標(biāo)簽
登錄容器服務(wù)管理控制臺(tái),在左側(cè)導(dǎo)航欄選擇集群。
在集群列表頁面,單擊目標(biāo)集群名稱,然后在左側(cè)導(dǎo)航欄,選擇 。
在節(jié)點(diǎn)池頁面右上角,單擊創(chuàng)建節(jié)點(diǎn)池。
在創(chuàng)建節(jié)點(diǎn)池頁面,設(shè)置創(chuàng)建節(jié)點(diǎn)池的配置項(xiàng)。本文以在可用區(qū)I創(chuàng)建開啟自動(dòng)伸縮的節(jié)點(diǎn)池auto-zone-I為例。
以下為重要配置項(xiàng)說明。其余配置項(xiàng)說明,請(qǐng)參見創(chuàng)建節(jié)點(diǎn)池。
配置項(xiàng)
說明
節(jié)點(diǎn)池名稱
auto-zone-I
虛擬交換機(jī)
選擇可用區(qū)I的虛擬交換機(jī)。
自動(dòng)伸縮
開啟自動(dòng)彈性伸縮。
節(jié)點(diǎn)標(biāo)簽
設(shè)置節(jié)點(diǎn)標(biāo)簽的鍵為avaliable_zone,值為i。
單擊確認(rèn)配置。
在節(jié)點(diǎn)池頁面,查看節(jié)點(diǎn)池列表。當(dāng)auto-zone-I節(jié)點(diǎn)池狀態(tài)為已激活,表示該節(jié)點(diǎn)池創(chuàng)建成功。
重復(fù)以上步驟,在每個(gè)需要擴(kuò)容的可用區(qū)創(chuàng)建開啟自動(dòng)伸縮的節(jié)點(diǎn)池。
步驟二:部署Placeholder及占位Deployment
在控制臺(tái)左側(cè)導(dǎo)航欄,選擇 。
在應(yīng)用目錄頁簽,搜索ack-autoscaling-placeholder,然后單擊ack-autoscaling-placeholder。
在ack-autoscaling-placeholder頁面,單擊一鍵部署。
在創(chuàng)建面板,選擇集群和命名空間,然后單擊下一步。選擇Chart版本,編輯參數(shù),然后單擊確定。
創(chuàng)建成功后,在
頁面,可查看到該應(yīng)用狀態(tài)為已部署。在集群管理頁左側(cè)導(dǎo)航欄,選擇 。
在Helm頁面,單擊ack-autoscaling-placeholder-defalut操作列的更新。
在更新發(fā)布面板中,更新YAML,然后單擊確定。將每個(gè)可用區(qū)都設(shè)置Placeholder,每個(gè)區(qū)域需要定義一個(gè)占位Deployment。
本文以在可用區(qū)I、K、H創(chuàng)建占位Deployment為例,YAML示例如下:
deployments: - affinity: {} annotations: {} containers: - image: registry-vpc.cn-beijing.aliyuncs.com/acs/pause:3.1 imagePullPolicy: IfNotPresent name: placeholder resources: requests: cpu: 3500m # 調(diào)度單元CPU。 memory: 6 # 調(diào)度單元內(nèi)存。 imagePullSecrets: {} labels: {} name: ack-place-holder-I # 占位Deployment名稱。 nodeSelector: {"avaliable_zone":i} # 可用區(qū)標(biāo)簽(需要與步驟一創(chuàng)建節(jié)點(diǎn)池中配置的標(biāo)簽一致)。 replicaCount: 10 # 每次擴(kuò)容可快速?gòu)棾鯬od數(shù)量。 tolerations: [] - affinity: {} annotations: {} containers: - image: registry-vpc.cn-beijing.aliyuncs.com/acs/pause:3.1 imagePullPolicy: IfNotPresent name: placeholder resources: requests: cpu: 3500m # 調(diào)度單元CPU。 memory: 6 # 調(diào)度單元內(nèi)存。 imagePullSecrets: {} labels: {} name: ack-place-holder-K # 占位Deployment名稱。 nodeSelector: {"avaliable_zone":k} # 可用區(qū)標(biāo)簽(需要與步驟一創(chuàng)建節(jié)點(diǎn)池中配置的標(biāo)簽一致)。 replicaCount: 10 # 每次擴(kuò)容可快速?gòu)棾鯬od數(shù)量。 tolerations: [] - affinity: {} annotations: {} containers: - image: registry-vpc.cn-beijing.aliyuncs.com/acs/pause:3.1 imagePullPolicy: IfNotPresent name: placeholder resources: requests: cpu: 3500m # 調(diào)度單元CPU。 memory: 6 # 調(diào)度單元內(nèi)存。 imagePullSecrets: {} labels: {} name: ack-place-holder-H # 占位Deployment名稱。 nodeSelector: {"avaliable_zone":h} # 可用區(qū)標(biāo)簽(需要與步驟一創(chuàng)建節(jié)點(diǎn)池中配置的標(biāo)簽一致)。 replicaCount: 10 # 每次擴(kuò)容可快速?gòu)棾鯬od數(shù)量。 tolerations: [] fullnameOverride: "" nameOverride: "" podSecurityContext: {} priorityClassDefault: enabled: true name: default-priority-class value: -1
更新成功后,在各個(gè)可用區(qū)可以查看到占位Deployment已創(chuàng)建。
步驟三:創(chuàng)建實(shí)際負(fù)載的PriorityClass
使用以下YAML示例,創(chuàng)建名為priorityClass.yaml的文件。
apiVersion: scheduling.k8s.io/v1 kind: PriorityClass metadata: name: high-priority value: 1000000 # 配置優(yōu)先級(jí),比步驟二的工作負(fù)載默認(rèn)優(yōu)先級(jí)高。 globalDefault: false description: "This priority class should be used for XYZ service pods only."
如果不希望在負(fù)載上配置PriorityClass,可以通過設(shè)置全局PriorityClass的方式進(jìn)行全局默認(rèn)設(shè)置,這樣只需要下發(fā)默認(rèn)配置后,搶占能力便自動(dòng)生效。
apiVersion: scheduling.k8s.io/v1 kind: PriorityClass metadata: name: global-high-priority value: 1 # 配置優(yōu)先級(jí),比步驟二的工作負(fù)載默認(rèn)優(yōu)先級(jí)高。 globalDefault: true description: "This priority class should be used for XYZ service pods only."
執(zhí)行以下命令,部署工作負(fù)載的PriorityClass。
kubectl apply -f priorityClass.yaml
預(yù)期輸出:
priorityclass.scheduling.k8s.io/high-priority created
步驟四:創(chuàng)建實(shí)際工作負(fù)載
以可用區(qū)I為例。
使用以下YAML示例,創(chuàng)建名為workload.yaml的文件。
apiVersion: apps/v1 kind: Deployment metadata: name: placeholder-test labels: app: nginx spec: replicas: 1 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: nodeSelector: # 節(jié)點(diǎn)選擇。 avaliable_zone: "i" priorityClassName: high-priority # 這里寫入步驟三配置的PriorityClass名稱,如果全局配置開啟,則為非必填。 containers: - name: nginx image: nginx:1.7.9 ports: - containerPort: 80 resources: requests: cpu: 3 # 實(shí)際負(fù)載的資源需求。 memory: 5
執(zhí)行以下命令,部署實(shí)際的工作負(fù)載。
kubectl apply -f workload.yaml
預(yù)期輸出:
deployment.apps/placeholder-test created
結(jié)果驗(yàn)證
部署后在
頁面可以發(fā)現(xiàn),由于實(shí)際負(fù)載的PriorityClass比占位Pod的要高,在彈出節(jié)點(diǎn)上,搶占的占位Pod會(huì)運(yùn)行起來。而被搶占的占位Pod會(huì)觸發(fā)節(jié)點(diǎn)自動(dòng)伸縮組件的并發(fā)擴(kuò)容,為下次實(shí)際負(fù)載擴(kuò)容做準(zhǔn)備。在
頁面,可以看到負(fù)載Pod運(yùn)行在之前占位Pod的節(jié)點(diǎn)上。