Argo Rollouts 實(shí)現(xiàn)藍(lán)綠/金絲雀發(fā)布
Argo Rollouts 是一個(gè) Kubernetes Operator 實(shí)現(xiàn),它為 Kubernetes 提供更加高級(jí)的部署能力,如藍(lán)綠、金絲雀、金絲雀分析、實(shí)驗(yàn)和漸進(jìn)式交付功能,為云原生應(yīng)用和服務(wù)實(shí)現(xiàn)自動(dòng)化、基于 GitOps 的逐步交付。
支持如下特性:
藍(lán)綠更新策略 金絲雀更新策略 更加細(xì)粒度、加權(quán)流量拆分 自動(dòng)回滾 手動(dòng)判斷 可定制的指標(biāo)查詢和業(yè)務(wù) KPI 分析 Ingress 控制器集成:NGINX,ALB 服務(wù)網(wǎng)格集成:Istio,Linkerd,SMI Metrics 指標(biāo)集成:Prometheus、Wavefront、Kayenta、Web、Kubernetes Jobs、Datadog、New Relic
實(shí)現(xiàn)原理
與 Deployment 對(duì)象類似,Argo Rollouts 控制器將管理 ReplicaSets 的創(chuàng)建、縮放和刪除,這些 ReplicaSet 由 Rollout 資源中的 spec.template 定義,使用與 Deployment 對(duì)象相同的 pod 模板。
當(dāng) spec.template 變更時(shí),這會(huì)向 Argo Rollouts 控制器發(fā)出信號(hào),表示將引入新的 ReplicaSet,控制器將使用 spec.strategy 字段內(nèi)的策略來(lái)確定從舊 ReplicaSet 到新 ReplicaSet 的 rollout 將如何進(jìn)行,一旦這個(gè)新的 ReplicaSet 被放大(可以選擇通過一個(gè) Analysis),控制器會(huì)將其標(biāo)記為穩(wěn)定。
如果在 spec.template 從穩(wěn)定的 ReplicaSet 過渡到新的 ReplicaSet 的過程中發(fā)生了另一次變更(即在發(fā)布過程中更改了應(yīng)用程序版本),那么之前的新 ReplicaSet 將縮小,并且控制器將嘗試發(fā)布反映更新 spec.template 字段的 ReplicasSet。
相關(guān)概念
在繼續(xù)之前我們先來(lái)了解一些基本的概念。
Rollout(滾動(dòng))
Rollout 是一個(gè) Kubernetes 的 CRD 資源,相當(dāng)于 Kubernetes Deployment 對(duì)象,在需要更高級(jí)的部署或漸進(jìn)式交付功能的情況下,它旨在取代 Deployment 對(duì)象,Rollout 提供了 Kubernetes Deployment 所不能提供的功能。
藍(lán)綠部署 金絲雀部署 與 Ingress 控制器和服務(wù)網(wǎng)格整合,實(shí)現(xiàn)高級(jí)流量路由 與用于藍(lán)綠和金絲雀分析的指標(biāo)提供者集成 根據(jù)成功或失敗的指標(biāo),自動(dòng)發(fā)布或回滾
漸進(jìn)式交付
漸進(jìn)式交付是以受控和漸進(jìn)的方式發(fā)布產(chǎn)品更新的過程,從而降低發(fā)布的風(fēng)險(xiǎn),通常將自動(dòng)化和指標(biāo)分析結(jié)合起來(lái)以驅(qū)動(dòng)更新的自動(dòng)升級(jí)或回滾。
漸進(jìn)式交付通常被描述為持續(xù)交付的演變,將 CI/CD 中的速度優(yōu)勢(shì)擴(kuò)展到部署過程。通過將新版本限制在一部分用戶,觀察和分析正確的行為,然后逐漸增加更多的流量,同時(shí)不斷驗(yàn)證其正確性。
部署策略
雖然業(yè)界使用了一致的術(shù)語(yǔ)來(lái)描述各種部署策略,但這些策略的實(shí)現(xiàn)往往因工具而異,為了明確 Argo Rollouts 的行為方式,以下是 Argo Rollouts 提供的各種部署策略實(shí)施的描述。
RollingUpdate(滾動(dòng)更新):慢慢地用新版本替換舊版本,隨著新版本的出現(xiàn),舊版本會(huì)慢慢縮減,以保持應(yīng)用程序的總數(shù)量。這是 Deployment 對(duì)象的默認(rèn)策略。 Recreate(重新創(chuàng)建):Recreate 會(huì)在啟動(dòng)新版本之前刪除舊版本的應(yīng)用程序,這可確保應(yīng)用程序的兩個(gè)版本永遠(yuǎn)不會(huì)同時(shí)運(yùn)行,但在部署期間會(huì)出現(xiàn)停機(jī)時(shí)間。 Blue-Green(藍(lán)綠):藍(lán)綠發(fā)布(有時(shí)稱為紅黑)指同時(shí)部署了新舊兩個(gè)版本的應(yīng)用程序,在此期間,只有舊版本的應(yīng)用程序會(huì)收到生產(chǎn)流量,這允許開發(fā)人員在將實(shí)時(shí)流量切換到新版本之前針對(duì)新版本進(jìn)行測(cè)試。

