本文發表於一年多前。舊文章可能包含過時內容。請檢查頁面中的資訊自發布以來是否已變得不正確。
使用 Jenkins 在 Kubernetes 中實現零停機部署
自從我們將 Kubernetes 持續部署和 Azure 容器服務外掛新增到 Jenkins 更新中心以來,“如何建立零停機部署”是我們最常被問到的問題之一。我們在 Azure 上建立了一個快速入門模板,以演示零停機部署的外觀。儘管我們的示例使用 Azure,但該概念很容易應用於所有 Kubernetes 安裝。
滾動更新
Kubernetes 支援 RollingUpdate(滾動更新)策略,以在不造成停機的情況下逐步替換舊 Pod,同時繼續為客戶端提供服務。要執行滾動更新部署:
- 將
.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 容器服務外掛,可以從環境變數中獲取該值,從而簡化部署過程。
在幕後,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。
滾動更新策略確保我們始終有一些就緒的後端 Pod 服務客戶端請求,因此不會出現服務停機。但是,需要格外注意:
- 在更新期間,舊 Pod 和新 Pod 都可能服務請求。如果服務層中沒有明確定義的會話親和性,使用者可能會被路由到新 Pod,然後又回到舊 Pod。
- 這還要求您為資料和 API 維護明確定義的前向和後向相容性,這可能具有挑戰性。
- Pod 啟動後,可能需要很長時間才能準備好處理流量。可能會有一段較長的時間視窗,在此期間流量由比平時更少的後端 Pod 提供服務。通常,這應該不是問題,因為我們傾向於在服務不那麼繁忙時進行生產升級。但這也會延長問題 1 的時間視窗。
- 我們無法對正在建立的新 Pod 進行全面的測試。將應用程式更改從開發/QA 環境轉移到生產環境可能會帶來破壞現有功能的持續風險。就緒探測可以進行一些工作來檢查就緒狀態,但是,它應該是一個可以定期執行的輕量級任務,不適合用作啟動完整測試的入口點。
藍綠部署
引自 TechTarget 的藍綠部署:
藍綠部署是一種用於釋出軟體程式碼的變更管理策略。藍綠部署,也可能被稱為 A/B 部署,需要兩個配置完全相同的相同硬體環境。當一個環境處於活動狀態併為終端使用者提供服務時,另一個環境保持空閒。
容器技術提供了一個獨立的執行所需服務的環境,這使得建立藍綠部署所需的相同環境變得非常容易。Kubernetes 中松耦合的服務 - ReplicaSets,以及基於標籤/選擇器的服務路由使得在不同後端環境之間切換變得容易。透過這些技術,Kubernetes 中的藍綠部署可以按如下方式進行:
- 部署之前,基礎設施按如下方式準備:
- 使用
TOMCAT_VERSION=7
和TARGET_ROLE
分別設定為 blue 或 green 準備藍色部署和綠色部署。
- 使用
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
更新服務配置,將前端服務路由切換到綠色環境。 - 在公共端點上執行額外的測試,以確保其正常工作。
- 現在藍色環境處於空閒狀態,我們可以:
- 保留舊應用程式,以便在新應用程式出現問題時可以回滾。
- 更新它以使其成為活動環境的熱備份。
- 減少其副本數量以節省佔用資源。
與滾動更新相比,藍綠部署 *公共服務要麼路由到舊應用程式,要麼路由到新應用程式,但絕不會同時路由到兩者。
- 新 Pod 準備就緒所需的時間不影響公共服務質量,因為只有當所有新 Pod 都經過測試並準備就緒後,流量才會路由到它們。
- 我們可以在新環境投入公共流量服務之前對其進行全面測試。請記住,這是在生產環境中,測試不應汙染即時應用程式資料。
Jenkins 自動化
Jenkins 提供易於設定的工作流程來自動化您的部署。透過 Pipeline 支援,可以靈活地構建零停機部署工作流程並可視化部署步驟。為了方便 Kubernetes 資源的部署過程,我們釋出了基於 kubernetes-client 構建的 Kubernetes 持續部署和 Azure 容器服務外掛。您可以將資源部署到 Azure Kubernetes Service (AKS) 或通用 Kubernetes 叢集,而無需 kubectl,並且它支援資源配置中的變數替換,因此您可以將特定於環境的資源部署到叢集,而無需更新資源配置。我們建立了一個 Jenkins Pipeline 來演示 AKS 的藍綠部署。流程如下:
- 預清理:清理工作區。
- SCM:從原始碼管理系統拉取程式碼。
- 準備映象:準備應用程式 Docker 映象並將其上傳到某個 Docker 倉庫。
- 檢查環境:確定活動和非活動環境,這將驅動後續部署。
- 部署:將新的應用程式資源配置部署到非活動環境。使用 Azure 容器服務外掛,這可以透過以下方式完成:
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 Kubernetes 藍綠部署並點選“部署到 Azure”按鈕以獲取工作演示。此模板將提供:
- 一個 AKS 叢集,包含以下資源:
- 兩個相似的部署,分別代表“藍色”和“綠色”環境。兩者最初都設定為使用
tomcat
:7 映象。 - 兩個測試端點服務(
tomcat-test-blue
和tomcat-test-green
),它們連線到相應的部署,可用於測試部署是否已準備好投入生產使用。 - 一個生產服務端點(
tomcat-service
),代表使用者將訪問的公共端點。最初,它路由到“藍色”環境。
- 兩個相似的部署,分別代表“藍色”和“綠色”環境。兩者最初都設定為使用
- 一個執行在 Ubuntu 16.04 VM 上的 Jenkins Master,並配置了 Azure 服務主體憑據。Jenkins 例項有兩個示例作業:
- AKS Kubernetes 滾動更新部署流水線,用於演示 AKS 的滾動更新部署。
- AKS Kubernetes 藍綠部署流水線,用於演示 AKS 的藍綠部署。
- 我們沒有在快速入門模板中包含電子郵件確認步驟。要新增此步驟,您需要在 Jenkins 系統配置中配置電子郵件 SMTP 伺服器詳細資訊,然後在“切換”之前新增一個流水線階段。
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 構建作業即可進行嘗試。