如何選對(duì)適合您的Kubernetes應(yīng)用發(fā)布模式
Kubernetes面向通用場(chǎng)景提供了非常靈活的應(yīng)用管理和運(yùn)維方式,而作為云效CI/CD平臺(tái)的開發(fā)同學(xué),在日常和用戶交流過程中,我們經(jīng)常會(huì)被用戶問到關(guān)于發(fā)布的問題,比如不同職能團(tuán)隊(duì)之間應(yīng)該如何配合、發(fā)布的最佳實(shí)踐應(yīng)該是什么樣子的等等。本文介紹Kubernetes下應(yīng)用發(fā)布方式的選擇,以及每種發(fā)布模式適合什么樣的場(chǎng)景。
Kubernetes應(yīng)用
首先我們來(lái)看看一般情況下Kubernetes是如何管理應(yīng)用的。 Kubernetes通過聲明式的API,并提供了一系列的資源來(lái)滿足各種各樣的應(yīng)用運(yùn)維場(chǎng)景:
從應(yīng)用的角度我們會(huì)關(guān)注應(yīng)用容器(Pod),應(yīng)用配置(ConfigMap/Secret),應(yīng)用需要持久化的信息(Volume),應(yīng)用與應(yīng)用之間的服務(wù)發(fā)現(xiàn)(Service),以及如何將應(yīng)用服務(wù)暴露給集群外的用戶(Ingress)等。
從集群運(yùn)維的角度看,由于應(yīng)用運(yùn)行在集群中我們需要控制應(yīng)用在集群中的權(quán)限(ServiceAccount/ClusterRole/Role)使得應(yīng)用能夠以最小所需權(quán)限原則在集群中運(yùn)行,同時(shí)運(yùn)維要管理和配置集群的存儲(chǔ)資源(PV/PVC),同時(shí)對(duì)于資源有限的情況我們還需要管理和控制應(yīng)用本身的資源暫用以及配額(quota)等。
而在實(shí)際場(chǎng)景中由于應(yīng)用使用的框架(Dubbo/Spring Cloud)的不同,應(yīng)用對(duì)外提供的服務(wù)場(chǎng)景不同(后端或者前端),不同的應(yīng)用可能只需要關(guān)注其中的一小部分資源。
比如當(dāng)您采用了像Spring Cloud或者Dubbo這類自帶了服務(wù)發(fā)現(xiàn)的應(yīng)用開發(fā)框架,您可能并不關(guān)心Kubernetes所提供的服務(wù)發(fā)現(xiàn)能力(Service),只需要通過Deployment來(lái)部署和管理這些應(yīng)用實(shí)例。又比如說(shuō)如果您采用了單獨(dú)的配置管理中心,那ConfigMap/Secret這些可能也不會(huì)出現(xiàn)在您的Kubernetes資源清單中。
又比如說(shuō),如果是一個(gè)面向用戶的前端應(yīng)用,在應(yīng)用部署時(shí)除了Deployment實(shí)例以外,您還要關(guān)心如何將這個(gè)服務(wù)暴露給外部用戶,這時(shí)就需要相應(yīng)的Ingress以及Service的資源來(lái)描述。
同時(shí)單個(gè)應(yīng)用在整個(gè)系統(tǒng)中所處的位置不同又會(huì)導(dǎo)致我們對(duì)于發(fā)布的驗(yàn)證方式產(chǎn)生差異,比如一個(gè)后端微服務(wù)的發(fā)布,我們可能只需要確保發(fā)布過程系統(tǒng)不中斷即可,而對(duì)于前端應(yīng)用我們可能希望發(fā)布能夠先在一小部分用戶上進(jìn)行驗(yàn)證,在線上流量充分測(cè)試后,再完成整個(gè)版本升級(jí)。
如上所示,對(duì)于應(yīng)用而言采用的技術(shù)架構(gòu)不同,提供的服務(wù)的方式不同,對(duì)發(fā)布驗(yàn)證方式要求的不同都會(huì)導(dǎo)致Kubernetes的使用上產(chǎn)生各種各樣的差異,而云效為了能夠支持這些不同的差異提供了多種多樣的發(fā)布模式,接下來(lái)我們就來(lái)看看云效下常用的這些發(fā)布模式,以及這些發(fā)布模式所適用的場(chǎng)景。
最原生:YAML發(fā)布模式
顧名思義,這是我們?cè)谑褂肒ubernetes時(shí)最直接的應(yīng)用部署方式,而在持續(xù)交付流水線中我們一般將這些用于描述Kubernetes資源的YAML文件通過Git進(jìn)行統(tǒng)一版本管理,通過云效CI/CD平臺(tái)監(jiān)聽代碼庫(kù)的變更事件,并通過流水線將這些YAML變更同步到集群當(dāng)中。這種方式也被稱為GitOps模式。
在云效當(dāng)中,我們除了支持直接同步Y(jié)AML到Kubernetes集群以外,還擴(kuò)展了基本的模板能力。您可以通過在YAML文件中定義變量占位符如${IMAGE},在流水線運(yùn)行時(shí)通過Docker鏡像構(gòu)建或者阿里云鏡像倉(cāng)庫(kù)觸發(fā)器,動(dòng)態(tài)產(chǎn)生要發(fā)布的鏡像版本。
立即體驗(yàn):云效流水線Flow
如下所示:
YAML發(fā)布支持任意資源類型,因此適用于如下場(chǎng)景:
開發(fā)自運(yùn)維:團(tuán)隊(duì)充分理解和掌握Kubernetes原生的發(fā)布策略,希望通過YAML完成應(yīng)用的升級(jí)與發(fā)布以及回滾,一般來(lái)說(shuō)應(yīng)用Git庫(kù)會(huì)包含應(yīng)用源碼,Dockerfile以及部署應(yīng)用所需的所有YAML文件(在某些情況下,YAML可能是由單獨(dú)的Git倉(cāng)庫(kù)進(jìn)行管理,以進(jìn)行細(xì)粒度的權(quán)限控制)。
基礎(chǔ)設(shè)施運(yùn)維:運(yùn)維團(tuán)隊(duì)通過Git管理集群的所有基礎(chǔ)設(shè)施配置,并通過流水線完成集群的統(tǒng)一管理以及配置的同步。
更多詳細(xì)使用介紹請(qǐng)參考:Kubernetes Kubectl 發(fā)布。
最簡(jiǎn)單:鏡像升級(jí)
在和一些用戶的交流場(chǎng)景中,也會(huì)有用戶希望開發(fā)團(tuán)隊(duì)能夠盡可能少的理解Kubernetes相關(guān)概念,在這種情況下由專職的運(yùn)維團(tuán)隊(duì)負(fù)責(zé)完成應(yīng)用環(huán)境的部署和初始化。而開發(fā)團(tuán)隊(duì)只負(fù)責(zé)完成代碼開發(fā),并通過流水線自動(dòng)化完成應(yīng)用鏡像構(gòu)建,并使用該鏡像對(duì)集群中已有的應(yīng)用進(jìn)行升級(jí)。開發(fā)團(tuán)隊(duì)只關(guān)心應(yīng)用的工作負(fù)載實(shí)例資源。
如下圖所示,在云效流水線中我們監(jiān)聽?wèi)?yīng)用代碼庫(kù)的變化,并構(gòu)建出相應(yīng)的Docker鏡像,而發(fā)布階段只需要指定對(duì)集群中實(shí)例并關(guān)聯(lián)前序任務(wù)產(chǎn)生的鏡像即可完成應(yīng)用的升級(jí)發(fā)布:
如上所述,該場(chǎng)景適用于:
開發(fā)和運(yùn)維分離:運(yùn)維團(tuán)隊(duì)充分理解Kubernetes的原生發(fā)布策略,開發(fā)團(tuán)隊(duì)只負(fù)責(zé)產(chǎn)出代碼以及應(yīng)用鏡像,由運(yùn)維團(tuán)隊(duì)負(fù)責(zé)集群中應(yīng)用的實(shí)際運(yùn)維管理。
關(guān)于如何在云效中使用鏡像升級(jí)能力,請(qǐng)參考:Kubernetes 鏡像升級(jí)。
過程可控:分批發(fā)布
在前面兩個(gè)小結(jié)中,我們都強(qiáng)調(diào)用戶需要充分理解Kubernetes的原生發(fā)布策略,Kubernetes原生的發(fā)布策略主要是指RollingUpdate模式,用戶通過聲明升級(jí)策略,如maxSurge和maxUnavailable控制Pod的啟動(dòng)策略以及最大不可用Pod數(shù),來(lái)確保即使應(yīng)用發(fā)布出現(xiàn)異常的情況,也能保證服務(wù)的基本可用。
除此之外,由于應(yīng)用啟動(dòng)往往有一定的耗時(shí),如果使用了Kubernetes的服務(wù)發(fā)現(xiàn)機(jī)制,我們還需要配置如liveness以及readiness探針,來(lái)避免應(yīng)用在啟動(dòng)過程中就有不在計(jì)劃內(nèi)的流量進(jìn)入到正在啟動(dòng)的實(shí)例當(dāng)中。同時(shí)整個(gè)發(fā)布過程是不可逆的,假如認(rèn)定當(dāng)前發(fā)布出現(xiàn)了異常我們只能通過重新發(fā)布的方式來(lái)使應(yīng)用回到可用狀態(tài)。
而在云效的分批發(fā)布中,我們以Service為最小發(fā)布單元,在發(fā)布開始階段我們將基于新版鏡像創(chuàng)建出應(yīng)用的版本V2,并根據(jù)當(dāng)前應(yīng)用的副本總數(shù)以及分批數(shù)量,對(duì)新舊兩個(gè)版本的應(yīng)用實(shí)例分別進(jìn)行縮容和擴(kuò)容,來(lái)控制實(shí)際進(jìn)入到新版應(yīng)用的流量比例,從而實(shí)現(xiàn)小規(guī)模的發(fā)布驗(yàn)證,在對(duì)發(fā)布進(jìn)行充分驗(yàn)證后再逐步完全下線老版應(yīng)用。
同時(shí)批次之間支持暫停和手動(dòng)恢復(fù)讓用戶可以充分對(duì)針對(duì)發(fā)布過程進(jìn)行控制。
該模式適用于:采用Kubernetes原生的服務(wù)發(fā)現(xiàn)機(jī)制,并希望獲得相比于原生Kubernetes發(fā)布更好過程控制性以及安全性的用戶。
關(guān)于如何在云效流水線中使用分批發(fā)布請(qǐng)參考幫助文檔:Kubernetes 分批發(fā)布。
外部流量可控:Ingress灰度發(fā)布
相比于分批發(fā)布,灰度發(fā)布更強(qiáng)調(diào)更加可控和安全的線上驗(yàn)證。而灰度發(fā)布在Kubernetes中由于應(yīng)用的部署模式的不同大致分為兩種,我們首先來(lái)說(shuō)第一種,基于Ingress的灰度發(fā)布,如下所示,我們通過Ingress將集群內(nèi)的服務(wù)暴露給外部用戶:
在發(fā)布過程中我們希望能夠通過cookie或者h(yuǎn)eader的方式使得特定的用戶或者開發(fā)人員,能夠在線上對(duì)新版本引用進(jìn)行驗(yàn)證,經(jīng)過小部分可控的線上流量驗(yàn)證后,我們的發(fā)布可靠性更好,如果出現(xiàn)預(yù)期外的問題,也可以快速回滾,并且整個(gè)灰度驗(yàn)證過程對(duì)非灰度用戶完全不可感知。
在云效流水線的Ingress灰度發(fā)布中,我們以Ingress作為發(fā)布單元,當(dāng)觸發(fā)部署后,將會(huì)根據(jù)當(dāng)前Ingress以及其關(guān)聯(lián)的Service/Deployment資源,基于新版鏡像創(chuàng)建出V2版本的Service/Deployment。并通過Nginx Ingress的Annoation完成對(duì)流量規(guī)則聲明,從而確保只有滿足特定特征的流量才能進(jìn)入到V2版本中,當(dāng)處于灰度狀態(tài)時(shí),流水線將會(huì)等待人工驗(yàn)證,以觸發(fā)發(fā)布或者回滾操作。
該模式適用于:采用Ingress對(duì)外暴露應(yīng)用服務(wù),并且希望能夠通過灰度的方式對(duì)發(fā)布進(jìn)行驗(yàn)證。
關(guān)于如何在云效流水線中使用灰度發(fā)布請(qǐng)參考幫助文檔:ACK Nginx Ingress 灰度發(fā)布。
內(nèi)部流量可控:Istio/ASM灰度發(fā)布
而在微服務(wù)的場(chǎng)景中,并不是所有的服務(wù)都需要直接暴露給外部用戶,如下所示:
當(dāng)采用微服務(wù)架構(gòu),我們大部分的后端服務(wù)是只暴露于集群內(nèi),微服務(wù)之間通過Kubernetes Service進(jìn)行相互訪問,在這種情況下,當(dāng)采用灰度發(fā)布模式時(shí),我們需要在Service級(jí)別進(jìn)行流量控制,以確保指定的流量才進(jìn)入到灰度的鏈路而不對(duì)正常用戶產(chǎn)生影響。
不過由于Kubernetes原生在Service級(jí)別并不支持任何的流量控制規(guī)則,因此我們需要在集群中部署Istio或者采用阿里云ServiceMesh來(lái)對(duì)服務(wù)之間的流量進(jìn)行細(xì)粒度的控制。
如下圖所示,當(dāng)使用Kubernetes藍(lán)綠發(fā)布模式時(shí),可以設(shè)置灰度流量規(guī)則,從而只有當(dāng)請(qǐng)求中包含指定的Cookie配置的請(qǐng)求轉(zhuǎn)發(fā)到灰度版本當(dāng)中:
該模式適用于:采用Istio或者阿里云ServiceMesh的Kubernetes用戶,并且希望能夠通過灰度的方式對(duì)發(fā)布進(jìn)行驗(yàn)證。
更多使用介紹請(qǐng)參考:Kubernetes 藍(lán)綠發(fā)布。