本文已超過一年。較舊的文章可能包含過時的內容。請檢查頁面中的資訊自發布以來是否已變得不正確。
在 Kubernetes 中使用 Jenkins 進行零停機部署
自從我們在 Jenkins 更新中心新增了 Kubernetes 持續部署 和 Azure Container Service 外掛程式以來,“如何建立零停機部署”是我們最常被問到的問題之一。我們在 Azure 上建立了一個快速入門範本,以示範零停機部署的外觀。雖然我們的範例使用 Azure,但這個概念很容易應用於所有 Kubernetes 安裝。
滾動更新
Kubernetes 支援 RollingUpdate 策略,逐步將舊 Pod 替換為新 Pod,同時繼續為客戶端提供服務而不會產生停機時間。要執行 RollingUpdate 部署
- 將
.spec.strategy.type
設定為RollingUpdate
(預設值)。 - 將
.spec.strategy.rollingUpdate.maxUnavailable
和.spec.strategy.rollingUpdate.maxSurge
設定為一些合理的值。maxUnavailable
:在更新過程中可能無法使用的 Pod 最大數量。這可以是絕對數字或副本計數的百分比;預設值為 25%。maxSurge
:在所需 Pod 數量之上可以建立的 Pod 最大數量。同樣,這可以是絕對數字或副本計數的百分比;預設值為 25%。
- 為您的服務容器配置
readinessProbe
,以幫助 Kubernetes 確定 Pod 的狀態。Kubernetes 將僅將客戶端流量路由到具有健康度探針的 Pod。
我們將使用官方 Tomcat 映像的部署來示範這一點
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: tomcat-deployment-rolling-update
spec:
replicas: 2
template:
metadata:
labels:
app: tomcat
role: rolling-update
spec:
containers:
- name: tomcat-container
image: tomcat:${TOMCAT_VERSION}
ports:
- containerPort: 8080
readinessProbe:
httpGet:
path: /
port: 8080
strategy:
type: RollingUpdate
rollingUp maxSurge: 50%
如果目前部署中執行的 Tomcat 是版本 7,我們可以將 ${TOMCAT_VERSION}
替換為 8,並將其應用於 Kubernetes 叢集。透過 Kubernetes 持續部署 或 Azure Container Service 外掛程式,可以從環境變數中獲取該值,從而簡化部署過程。
在幕後,Kubernetes 像這樣管理更新
- 最初,所有 Pod 都執行 Tomcat 7,並且前端服務將流量路由到這些 Pod。
- 在滾動更新期間,Kubernetes 關閉一些 Tomcat 7 Pod 並建立相應的新 Tomcat 8 Pod。它確保
- 在所需的 Pod 中,最多
maxUnavailable
個 Pod 可能無法使用,也就是說,至少 (replicas
-maxUnavailable
) 個 Pod 應為客戶端流量提供服務,在我們的例子中為 2-1=1。 - 在更新過程中,最多可以建立 maxSurge 個更多 Pod,也就是說在我們的例子中為 2*50%=1。
- 在所需的 Pod 中,最多
- 一個 Tomcat 7 Pod 被關閉,一個 Tomcat 8 Pod 被建立。Kubernetes 不會將流量路由到它們中的任何一個,因為它們的健康度探針尚未成功。
- 當新的 Tomcat 8 Pod 準備就緒 (由健康度探針確定) 時,Kubernetes 將開始將流量路由到它。這表示在更新過程中,使用者可能會同時看到舊服務和新服務。
- 滾動更新繼續關閉 Tomcat 7 Pod 並建立 Tomcat 8 Pod,然後將流量路由到就緒的 Pod。
- 最後,所有 Pod 都使用 Tomcat 8。
Rolling Update 策略確保我們始終有一些就緒的後端 Pod 為客戶端請求提供服務,因此不會發生服務停機。但是,需要額外注意一些事項
- 在更新期間,舊 Pod 和新 Pod 都可能為請求提供服務。如果服務層中沒有明確定義的會話親和性,則使用者可能會被路由到新 Pod,然後又被路由回舊 Pod。
- 這也要求您為資料和 API 維護明確定義的前向和後向相容性,這可能具有挑戰性。
- Pod 在啟動後可能需要很長時間才能準備好處理流量。可能會有很長一段時間,流量是由比平常更少的後端 Pod 提供服務。通常,這不應該是一個問題,因為我們傾向於在服務不太繁忙時執行生產升級。但這也會延長問題 1 的時間窗口。
- 我們無法對正在建立的新 Pod 進行全面的測試。將應用程式變更從開發/QA 環境移至生產環境可能會帶來破壞現有功能的持續風險。健康度探針可以做一些工作來檢查就緒狀態,但是,它應該是一個可以定期執行的輕量級任務,不適合用作啟動完整測試的入口點。
藍綠部署
藍綠部署引自 TechTarget
藍綠部署是一種用於發布軟體程式碼的變更管理策略。藍綠部署 (也可能稱為 A/B 部署) 需要兩個完全相同的硬體環境,並且配置完全相同。當一個環境處於活動狀態並為終端使用者提供服務時,另一個環境保持閒置。
容器技術提供了一個獨立的環境來執行所需的服務,這使得建立藍綠部署中所需的相同環境變得非常容易。Kubernetes 中鬆散耦合的服務 - ReplicaSet,以及基於標籤/選擇器的服務路由,使得在不同後端環境之間切換變得容易。使用這些技術,可以在 Kubernetes 中完成藍綠部署,如下所示
- 在部署之前,基礎架構的準備工作如下
- 準備藍色部署和綠色部署,並將
TOMCAT_VERSION=7
和TARGET_ROLE
分別設定為藍色或綠色。
- 準備藍色部署和綠色部署,並將
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
name: tomcat-deployment-${TARGET_ROLE}
spec:
replicas: 2
template:
metadata:
labels:
app: tomcat
role: ${TARGET_ROLE}
spec:
containers:
- name: tomcat-container
image: tomcat:${TOMCAT_VERSION}
ports:
- containerPort: 8080
readinessProbe:
httpGet:
path: /
port: 8080
- 準備公共服務端點,最初路由到後端環境之一,例如
TARGET_ROLE=blue
。
kind: Service
apiVersion: v1
metadata:
name: tomcat-service
labels:
app: tomcat
role: ${TARGET_ROLE}
env: prod
spec:
type: LoadBalancer
selector:
app: tomcat
role: ${TARGET_ROLE}
ports:
- port: 80
targetPort: 8080
- 選擇性地,準備一個測試端點,以便我們可以訪問後端環境進行測試。它們與公共服務端點類似,但它們旨在僅供開發/運維團隊在內部訪問。
kind: Service
apiVersion: v1
metadata:
name: tomcat-test-${TARGET_ROLE}
labels:
app: tomcat
role: test-${TARGET_ROLE}
spec:
type: LoadBalancer
selector:
app: tomcat
role: ${TARGET_ROLE}
ports:
- port: 80
targetPort: 8080
- 更新非活動環境中的應用程式,例如綠色環境。在部署配置中設定
TARGET_ROLE=green
和TOMCAT_VERSION=8
以更新綠色環境。 - 透過
tomcat-test-green
測試端點測試部署,以確保綠色環境已準備好為客戶端流量提供服務。 - 透過使用
TARGET_ROLE=green
更新服務配置,將前端服務路由切換到綠色環境。 - 在公共端點上執行其他測試,以確保其正常運作。
- 現在藍色環境處於閒置狀態,我們可以
- 將其保留舊應用程式,以便在新應用程式出現問題時可以回滾
- 更新它使其成為活動環境的熱備份
- 減少其副本計數以節省佔用的資源
與 Rolling Update 相比,藍綠部署的優點* 公共服務要么路由到舊應用程式,要么路由到新應用程式,但永遠不會同時路由到兩者。
- 新 Pod 準備就緒所需的時間不會影響公共服務品質,因為只有當所有新 Pod 都經過測試準備就緒後,流量才會路由到新 Pod。
- 我們可以在新環境為任何公共流量提供服務之前,對其進行全面的測試。請記住,這是在生產環境中,並且測試不應污染即時應用程式資料。
Jenkins 自動化
Jenkins 提供易於設定的工作流程來自動化您的部署作業。透過 Pipeline 支援,可以彈性地建構零停機部署工作流程,並視覺化部署步驟。為了簡化 Kubernetes 資源的部署流程,我們發布了基於 kubernetes-client 建置的 Kubernetes Continuous Deploy 和 Azure Container Service 外掛程式。您可以使用這些外掛程式將資源部署到 Azure Kubernetes Service (AKS) 或一般的 Kubernetes 叢集,而無需 kubectl,並且它們支援資源組態中的變數替換,因此您可以將環境特定的資源部署到叢集,而無需更新資源組態。我們建立了一個 Jenkins Pipeline 來示範 AKS 的藍綠部署。流程如下:
- 預先清除:清除工作區。
- SCM:從原始碼控制管理系統提取程式碼。
- 準備映像檔:準備應用程式 Docker 映像檔並將其上傳到 Docker 儲存庫。
- 檢查環境:判斷作用中和非作用中環境,這將驅動後續的部署。
- 部署:將新的應用程式資源組態部署到非作用中環境。使用 Azure Container Service 外掛程式,可以透過以下方式完成:
acsDeploy azureCredentialsId: 'stored-azure-credentials-id',
configFilePaths: "glob/path/to/*/resource-config-*.yml",
containerService: "aks-name | AKS",
resourceGroupName: "resource-group-name",
enableConfigSubstitution: true
- 驗證已暫存:驗證到非作用中環境的部署,以確保其正常運作。再次提醒,這是在生產環境中,因此請小心不要在測試期間污染實際應用程式資料。
- 確認:選擇性地,傳送電子郵件通知以進行人工使用者核准,以繼續進行實際的環境切換。
- 切換:將前端服務端點路由切換到非作用中環境。這只是另一個到 AKS Kubernetes 叢集的服務部署。
- 驗證生產環境:驗證前端服務端點在新環境中是否正常運作。
- 後續清除:對暫存檔執行一些後續清除。
對於滾動更新策略,只需將部署組態部署到 Kubernetes 叢集即可,這是一個簡單的單一步驟。
總結
我們在 Azure 上建立了一個快速入門範本,以示範如何使用 Jenkins 在 AKS (Kubernetes) 上執行零停機部署。前往 Jenkins Blue-Green Deployment on Kubernetes 並點擊「部署到 Azure」按鈕以取得可運作的示範。此範本將佈建:
- 一個 AKS 叢集,包含以下資源:
- 兩個類似的部署,代表 "blue" 和 "green" 環境。兩者最初都設定為
tomcat
:7 映像檔。 - 兩個測試端點服務 (
tomcat-test-blue
和tomcat-test-green
),它們連接到對應的部署,可用於測試部署是否已準備好用於生產環境。 - 一個生產服務端點 (
tomcat-service
),它代表使用者將存取的公開端點。最初,它路由到 "blue" 環境。
- 兩個類似的部署,代表 "blue" 和 "green" 環境。兩者最初都設定為
- 一個在 Ubuntu 16.04 VM 上執行的 Jenkins master,並已設定 Azure 服務主體認證。Jenkins 實例有兩個範例作業:
- AKS Kubernetes 滾動更新部署 Pipeline,用於示範 AKS 的滾動更新部署。
- AKS Kubernetes 藍綠部署 Pipeline,用於示範 AKS 的藍綠部署。
- 我們未在快速入門範本中包含電子郵件確認步驟。若要新增該步驟,您需要在 Jenkins 系統組態中設定電子郵件 SMTP 伺服器詳細資訊,然後在「切換」之前新增一個 Pipeline 階段。
stage('Confirm') {
mail (to: 'to@example.com',
subject: "Job '${env.JOB_NAME}' (${env.BUILD_NUMBER}) is waiting for input",
body: "Please go to ${env.BUILD_URL}.")
input 'Ready to go?'
}
依照步驟設定資源,然後您可以透過啟動 Jenkins 建置作業來試用它。