Canary(金絲雀):金絲雀發(fā)布指將一部分用戶暴露在新版本的應(yīng)用程序中,而將其余流量提供給舊版本,一旦新版本被驗(yàn)證是正確的,新版本可以逐漸取代舊版本。Ingress 控制器和服務(wù)網(wǎng)格,如 NGINX Ingress 和 Istio,可以使金絲雀的流量拆分模式比原生的更復(fù)雜(例如,實(shí)現(xiàn)非常細(xì)粒度的流量分割,或基于 HTTP 頭的分割)。

上面顯示了一個(gè)有兩個(gè)階段的金絲雀(10%和33%的流量進(jìn)入新版本),通過使用 Argo Rollouts,我們可以根據(jù)實(shí)際的使用情況定義確切的階段數(shù)和流量百分比。
場(chǎng)景
用戶希望在新版本開始為生產(chǎn)環(huán)境提供服務(wù)之前對(duì)其進(jìn)行最后一分鐘的功能測(cè)試,通過 BlueGreen 策略,Argo Rollouts 允許用戶指定預(yù)覽服務(wù)和活動(dòng)服務(wù),Rollout 將配置預(yù)覽服務(wù)以將流量發(fā)送到新版本,同時(shí)活動(dòng)服務(wù)繼續(xù)接收生產(chǎn)流量。一旦達(dá)到要求,則可以將預(yù)覽服務(wù)提升為新的活動(dòng)服務(wù)。
在新版本開始接收實(shí)時(shí)流量之前,需要預(yù)先執(zhí)行一套通用步驟,通過使用 BlueGreen 策略,用戶可以在不接收來(lái)自活動(dòng)服務(wù)的流量的情況下啟動(dòng)新版本,一旦這些步驟執(zhí)行完畢,就可以將流量切換到新版本了。
用戶希望在幾個(gè)小時(shí)內(nèi)將一小部分生產(chǎn)流量提供給他們應(yīng)用程序的新版本。之后,他們希望縮小新版本規(guī)模,并查看一些指標(biāo)以確定新版本與舊版本相比是否具有性能問題,然后他們將決定是否為切換到新版本。使用金絲雀策略,rollout 可以用新版本擴(kuò)大 ReplicaSet 的規(guī)模,以接收指定百分比的流量,等待指定的時(shí)間,然后將百分比設(shè)置回 0,然后等待用戶滿意后再發(fā)布,為所有的流量提供服務(wù)。
一個(gè)用戶想慢慢給新版增加生產(chǎn)流量,先給它一小部分的實(shí)時(shí)流量,然后等待一段時(shí)間再給新版本更多的流量,最終,新版本將接收所有生產(chǎn)流量。使用金絲雀策略,用戶指定他們希望新版本接收的百分比以及在百分比之間等待的時(shí)間。
用戶想要使用 Deployment 中的正常滾動(dòng)更新策略,如果用戶使用沒有步驟的金絲雀策略,rollout 將使用 maxSurge 和最大不可用值來(lái)滾動(dòng)到新版本。
架構(gòu)
下面展示了由 Argo Rollouts 管理的 Deployment 的所有組件。

