在雲原生時代,持續交付流程至關重要。本文將探討如何在 Docker Swarm 和 Kubernetes 上建構高效的持續交付流程,以確保應用程式快速且可靠地佈署到不同環境。首先,我們會在 Docker Swarm 上利用 Jenkins 建立自動化Pipeline,實作程式碼更新後的自動建置、測試和佈署。過程中,我們會使用 VPC 對等連線確保環境隔離,並透過 Docker Compose 進行服務協調。同時,Jenkinsfile 的使用能更精細地控制佈署流程,並整合手動驗證步驟以確保佈署品質。接著,我們將轉向 Kubernetes,使用 Terraform 在 AWS EKS 上建立叢集,並佈署微服務應用程式。過程中,我們會探討如何設定節點群組、組態 kubectl 以及建立佈署和服務資源。最後,我們將比較 Docker Swarm 和 Kubernetes 的佈署策略,並說明如何選擇適合自身需求的平台。
在 Docker Swarm 上實作雲原生應用程式的持續交付流程
10.5 實作 Jenkins 交付流程
要將應用程式堆積疊佈署到生產環境,首先需要為生產環境建立新的 Swarm 叢集。再次強調,為了隔離生產工作負載,選擇在專用的生產 VPC 中建立 Swarm 叢集,該 VPC 的 CIDR 位址區塊為 10.3.0.0/16,並在管理 VPC(Jenkins 所在位置)與生產 VPC(Swarm 生產環境佈署位置)之間設定 VPC 對等連線。圖 10.45 總結了已佈署的架構。
圖表翻譯:
此圖示展示了多個 Swarm 叢集 VPC 與管理 VPC 之間的對等連線。管理 VPC 中佈署了 Jenkins 叢集,可以存取沙盒(sandbox)、預生產(staging)和生產(production)VPC。
VPC 對等連線的注意事項
VPC 對等連線不支援過渡式對等連線(transitive peering)。這意味著生產、預生產和沙盒環境是完全隔離的,封包無法直接從沙盒路由到生產環境,例如透過管理 VPC。
在生產環境中佈署 Docker Compose
在 watchlist-deployment 儲存函式庫的主分支(master branch)上,建立一個 docker-compose.yml 檔案。這次,我們使用 latest 標籤來代表在生產環境中執行的服務,如下所示:
version: "3.3"
services:
movies-loader:
image: ID.dkr.ecr.REGION.amazonaws.com/USER/movies-loader:latest
environment:
- AWS_REGION=eu-west-3
- SQS_URL=https://sqs.REGION.amazonaws.com/ID/movies_to_parse_production
movies-parser:
image: ID.dkr.ecr.REGION.amazonaws.com/USER/movies-parser:latest
內容解密:
此 Docker Compose 檔案定義了兩個服務:movies-loader 和 movies-parser。這兩個服務分別使用了來自 Amazon ECR 的 Docker 映像,並設定了必要的環境變數,如 AWS_REGION 和 SQS_URL。使用 latest 標籤確保佈署的是最新的映像版本。
設定 Jenkins 認證與佈署流程
在 Jenkins 中建立一個認證憑證,使用用於佈署 Swarm 叢集的 SSH 金鑰,並將其命名為
swarm-production。建立一個 Jenkinsfile,用於遠端上傳
docker-compose.yml檔案到管理節點,並執行docker stack deploy命令來佈署應用程式。
def swarmManager = 'manager.production.domain.com'
def region = 'AWS REGION'
node('master') {
stage('Checkout') {
// 克隆 GitHub 儲存函式庫的指令,請參考清單 10.25
}
sshagent(credentials: ['swarm-production']) {
stage('Copy') {
// 將 docker-compose.yml 複製到 Swarm 管理節點的指令,請參考清單 10.25
}
stage('Deploy stack') {
// 透過 SSH 重新佈署 Docker Compose 堆積疊的指令,請參考清單 10.25
}
}
}
內容解密:
此 Jenkinsfile 定義了一個Pipeline,包含了簽出程式碼、複製 docker-compose.yml 到遠端伺服器以及佈署 Docker 堆積疊的階段。使用 sshagent 和 swarm-production 認證憑證來安全地連線到 Swarm 管理節點。
自動化與手動驗證的佈署流程
為了模擬產品/業務驗證或 QA 團隊在佈署到生產環境前進行測試,我們需要在佈署到生產環境前加入手動驗證步驟。
stage('Deploy') {
if (env.BRANCH_NAME == 'develop' || env.BRANCH_NAME == 'preprod') {
build job: "watchlist-deployment/${env.BRANCH_NAME}"
}
if (env.BRANCH_NAME == 'master') {
timeout(time: 2, unit: "HOURS") {
input message: "Approve Deploy?", ok: "Yes"
}
build job: "watchlist-deployment/master"
}
}
內容解密:
在此階段中,如果分支是 develop 或 preprod,則自動觸發對應的佈署作業。如果是 master 分支,則暫停Pipeline執行,並等待手動確認是否佈署到生產環境。設定了2小時的超時時間,以避免 Jenkins 工作節點長時間閒置。
合併變更與觸發佈署
- 將變更推播到功能分支,並提出一個合併請求,將變更合併到
develop分支。 - 合併變更到
develop分支後,會觸發沙盒叢集的佈署。 - 然後,提出另一個合併請求,將
develop合併到preprod分支,觸發預生產叢集的佈署。 - 最後,將
preprod合併到master分支,觸發生產環境的佈署,但需經過手動驗證。
圖表翻譯:
此圖示展示了從功能分支到 develop、preprod 和最終 master 分支的合併流程,每一步都觸發了相應環境的佈署。確保每一步都經過適當的測試和驗證,以保證軟體品質。
在Docker Swarm上佈署雲原生應用程式的持續整合與交付
Jenkins交付流程的實作
當程式碼合併發生時,Jenkins將觸發movies-loader服務的主分支建置。如圖10.54所示。然而,這次當它到達佈署階段時,將彈出一個輸入對話方塊以確認佈署。
圖10.54 主分支上的CI/CD流程執行
如圖10.55所示,互動式輸入將詢問是否批准佈署。
圖10.55 佈署使用者輸入對話方塊
如果我們點選“是”,流程將繼續,並在主分支上觸發佈署作業,如圖10.56所示。
圖10.56 生產佈署批准
在佈署過程結束時,新的堆積疊將被佈署到Swarm生產環境,並向組態的Slack頻道傳送通知(圖10.57)。
圖10.57 生產佈署成功通知
透過生產佈署的介紹,我們已經瞭解瞭如何將容器化的微服務應用程式佈署到多個環境中,以及如何在CI/CD流程中處理程式碼升級。然而,由於我們只管理三個環境(沙盒、預釋出和生產),因此我們將透過定義正規表示式來限制佈署作業的發現行為,如圖10.58所示。
圖10.58 根據正規表示式的Jenkins發現行為
因此,Jenkins將只在三個主要分支之一發生變化時才會發現並觸發,如圖10.59所示。
圖10.59 佈署多分支作業
現在,如果我們對應用程式進行任何更改,CI/CD流程將被觸發,並執行docker stack deploy,這將更新與前一版本相比發生變化的任何服務。
內容解密:
本文描述了Jenkins交付流程的實作細節,包括觸發建置、佈署確認和生產佈署的通知機制。重點介紹瞭如何透過定義正規表示式來限制佈署作業的發現行為,從而實作對多個環境的管理。
將微服務佈署到Kubernetes
設定Kubernetes叢集
AWS提供了Amazon Elastic Kubernetes Service(EKS),這是一種託管的Kubernetes服務。EKS叢集將被佈署在自定義VPC內的多個私有子網路中。EKS跨多個AWS可用區域執行Kubernetes控制平面,以消除單點故障,如圖11.2所示。
圖11.2 AWS EKS架構由佈署在私有子網路中的節點組組成
有多種工具(包括AWS CloudFormation、eksctl和kOps)可以讓您快速上手EKS。在本章中,我們選擇了Terraform,因為我們已經使用它來管理我們的Jenkins叢集在AWS上。
首先,為了託管沙盒環境,建立一個新的VPC,並將其劃分為兩個私有子網路。Amazon EKS要求至少在兩個可用區域中有子網路。
resource "aws_vpc" "sandbox" {
cidr_block = var.cidr_block
enable_dns_hostnames = true
tags = {
Name = var.vpc_name
Author = var.author
"kubernetes.io/cluster/${var.cluster_name}" = "shared"
}
}
建立EKS叢集
接下來,建立一個新的eks_masters.tf檔案,並定義sandbox EKS叢集,這是一個託管的K8s控制平面,如下所示。
resource "aws_eks_cluster" "sandbox" {
name = var.cluster_name
role_arn = aws_iam_role.cluster_role.arn
vpc_config {
security_group_ids = [aws_security_group.cluster_sg.id]
subnet_ids = [for subnet in aws_subnet.private_subnets : subnet.id]
}
depends_on = [
aws_iam_role_policy_attachment.cluster_policy,
aws_iam_role_policy_attachment.service_policy,
]
}
託管控制平面使用具有AmazonEKSClusterPolicy和AmazonEKServicePolicy策略的IAM角色。這些附件授予叢集所需的許可,以便其能夠自行管理。
工作節點的建立
現在是時候啟動一些工作節點了。節點是一個簡單的EC2例項,它執行Kubernetes物件(pod、deployment、service等)。主節點的管理由EKS控制平面負責。
內容解密:
本文描述瞭如何使用Terraform在AWS上建立EKS叢集,包括建立VPC、子網路和EKS叢集本身。同時,也介紹瞭如何組態IAM角色和策略,以授予EKS叢集必要的許可。重點介紹了使用Terraform的好處,即可以重用已有的Jenkins叢集管理經驗。
在 Kubernetes(K8s)上佈署 Dockerized 微服務
建立 Amazon EKS 叢集
要使用 Terraform 建立 Amazon Elastic Kubernetes Service(EKS)叢集,首先需要在 eks_workers.tf 檔案中定義 EKS 節點群組資源。以下範例程式碼展示瞭如何定義節點群組:
resource "aws_eks_node_group" "workers_node_group" {
cluster_name = aws_eks_cluster.sandbox.name
node_group_name = "${var.cluster_name}-workers-node-group"
node_role_arn = aws_iam_role.worker_role.arn
subnet_ids = [for subnet in aws_subnet.private_subnets : subnet.id]
scaling_config {
desired_size = 2
max_size = 5
min_size = 2
}
depends_on = [
aws_iam_role_policy_attachment.worker_node_policy,
aws_iam_role_policy_attachment.cni_policy,
aws_iam_role_policy_attachment.ecr_policy,
]
}
內容解密:
aws_eks_node_group資源用於建立 EKS 節點群組。cluster_name和node_group_name分別指定了 EKS 叢集名稱和節點群組名稱。node_role_arn指定了節點群組所使用的 IAM 角色。subnet_ids指定了節點群組所使用的子網路 ID。scaling_config用於設定節點群組的擴充套件組態,包括所需的節點數量、最大節點數量和最小節點數量。depends_on用於指定建立節點群組所依賴的資源。
設定 Kubernetes 叢集
在建立 EKS 叢集後,需要組態 kubectl 命令列工具以與叢集 API 伺服器進行通訊。首先,需要使用 AWS CLI 的 update-kubeconfig 命令來生成 kubeconfig 檔案:
aws eks update-kubeconfig --name sandbox --region AWS_REGION
然後,可以使用以下命令來驗證叢集是否正確組態和執行:
kubectl get nodes
自動化佈署流程
要使用 Jenkins 自動佈署 Watchlist 應用程式,需要建立 Kubernetes 佈署檔案。以下範例程式碼展示瞭如何定義 movies-loader 服務的佈署資源:
apiVersion: apps/v1
kind: Deployment
metadata:
name: movies-loader
namespace: watchlist
spec:
selector:
matchLabels:
app: movies-loader
template:
metadata:
labels:
app: movies-loader
spec:
containers:
- name: movies-loader
image: ID.dkr.ecr.REGION.amazonaws.com/USER/movies-loader:develop
env:
- name: AWS_REGION
value: REGION
- name: SQS_URL
value: https://sqs.REGION.amazonaws.com/ID/movies_to_parse_sandbox
內容解密:
apiVersion和kind分別指定了 Kubernetes API 版本和資源型別。metadata用於指定佈署資源的後設資料,包括名稱和名稱空間。spec用於指定佈署資源的規格,包括選擇器、範本和容器組態。containers用於指定容器組態,包括映像檔名稱、環境變數等。
MongoDB 佈署資源
以下範例程式碼展示瞭如何定義 MongoDB 的佈署資源:
apiVersion: apps/v1
kind: Deployment
metadata:
name: mongodb
namespace: watchlist
spec:
selector:
matchLabels:
app: mongodb
template:
metadata:
labels:
app: mongodb
spec:
containers:
- name: mongodb
image: bitnami/mongodb:latest
env:
- name: MONGODB_USERNAME
valueFrom:
secretKeyRef:
name: mongodb-access
key: username
- name: MONGODB_PASSWORD
valueFrom:
secretKeyRef:
name: mongodb-access
key: password
- name: MONGODB_DATABASE
valueFrom:
secretKeyRef:
name: mongodb-access
key: database
內容解密:
apiVersion和kind分別指定了 Kubernetes API 版本和資源型別。metadata用於指定佈署資源的後設資料,包括名稱和名稱空間。spec用於指定佈署資源的規格,包括選擇器、範本和容器組態。containers用於指定容器組態,包括映像檔名稱、環境變數等。- 環境變數的值從 Secret 資源中取得。