在設定完 Docker Swarm 叢集和 VPC 對等連線後,我們將著手建立一個自動化的持續佈署流程,用以佈署 Docker 化的應用程式。這個流程涵蓋了從程式碼提交到應用程式佈署的完整生命週期,並整合了多種工具和技術,例如 Docker Compose、Jenkins、AWS SQS 和負載平衡器等。透過這個流程,我們可以確保應用程式能夠快速、可靠地佈署到 Swarm 叢集上,同時也能夠有效地管理應用程式的組態和版本控制。
在Docker Swarm上建立雲原生應用程式的持續佈署流程
在前一章節中,我們成功建立了Docker Swarm叢集,並完成了VPC對等連線的設定。現在,我們將繼續探討如何定義一個持續佈署流程,以自動化佈署我們的Docker化應用程式。
設定VPC對等連線
首先,我們需要設定VPC對等連線,以便管理VPC和沙箱VPC之間的通訊。請參考圖10.6,瞭解VPC對等連線的架構。
VPC對等連線的步驟:
- 建立VPC對等連線:在VPC儀錶板中,導航到Peering Connections並建立一個新的對等連線。
- 組態對等連線:按照圖10.7的組態,設定對等連線。
- 接受對等連線請求:在對等連線建立後,您將看到Pending Acceptance的狀態。請接受對等連線請求,如圖10.8所示。
- 更新路由表:在VPC路由表中,新增一條路由,將對等VPC的CIDR區塊作為目的地,並將VPC對等連線的ID作為目標。請參考圖10.9,瞭解更新後的路由表。
設定SSH隧道
為了檢視Swarm的狀態,我們需要設定一個SSH隧道,使用在第5章節中佈署的堡壘主機。
ssh -N 3000:SWARM_MANAGER_IP:22 ec2-user@BASTION_IP
ssh ec2-user@localhost -p 3000
驗證Swarm叢集
連線到Swarm管理節點後,請執行docker info命令,以驗證Swarm是否已正確組態。
docker info
執行docker node ls命令,以檢視Swarm叢集中的節點。
docker node ls
docker node ls輸出結果
此命令將顯示Swarm叢集中的節點列表,包括管理節點和工作節點,如圖10.10所示。
建立持續佈署流程
為了實作持續佈署,我們需要建立一個新的GitHub倉函式庫,用於儲存佈署相關的組態。請建立三個主要分支:develop、preprod和master,如圖10.11所示。
Docker Compose檔案
在develop分支中,建立一個docker-compose.yml檔案,使用您喜歡的文字編輯器或IDE。檔案內容如下所示:
version: "3.3"
services:
movies-loader:
image: ID.dkr.ecr.REGION.amazonaws.com/USER/movies-loader:develop
environment:
- AWS_REGION=REGION
- SQS_URL=https://sqs.REGION.amazonaws.com/ID/movies_to_parse_sandbox
movies-parser:
image: ID.dkr.ecr.REGION.amazonaws.com/USER/movies-parser:develop
environment:
- AWS_REGION=REGION
- SQS_URL=https://sqs.REGION.amazonaws.com/ID/movies_to_parse_sandbox
- MONGO_URI=mongodb://root:root@mongodb/watchlist
- MONGO_DATABASE=watchlist
depends_on:
- mongodb
movies-store:
image: ID.dkr.ecr.REGION.amazonaws.com/USER/movies-store:develop
environment:
- MONGO_URI=mongodb://root:root@mongodb/watchlist
ports:
- "3000:3000"
depends_on:
- mongodb
movies-marketplace:
image: ID.dkr.ecr.REGION.amazonaws.com/USER/movies-marketplace:develop
ports:
- "80:80"
mongodb:
image: bitnami/mongodb:latest
environment:
- MONGODB_USERNAME=root
- MONGODB_PASSWORD=root
- MONGODB_DATABASE=watchlist
內容解密:
- 定義了五個服務:movies-loader、movies-parser、movies-store、movies-marketplace和mongodb。
- 每個服務都使用了在第9章節中建立的Docker映像。
- 使用了環境變數來組態服務,例如AWS_REGION和MONGO_URI。
- 定義了服務之間的依賴關係,例如movies-parser依賴於mongodb。
使用Docker Secrets管理敏感資訊
為了避免將敏感資訊(如資料函式庫憑證)提交到版本控制系統,我們可以使用Docker Secrets來管理這些資訊。
openssl rand -base64 12 | docker secret create mongodb_password -
然後,更新docker-compose.yml檔案,以使用secret代替明文密碼:
mongodb:
image: bitnami/mongodb:latest
environment:
- MONGODB_USERNAME=root
- MONGO_ROOT_PASSWORD_FILE: /run/secrets/mongodb_password
- MONGODB_DATABASE=watchlist
內容解密:
- 使用
openssl命令生成一個隨機密碼,並將其儲存在Docker secret中。 - 更新docker-compose.yml檔案,以使用secret代替明文密碼。
在 Docker Swarm 上佈署雲原生應用程式的持續佈署流程
在前面的章節中,我們已經建立了一個 Docker Compose 檔案來定義我們的應用程式服務。現在,我們將建立一個 Jenkinsfile 來自動化佈署流程,將應用程式佈署到 Docker Swarm 上。
建立 SQS 佇列
首先,我們需要建立一個 Amazon SQS 佇列來儲存待解析的電影資料。使用 Terraform,我們可以建立一個名為 movies_to_parse_sandbox 的 SQS 佇列。
# chapter10/swarm/terraform/sqs.tf
resource "aws_sqs_queue" "movies_to_parse_sandbox" {
name = "movies_to_parse_sandbox"
}
建立 Jenkinsfile
接下來,我們需要建立一個 Jenkinsfile 來定義佈署流程。以下是一個範例 Jenkinsfile:
// chapter10/deployment/sandbox/Jenkinsfile
def swarmManager = 'manager.sandbox.domain.com'
def region = 'AWS REGION'
node('master') {
stage('Checkout') {
checkout scm
}
stage('Copy') {
sshagent(credentials: ['swarm-sandbox']) {
sh "scp -o StrictHostKeyChecking=no docker-compose.yml ec2-user@${swarmManager}:/home/ec2-user"
}
}
stage('Deploy stack') {
sshagent(credentials: ['swarm-sandbox']) {
sh "ssh -o StrictHostKeyChecking=no ec2-user@${swarmManager} '\$(\$(aws ecr get-login --no-include-email --region ${region}))' || true"
sh "ssh -o StrictHostKeyChecking=no ec2-user@${swarmManager} docker stack deploy --compose-file docker-compose.yml --with-registry-auth watchlist"
}
}
}
Jenkinsfile 內容解密:
- Checkout Stage:此階段從 GitHub 倉函式庫中簽出程式碼。
- Copy Stage:此階段使用
scp命令將docker-compose.yml檔案複製到 Swarm 管理節點上。使用了sshagent外掛來注入 SSH 認證。 - Deploy Stack Stage:此階段使用
docker stack deploy命令將應用程式佈署到 Swarm 上。同樣使用了sshagent外掛來注入 SSH 認證。
設定 Jenkins Job
在 Jenkins 上建立一個新的 Multibranch Pipeline Job,名稱為 watchlist-deployment。設定 GitHub 倉函式庫的 HTTPS Clone URL,並允許 Jenkins 發現所有分支。
新增 SSH 認證
在 Jenkins 上新增一個新的 SSH 認證,名稱為 swarm-sandbox,並將私鑰內容貼上。
觸發佈署
將 Jenkinsfile 和 docker-compose.yml 檔案推播到 develop 分支。Jenkins 將自動觸發佈署流程。
驗證佈署結果
在 Swarm 管理節點上執行 docker service ls 命令,驗證應用程式服務是否已成功佈署。
docker service ls
佈署 Visualizer
執行以下命令,在 Swarm 上佈署 Visualizer:
docker service create --name=visualizer \
--publish=8080:8080/tcp \
--constraint=node.role==manager \
--mount=type=bind,src=/var/run/docker.sock,dst=/var/run/docker.sock \
dockersamples/visualizer
Visualizer 命令內容解密:
- 建立 Visualizer 服務:此命令建立了一個名為
visualizer的服務。 - 發布埠號:將容器的 8080 埠號對映到主機的 8080 埠號。
- 限制節點角色:僅在 Swarm 管理節點上執行此服務。
- 掛載 Docker Socket:將主機的 Docker Socket 掛載到容器內,以便 Visualizer 可以存取 Docker 資訊。
透過以上步驟,我們成功地在 Docker Swarm 上佈署了雲原生應用程式,並實作了持續佈署流程。
在Docker Swarm上佈署雲原生應用程式
一旦服務佈署完成,我們將建立一個公共負載平衡器,將傳入的HTTP和HTTPS(可選)流量轉發到8080埠,這是Visualizer UI所暴露的埠。宣告ELB資源於下方的清單中,或從chapter8/services/loadbalancers.tf下載資源檔案。
建立負載平衡器與自動擴充套件群組
resource "aws_elb" "visualizer_elb" {
subnets = var.public_subnets
cross_zone_load_balancing = true
security_groups = [aws_security_group.elb_visualizer_sg.id]
listener {
instance_port = 8080
instance_protocol = "http"
lb_port = 443
lb_protocol = "https"
ssl_certificate_id = var.ssl_arn
}
listener {
instance_port = 8080
instance_protocol = "http"
lb_port = 80
lb_protocol = "http"
}
health_check {
healthy_threshold = 2
unhealthy_threshold = 2
timeout = 3
target = "TCP:8080"
interval = 5
}
}
resource "aws_autoscaling_attachment" "cluster_attach_visualizer_elb" {
autoscaling_group_name = var.swarm_managers_asg_id
elb = aws_elb.visualizer_elb.id
}
內容解密:
aws_elb資源用於建立一個Elastic Load Balancer(ELB),並組態其監聽器和健康檢查。subnets和security_groups分別指定了ELB的子網和安全群組。listener區塊定義了ELB的監聽規則,包括HTTP和HTTPS協定的轉發組態。health_check區塊定義了ELB對後端例項的健康檢查組態。aws_autoscaling_attachment資源將ELB附加到自動擴充套件群組(ASG),實作動態擴充套件。
組態DNS記錄
resource "aws_route53_record" "visualizer" {
zone_id = var.hosted_zone_id
name = "visualizer.${var.environment}.${var.domain_name}"
type = "A"
alias {
name = aws_elb.visualizer_elb.dns_name
zone_id = aws_elb.visualizer_elb.zone_id
evaluate_target_health = true
}
}
內容解密:
aws_route53_record資源用於在Route 53中建立DNS記錄,將自定義網域名稱對映到ELB的DNS名稱。alias區塊組態了別名記錄,指向ELB的DNS名稱和區域ID。
更新Jenkinsfile實作持續佈署
stage('Deploy'){
if(env.BRANCH_NAME == 'develop'){
build job: "watchlist-deployment/${env.BRANCH_NAME}"
}
}
內容解密:
- 在Jenkinsfile中新增
Deploy階段,用於在CI流程成功後觸發佈署作業。 - 使用
build job步驟呼叫另一個Jenkins作業,實作持續佈署。