Rollout Controller
這是主控制器,用于監(jiān)視集群的事件并在 Rollout 類型的資源發(fā)生更改時(shí)做出反應(yīng)??刂破鲗⒆x取 rollout 的所有詳細(xì)信息,并使集群處于 rollout 定義中描述的相同狀態(tài)。
請(qǐng)注意,Argo Rollouts 不會(huì)篡改或響應(yīng)正常 Deployment 資源上發(fā)生的任何變更,這意味著你可以在一個(gè)使用其他方法部署應(yīng)用的集群中安裝 Argo Rollouts。
Rollout 資源
Rollout 資源是 Argo Rollouts 引入和管理的一種自定義 Kubernetes 資源,它與原生的 Kubernetes Deployment 資源基本兼容,但有額外的字段來(lái)控制更加高級(jí)的部署方法,如金絲雀和藍(lán)/綠部署。
Argo Rollouts 控制器將只對(duì) Rollout 資源中的變化做出反應(yīng),不會(huì)對(duì)正常的 Deployment 資源做任何事情,所以如果你想用 Argo Rollouts 管理你的 Deployment,你需要將你的 Deployment 遷移到Rollouts。
舊版和新版的 ReplicaSets
這些是標(biāo)準(zhǔn)的 Kubernetes ReplicaSet 資源的實(shí)例,Argo Rollouts 給它們添加了一些額外的元數(shù)據(jù),以便跟蹤屬于應(yīng)用程序的不同版本。
還要注意的是,參加 Rollout 的 ReplicaSet 完全由控制器自動(dòng)管理,你不應(yīng)該用外部工具來(lái)篡改它們。
Ingress/Service
用戶的流量進(jìn)入集群后,被重定向到合適的版本,Argo Rollouts 使用標(biāo)準(zhǔn)的 Kubernetes Service 資源,但有一些額外的元數(shù)據(jù)。
Argo Rollouts 在網(wǎng)絡(luò)配置上非常靈活,首先,可以在 Rollout 期間使用不同的服務(wù),這些服務(wù)僅適用于新版本、僅適用于舊版本或兩者都適用。特別是對(duì)于 Canary 部署,Argo Rollouts 支持多種服務(wù)網(wǎng)格和 Ingress 解決方案,用于按特定百分比拆分流量,而不是基于 Pod 數(shù)量進(jìn)行簡(jiǎn)單的配置。
Analysis 與 AnalysisRun
Analysis 是一種自定義 Kubernetes 資源,它將 Rollout 連接到指標(biāo)提供程序,并為某些指標(biāo)定義特定閾值,這些閾值將決定 Rollout 是否成功。對(duì)于每個(gè) Analysis,你可以定義一個(gè)或多個(gè)指標(biāo)查詢及其預(yù)期結(jié)果,如果指標(biāo)查詢正常,則 Rollout 將繼續(xù)操作;如果指標(biāo)顯示失敗,則自動(dòng)回滾;如果指標(biāo)無(wú)法提供成功/失敗的答案,則暫停發(fā)布。
Analysis 只是關(guān)于要查詢哪些指標(biāo)的模板。附加到 Rollout 的實(shí)際結(jié)果是 AnalysisRun 自定義資源,你可以在特定 Rollout 上或在集群上全局定義 Analysis 以供多個(gè) rollout 共享。
請(qǐng)注意,在 Rollout 中使用 Analysis 和指標(biāo)是完全可選的,你可以通過 API 或 CLI 手動(dòng)暫停和促進(jìn)發(fā)布或使用其他外部方法(例如冒煙測(cè)試)。你不需要僅使用 Argo Rollouts 的 Metrics 解決方案,你還可以在 Rollout 中混合自動(dòng)(即基于 Analysis)和手動(dòng)步驟。
除了指標(biāo)之外,你還可以通過運(yùn)行 Kubernetes Job 或運(yùn)行 webhook 來(lái)決定發(fā)布的成功與否。
Metric Providers
Argo Rollouts 包括幾個(gè)流行的指標(biāo)提供者的原生集成,你可以在 Analysis 資源中使用,來(lái)自動(dòng)提升或回滾發(fā)布。
CLI 和 UI(圖中未顯示)
還可以使用 Argo Rollouts CLI 或集成 UI 查看和管理 Rollout,兩者都是可選的。
安裝
直接使用下面的命令安裝 Argo Rollouts:
? ~ kubectl create namespace argo-rollouts
? ~ kubectl apply -n argo-rollouts -f https://github.com/argoproj/argo-rollouts/releases/download/v1.0.2/install.yaml
這里會(huì)創(chuàng)建一個(gè)名為 argo-rollouts 的命名空間,Argo Rollouts 控制器運(yùn)行在下面。
? ~ kubectl get pods -n argo-rollouts
NAME READY STATUS RESTARTS AGE
argo-rollouts-6fdcf89f7c-7z2mh 1/1 Running 0 58s
此外,我們還可以安裝一個(gè) kubectl 插件,對(duì)于命令行管理和可視化發(fā)布非常方便。
我們這里是 Mac 系統(tǒng),可以直接使用下面的命令進(jìn)行安裝:
? ~ brew install argoproj/tap/kubectl-argo-rollouts
當(dāng)然也可以手動(dòng)進(jìn)行安裝,使用 curl 安裝 Argo Rollouts kubectl 插件:
? ~ curl -LO https://github.com/argoproj/argo-rollouts/releases/download/v1.0.2/kubectl-argo-rollouts-darwin-amd64
然后賦予 kubectl-argo-rollouts 二進(jìn)制文件可執(zhí)行權(quán)限:
? ~ chmod +x ./kubectl-argo-rollouts-darwin-amd64
將該二進(jìn)制文件移動(dòng)到你的 PATH 路徑下面去:
? ~ sudo mv ./kubectl-argo-rollouts-darwin-amd64 /usr/local/bin/kubectl-argo-rollouts
執(zhí)行下面的命令來(lái)驗(yàn)證插件是否安裝成功:
? ~ kubectl argo rollouts version
kubectl-argo-rollouts: v1.0.2+7a23fe5
BuildDate: 2021-06-15T19:36:10Z
GitCommit: 7a23fe5dbf78181248c48af8e5224246434e7f99
GitTreeState: clean
GoVersion: go1.16.3
Compiler: gc
Platform: darwin/amd64
使用
接下來(lái)我們通過幾個(gè)簡(jiǎn)單的示例來(lái)說(shuō)明 Rollout 的部署、升級(jí)、發(fā)布和中斷等操作,以此來(lái)展示 Rollouts 的各種功能。
1. 部署 Rollout
首先我們部署一個(gè) Rollout 資源和一個(gè)針對(duì)該資源的 Kubernetes Service 對(duì)象,這里我們示例中的 Rollout 采用了金絲雀的更新策略,將 20% 的流量發(fā)送到金絲雀上,然后手動(dòng)發(fā)布,最后在升級(jí)的剩余時(shí)間內(nèi)逐漸自動(dòng)增大流量,可以通過如下所示的 Rollout 來(lái)描述這個(gè)策略:
# basic-rollout.yaml
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: rollouts-demo
spec:
replicas: 5 # 定義5個(gè)副本
strategy: # 定義升級(jí)策略
canary: # 金絲雀發(fā)布
steps: # 發(fā)布的節(jié)奏
- setWeight: 20
- pause: {} # 會(huì)一直暫停
- setWeight: 40
- pause: {duration: 10}
- setWeight: 60
- pause: {duration: 10}
- setWeight: 80
- pause: {duration: 10}
revisionHistoryLimit: 2 # 下面部分其實(shí)是和 Deployment 兼容的
selector:
matchLabels:
app: rollouts-demo
template:
metadata:
labels:
app: rollouts-demo
spec:
containers:
- name: rollouts-demo
image: argoproj/rollouts-demo:blue
ports:
- name: http
containerPort: 8080
protocol: TCP
resources:
requests:
memory: 32Mi
cpu: 5m
還包括一個(gè)如下所示的 Service 資源對(duì)象:
# basic-service.yaml
apiVersion: v1
kind: Service
metadata:
name: rollouts-demo
spec:
ports:
- port: 80
targetPort: http
protocol: TCP
name: http
selector:
app: rollouts-demo
直接創(chuàng)建上面的兩個(gè)資源對(duì)象:
? ~ kubectl apply -f basic-rollout.yaml
? ~ kubectl apply -f basic-service.yaml
任何 Rollout 的初始創(chuàng)建都會(huì)立即將副本擴(kuò)展到100%(跳過任何金絲雀升級(jí)步驟、分析等...),因?yàn)檫€沒有發(fā)生升級(jí)。
Argo Rollouts 的 kubectl 插件允許我們可視化 Rollout 以及相關(guān)資源對(duì)象,并展示實(shí)時(shí)狀態(tài)變化,要在部署過程中觀察 Rollout,可以通過運(yùn)行插件的 get rollout --watch 命令,比如:
? ~ kubectl argo rollouts get rollout rollouts-demo --watch

