摘要: 在上一篇本文中,我們示範了如何使用藍綠發佈來實現熱部署,但是在實際生產的場景中,套用的拓撲結構會複雜很多。在本篇本文中我們將會討論下複雜套用拓撲中的藍綠發佈方案以及藍綠發佈適用的場景。
前言
在上一篇本文中,我們示範了如何使用藍綠發佈來實現熱部署,但是在實際生產的場景中,套用的拓撲結構會複雜很多。在本篇本文中我們將會討論下複雜套用拓撲中的藍綠發佈方案以及藍綠發佈適用的場景。
場景剖析
大於大多數場景而言,對客戶提供服務的軟體的形態有三種。一種是前端類服務,用戶可以直接或者間接通過網頁、介面叫用使用該服務提供的能力;一種是後端類服務,用戶無法直接使用該服務提供的功能,該服務主要的消費者是其他服務,並通過其他服務最終將處理後的結果回饋給用戶;第三種是調度任務類服務,即不被用戶使用也不被其他服務叫用,它的生命週期只存在在一個任務的執行生命週期中,通常任務的執行循環完畢,服務的生命週期就停止,通常為無狀態資源密集性服務。
對於上述三種場景,以路由權數切換為主要實現方式的發佈原則例如藍綠發佈、A/BTest等通常情況下比較適用於前端類服務與後端類服務。下面我們用一個簡單的例子來拆解下如何使用阿裡雲容器服務來實現這兩類服務的藍綠發佈。
在上一篇發佈原則的本文中,有的開發人員會問我的應用程式的拓撲關聯不是單體的,不能通過單一容器等級的路由權數切換解決。在此要明確的一件事情,藍綠發佈是一種發佈原則,部署的最小維度是容器,而發佈的最小維度是套用。藍綠發佈的原理是老的套用的組建不變,新的套用組建進行部署,如果新組建與老組建之間套用的名字以及相關的設定沒有改變,那麼會認為這個套用是新老組建中共用的,無需變更;需要進行變更的套用通過名字的不同進行區分。簡單的來講,藍綠發佈是一個套用等級的更新動作,你可以對一個服務進行兩個組建之間的切換,服務是一個邏輯的概念,而不是容器這樣一個實體的概念,藍綠發佈可以做複雜拓撲的應用程式更新動作。
DEMO
下面我們通過一個拓撲結構複雜一點的例子來講述藍綠發佈。套用的拓撲結構如下:
serviceA,通過介面返回資料“world!”
from flask import Flask
app = Flask(__name__)
@app.route('/')
def world():
return 'world!'
if __name__ == '__main__':
app.run(port=5000,debug=True,host='0.0.0.0')
serviceB,叫用serviceA的介面,並將返回的資料欄位前面新增“Hello ”
from flask import Flask
import requests
import os
dep_endpoint = os.getenv('dep_endpoint');
app = Flask(__name__)
@app.route('/')
def hello():
msg = requests.get(dep_endpoint);
return 'Hello ' + msg.text;
if __name__ == '__main__':
app.run(port=5001,debug=True,host='0.0.0.0')
傳統套用之間的呼叫者式可以是通過設定IP位址或者網域名稱來叫用,也可以通過服務註冊中心中的位址的方式叫用,但是對於一個無狀態的多實例的服務,常見的做法是使用用戶端的負載平衡器或者伺服器的服務等化器端點來實現。在容器服務中使用的方式是使用伺服器端的負載平衡端點的方式,提供內部叫用的路由端點,來實現後端服務的負載平衡。大致的呼叫者式如下。
serviceA-v1:
image: 'registry-internal.cn-hangzhou.aliyuncs.com/ringtail/demo-service-a:1.0'
labels:
aliyun.scale: 3
aliyun.routing.port_5000: servicea.local
serviceB-v1:
image: 'registry-internal.cn-hangzhou.aliyuncs.com/ringtail/demo-service-b:1.0'
environment:
- 'dep_endpoint=http://servicea.local'
labels:
aliyun.scale: 2
aliyun.routing.port_5001: serviceb
external_links:
- "servicea.local"
serviceB通過external_links的方式將serviceA的內部路由端點引入,在環境變數中將dep_endpoint=http://servicea.local,使用servicea.local作為叫用的位址。
存取serviceB的對外存取位址,可以得到:
我們最開始基本結構的套用就已經部署完畢了,下面開始進行不同服務的藍綠發佈。
前端服務的藍綠發佈
首先我們先看如果做前端服務的藍綠發佈,也就是說要對serviceB進行藍綠發佈的流程。大致的結構圖如下。
在這個套用中前端服務的藍綠發佈,也就是對serviceB進行藍綠發佈,下面我們修改serviceB的代碼
from flask import Flask
import requests
import os
dep_endpoint = os.getenv('dep_endpoint');
app = Flask(__name__)
@app.route('/')
def hello():
msg = requests.get(dep_endpoint);
return 'Welcome to the ' + msg.text;//修改"Hello " => "Welcome to the "
if __name__ == '__main__':
app.run(port=5001,debug=True,host='0.0.0.0')
修改編排範本,進行藍綠發佈
serviceA-v1:
image: 'registry-internal.cn-hangzhou.aliyuncs.com/ringtail/demo-service-a:1.0'
labels:
aliyun.scale: 3
aliyun.routing.port_5000: servicea.local
serviceB-v2:
image: 'registry-internal.cn-hangzhou.aliyuncs.com/ringtail/demo-service-b:2.0'
environment:
- 'dep_endpoint=http://servicea.local'
labels:
aliyun.scale: 2
aliyun.routing.port_5001: serviceb
external_links:
- "servicea.local"
進行藍綠發佈更新後,可以看到更新後的服務清單,其中黃色的serviceA-v1表示本期的套用在藍綠發佈的程序中不會產生變化,serviceB-v1為老組建,serviceB-v2為新組建
通過路由清單選擇相應的權數管理,進行權數的調整,將serviceA-v1的權數調整為0,將serviceA-v2的權數調整為100,此時存取serviceB的網址可以發現。
驗證完畢,點選確認發佈完成,完成藍綠發佈。
後端服務的藍綠發佈
我們再看下如何做後端服務的藍綠發佈,也就是說對serviceA進行藍綠發佈。大致的結構圖如下。
修改編排範本
serviceA-v2:
image: 'registry-internal.cn-hangzhou.aliyuncs.com/ringtail/demo-service-a:2.0'
labels:
aliyun.scale: 3
aliyun.routing.coexist: true
aliyun.routing.port_5000: servicea.local
serviceB-v2:
image: 'registry-internal.cn-hangzhou.aliyuncs.com/ringtail/demo-service-b:2.0'
environment:
- 'dep_endpoint=http://servicea.local'
labels:
aliyun.scale: 2
aliyun.routing.coexist: true
aliyun.routing.port_5001: serviceb
external_links:
- "servicea.local"
部署後的服務清單:
此時可以發現serviceB-v2在本次發佈中不會進行變更,調整服務的權數
此時再存取serviceB的位址,可以得到如下的結果
總結
藍綠發佈是一種用於升級與更新的發佈原則,對於增量升級有比較好的支援,但是對於涉及資料工作表結構變更等等不可逆轉的升級,並不完全合適用藍綠發佈來實現,需要結合一些商務的邏輯以及資料移轉與復原的原則才可以完全滿足需求,希望給位開發人員可以在自己的商務場景中,更靈活的使用和實現藍綠發佈。
附錄
代碼倉庫位址:https://github.com/ringtail/BlueGreenDevelopment
相關產品:
- 容器服務(Docker)
- 企業級分散式套用服務
- 雲效
- 雲端服務器ECS