返回文章列表

Docker Swarm 雲原生應用程式持續佈署流程

本文闡述如何在 Docker Swarm 上建立雲原生應用程式的持續佈署流程,包含 VPC 對等連線設定、SSH 隧道建立、Swarm 叢集驗證、持續佈署流程建立、Docker Compose 檔案撰寫、Docker Secrets 使用、Jenkinsfile 建立與設定、SQS

容器技術 DevOps

在設定完 Docker Swarm 叢集和 VPC 對等連線後,我們將著手建立一個自動化的持續佈署流程,用以佈署 Docker 化的應用程式。這個流程涵蓋了從程式碼提交到應用程式佈署的完整生命週期,並整合了多種工具和技術,例如 Docker Compose、Jenkins、AWS SQS 和負載平衡器等。透過這個流程,我們可以確保應用程式能夠快速、可靠地佈署到 Swarm 叢集上,同時也能夠有效地管理應用程式的組態和版本控制。

在Docker Swarm上建立雲原生應用程式的持續佈署流程

在前一章節中,我們成功建立了Docker Swarm叢集,並完成了VPC對等連線的設定。現在,我們將繼續探討如何定義一個持續佈署流程,以自動化佈署我們的Docker化應用程式。

設定VPC對等連線

首先,我們需要設定VPC對等連線,以便管理VPC和沙箱VPC之間的通訊。請參考圖10.6,瞭解VPC對等連線的架構。

VPC對等連線的步驟:

  1. 建立VPC對等連線:在VPC儀錶板中,導航到Peering Connections並建立一個新的對等連線。
  2. 組態對等連線:按照圖10.7的組態,設定對等連線。
  3. 接受對等連線請求:在對等連線建立後,您將看到Pending Acceptance的狀態。請接受對等連線請求,如圖10.8所示。
  4. 更新路由表:在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 內容解密:

  1. Checkout Stage:此階段從 GitHub 倉函式庫中簽出程式碼。
  2. Copy Stage:此階段使用 scp 命令將 docker-compose.yml 檔案複製到 Swarm 管理節點上。使用了 sshagent 外掛來注入 SSH 認證。
  3. 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 命令內容解密:

  1. 建立 Visualizer 服務:此命令建立了一個名為 visualizer 的服務。
  2. 發布埠號:將容器的 8080 埠號對映到主機的 8080 埠號。
  3. 限制節點角色:僅在 Swarm 管理節點上執行此服務。
  4. 掛載 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),並組態其監聽器和健康檢查。
  • subnetssecurity_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作業,實作持續佈署。