2. 更新 Rollout
上面已經(jīng)部署完成,接下來(lái)就需要執(zhí)行更新了,和 Deployment 類似,對(duì) Pod 模板字段的任何變更都會(huì)導(dǎo)致新的版本(即 ReplicaSet)被部署,更新 Rollout 通常是修改容器鏡像的版本,然后執(zhí)行 kubectl apply ,為了方便,rollouts 插件還單獨(dú)提供了一個(gè) set image 的命令,比如這里我們運(yùn)行以下所示命令,用 yellow 版本的容器更新上面的 Rollout:
? ~ kubectl argo rollouts set image rollouts-demo \
rollouts-demo=argoproj/rollouts-demo:yellow
在 rollout 更新期間,控制器將通過 Rollout 更新策略中定義的步驟進(jìn)行。這個(gè)示例的 rollout 為金絲雀設(shè)置了20%的流量權(quán)重,并一直暫停 rollout,直到用戶取消或促進(jìn)發(fā)布。在更新鏡像后,再次觀察rollout,直到它達(dá)到暫停狀態(tài)。
? ~ kubectl argo rollouts get rollout rollouts-demo --watch

當(dāng) demo rollout 到達(dá)第二步時(shí),我們可以從插件中看到,Rollout 處于暫停狀態(tài),現(xiàn)在有5個(gè)副本中的1個(gè)運(yùn)行新版本的 pod,其余4個(gè)仍然運(yùn)行舊版本,這相當(dāng)于 setWeight: 20 步驟所定義的20%的金絲雀權(quán)重。
3. Promote Rollout
經(jīng)過上面的更新后,Rollout 現(xiàn)在處于暫停狀態(tài),當(dāng)一個(gè) Rollout 到達(dá)一個(gè)沒有持續(xù)時(shí)間的暫停步驟時(shí),它將一直保持在暫停狀態(tài),直到它被恢復(fù)/提升。要手動(dòng)將 Rollout 切換到下一個(gè)步驟,請(qǐng)運(yùn)行插件的 promotion 命令。
? ~ kubectl argo rollouts promote rollouts-demo
切換后 Rollout 將繼續(xù)執(zhí)行剩余的步驟。在我們的例子中,剩余的步驟是完全自動(dòng)化的,所以 Rollout 最終會(huì)完成步驟,直到它已經(jīng)完全過渡到新版本。再次觀察 Rollout,直到它完成所有步驟。
? ~ kubectl argo rollouts get rollout rollouts-demo --watch

promote 命令還支持用
--full標(biāo)志跳過所有剩余步驟和分析。
可以看到 stable 版本已經(jīng)切換到 revision:2 這個(gè) ReplicaSet 了。在更新過程中,無(wú)論何時(shí),無(wú)論是通過失敗的金絲雀分析自動(dòng)中止,還是由用戶手動(dòng)中止,Rollout 都會(huì)退回到 stable 版本。
4. 中斷 Rollout
接下來(lái)我們來(lái)了解如何在更新過程中手動(dòng)中止 Rollout,首先,使用 set image 命令部署一個(gè)新的 red 版本的容器,并等待 rollout 再次達(dá)到暫停的步驟。
? ~ kubectl argo rollouts set image rollouts-demo \
rollouts-demo=argoproj/rollouts-demo:red

這一次我們將中止更新,而不是將滾動(dòng)切換到下一步,這樣它就回到了 stable 版本,該插件同樣提供了一個(gè) abort 命令,可以在更新過程中的任何時(shí)候手動(dòng)中止 Rollout。
? ~ kubectl argo rollouts abort rollouts-demo
當(dāng)中止?jié)L動(dòng)時(shí),它將擴(kuò)大 ReplicaSet 的 stable 版本(在本例中是 yellow 版本),并縮小任何其他版本。盡管 ReplicaSet 的穩(wěn)定版本可能正在運(yùn)行,并且是健康的,但整個(gè) Rollout 仍然被認(rèn)為是退化的,因?yàn)槠谕陌姹荆?code style="font-size: 14px;overflow-wrap: break-word;padding: 2px 4px;border-radius: 4px;margin-right: 2px;margin-left: 2px;color: rgb(30, 107, 184);background-color: rgba(27, 31, 35, 0.05);font-family: "Operator Mono", Consolas, Monaco, Menlo, monospace;word-break: break-all;">red 版本)不是實(shí)際運(yùn)行的版本。

為了使 Rollout 再次被認(rèn)為是健康的而不是有問題的版本,有必要將所需的狀態(tài)改回以前的穩(wěn)定版本。在我們的例子中,我們可以簡(jiǎn)單地使用之前的 yellow 鏡像重新運(yùn)行 set image 命令即可。
? ~ kubectl argo rollouts set image rollouts-demo \
rollouts-demo=argoproj/rollouts-demo:yellow
運(yùn)行這個(gè)命令后,可以看到 Rollout 立即變成了 health 狀態(tài),而且沒有任何關(guān)于創(chuàng)建新 ReplicaSets 的動(dòng)態(tài)。

當(dāng) Rollout 還沒有達(dá)到預(yù)期狀態(tài)(例如,它被中止了,或者正在更新中),而穩(wěn)定版本的資源清單被重新應(yīng)用,Rollout 檢測(cè)到這是一個(gè)回滾,而不是一個(gè)更新,并將通過跳過分析和步驟快速部署穩(wěn)定的 ReplicaSet。
上面例子中的 Rollout 沒有使用 Ingress 控制器或服務(wù)網(wǎng)格來(lái)控制流量。相反,它使用正常的 Kubernetes Service 來(lái)實(shí)現(xiàn)近似的金絲雀權(quán)重,基于新舊副本數(shù)量的比例來(lái)實(shí)現(xiàn)。所以,這個(gè) Rollout 有一個(gè)限制,即它只能實(shí)現(xiàn) 20% 的最小加權(quán),通過擴(kuò)展5個(gè)pod中的一個(gè)來(lái)運(yùn)行新版本。為了實(shí)現(xiàn)更細(xì)粒度的金絲雀,這就需要一個(gè) Ingress 控制器或服務(wù)網(wǎng)格了,這部分我們可以在后續(xù)服務(wù)網(wǎng)格的學(xué)習(xí)中來(lái)介紹。
Dashboard
Argo Rollouts Kubectl 插件可以提供一個(gè)本地 Dashboard,來(lái)可視化你的 Rollouts。
要啟動(dòng)這個(gè) Dashboard,需要在包含 Rollouts 資源對(duì)象的命名空間中運(yùn)行 kubectl argo rollouts dashboard 命令,然后訪問localhost:3100 即可。

點(diǎn)擊 Rollout 可以進(jìn)行詳細(xì)頁(yè)面,在詳細(xì)頁(yè)面可以看到 Rollout 的配置信息,還可以直接在 UI 界面上執(zhí)行一些常用的操作,比如重啟、重啟、中斷等。

K8S 進(jìn)階訓(xùn)練營(yíng)
點(diǎn)擊屏末 | 閱讀原文 | 即刻學(xué)習(xí)

掃描二維碼獲取
更多云原生知識(shí)
k8s 技術(shù)圈

