返回文章列表

AWS Chatbot 與 Slack 整合實作 CI/CD 佈署

本文說明如何整合 AWS Chatbot 與 Slack,並建立自動化的 CI/CD 流程,將程式碼佈署至開發和生產環境。文章涵蓋設定 Slack 應用程式、建立不同環境的佈署組態、更新 Pipeline 原始碼以及佈署 CI/CD Pipeline 等步驟,最後示範如何驗證佈署結果並說明 CodePipeline

Web 開發 DevOps

透過 AWS Chatbot 與 Slack 的整合,開發團隊可以即時接收佈署通知和監控 CI/CD 流程。首先在 AWS 儀錶板中新增 Slack 應用程式,並設定對應的工作區和頻道,確保 AWS Chatbot 能夠順利傳送訊息。接著,建立 config.json 檔案設定網域名稱和子網域名稱,並分別建立 .env.development.env.production 檔案設定環境變數,用於區分開發和生產環境的佈署組態。更新 infrastructure/lib/constructs/Pipeline/index.ts 檔案中的原始碼,指定 GitHub 儲存函式庫位置和分支,並設定 OAuth 權杖。最後,執行佈署指令,CDK 將自動建立 CI/CD Pipeline。完成佈署後,可以透過瀏覽器驗證開發和生產環境的佈署結果,並在 CloudFormation 中檢視相關堆積疊資訊。

設定AWS Chatbot與Slack整合

在AWS儀錶板中設定Slack的整合需要經過幾個步驟。以下將詳細介紹如何完成這項設定。

步驟1:新增Slack應用程式至AWS儀錶板

首先,您需要在AWS儀錶板中新增Slack應用程式。請按照以下步驟進行:

  1. 登入AWS管理控制檯。
  2. 導航至AWS Chatbot設定頁面。
  3. 選擇Slack作為您的聊天平台。
  4. 您將被重新導向至Slack的授權頁面,請按照指示完成授權程式。

步驟2:設定Slack工作區

完成授權後,您將被重新導向回AWS儀錶板。請按照以下步驟完成設定:

  1. 前往「管理應用程式」頁面,您將看到新新增的Slack應用程式。
  2. 建立兩個新的頻道,分別命名為book-devbook-prod
  3. 在每個頻道上右鍵點選,選擇「複製」>「複製連結」。頻道的ID位於複製的URL末端,請妥善儲存這些值,因為稍後會用到它們。

複製Slack頻道連結

此圖示展示瞭如何複製Slack頻道的連結。

圖表翻譯: 此圖示用於展示如何在Slack中複製頻道連結的過程。首先,您需要右鍵點選頻道,然後選擇「複製連結」選項。接著,您將獲得一個包含頻道ID的URL。

步驟3:邀請AWS Chatbot加入頻道

為了在每個頻道接收通知,請執行以下操作:

  1. book-devbook-prod頻道中,分別執行/invite @AWS命令。
  2. 這樣,AWS Chatbot就會被邀請加入這兩個頻道。

邀請AWS Chatbot加入Slack頻道

此圖示展示瞭如何在Slack頻道中邀請AWS Chatbot。

圖表翻譯: 此圖示說明瞭邀請AWS Chatbot加入Slack頻道的步驟。透過執行/invite @AWS命令,您可以將AWS Chatbot新增至指定的頻道中。

建立不同環境的佈署

在本章中,為了簡化操作,我們將建立兩個不同的環境來佈署TODO應用程式:開發環境和生產環境。您可以根據需要建立其他環境,例如預發環境或演示環境。

設定config.json檔案

首先,在專案根目錄下建立一個名為config.json的檔案。檔案內容如下所示:

{
  "domain_name": "cdkbook.click",
  "backend_subdomain": "backend-cdk-book",
  "frontend_subdomain": "frontend-cdk-book",
  "backend_dev_subdomain": "dev-backend-cdk-book",
  "frontend_dev_subdomain": "dev-frontend-cdk-book"
}

請根據您的實際網域名稱組態修改domain_name欄位。

設定環境變數檔案

接下來,在infrastructure目錄下建立兩個檔案:.env.development.env.production

.env.development檔案內容

GITHUB_TOKEN=<您的個人存取權杖>
CHANNEL_ID=<BOOK_DEV_CHANNEL_ID>
WORKSPACE_ID=<您的SLACK_CHANNEL_ID>
NODE_ENV=Development

.env.production檔案內容

GITHUB_TOKEN=<您的個人存取權杖>
CHANNEL_ID=<BOOK_PROD_CHANNEL_ID>
WORKSPACE_ID=<您的SLACK_CHANNEL_ID>
NODE_ENV=Production

這些檔案用於載入不同環境下的環境變數。

更新Pipeline原始碼

為了使用分叉的儲存函式庫,請更新infrastructure/lib/constructs/Pipeline/index.ts檔案中的原始碼。具體來說,請找到以下程式碼段並更新ownerrepo屬性的值:

this.pipeline.addStage({
  stageName: 'Source',
  actions: [
    new GitHubSourceAction({
      actionName: 'Source',
      owner: '<您的GitHub使用者名稱>',
      repo: '<儲存函式庫名稱>',
      branch: `${branch}`,
      oauthToken: secretToken,
      output: outputSource,
      trigger: GitHubTrigger.WEBHOOK,
    }),
  ],
});

程式碼解密:

此段程式碼用於設定CodePipeline的原始碼階段。它指定了GitHub儲存函式庫的位置,包括擁有者、儲存函式庫名稱和分支。此外,它還設定了OAuth權杖以進行身份驗證。

佈署CI/CD Pipeline

完成上述設定後,請在終端機中執行以下命令以佈署CI/CD Pipeline:

$ yarn
$ yarn run cdk:pipeline deploy --profile cdk

當提示時,請輸入Y並按下Enter鍵。CDK將自動建立Pipeline。

檢視Pipeline執行狀態

登入AWS管理控制檯,導航至CodePipeline服務。您將看到兩個Pipeline:Chapter5-DevelopmentChapter5-Production。請等待它們的狀態變為「Succeeded」。

成功執行的Pipeline

此圖示展示了成功執行的CodePipeline。

圖表翻譯: 此圖示顯示了CodePipeline的成功執行狀態。當Pipeline成功執行時,其狀態將更新為「Succeeded」。

實作穩健的CI/CD流程

現在,讓我們來測試應用程式。選擇您新增到組態中的網域名稱,並在其後新增dev-frontend-cdk-book;在我們的例子中,即dev-frontend-cdk-book.cdkbook

成功載入開發環境的前端

這是您的開發環境!現在,從該URL中刪除dev-部分,您將獲得生產環境,在本例中應該與開發環境看起來完全相同。但它們是獨立的環境。您可以透過在其中一個環境中新增TODO專案來驗證這一點。它不會出現在另一個環境中。

現在,讓我們進入AWS服務列表中的CloudFormation,看看在那裡發生了什麼:

CloudFormation中的堆積疊列表

我們可以在堆積疊列表中看到,除了我們佈署的Chapter5PipelineStack之外,還有兩個由管道堆積疊為每個開發和生產環境建立的其他堆積疊。本質上,我們的管道堆積疊產生並維護了另外兩個堆積疊!

讓我們回到CodePipeline並檢查其中一個建立的管道。我們將選擇Chapter5-Development。在那裡,您將看到四個階段,希望全部為綠色,分別命名為SourceBack-End-TestFront-End-TestBuild-and-Deploy

階段說明

以下是每個階段的簡要說明:

  • Source:此階段負責讀取儲存函式庫,並在GitHub儲存函式庫更新時觸發其餘的管道。此階段還使用您生成的個人存取令牌。
  • Back-End-Test:此階段安裝後端的yarn依賴項(即server目錄),然後執行後端測試。如果任何測試失敗,此階段將失敗,管道將被中止。
  • Front-End-Test:此階段執行與前一階段類別似的工作,但針對前端(即web目錄)。同樣,如果任何測試失敗,管道將停止。
  • Build-and-Deploy:正如名稱所示,它執行構建和佈署操作。

內容解密:

此段落描述了CodePipeline中的四個主要階段。它們負責原始碼管理、後端測試、前端測試和最終的構建與佈署。每個階段都有其特定的任務,並且如果任何測試失敗,管道將被終止。

讓我們現在檢查一下所有這些是如何實作的。首先,看看在bin/chapter5.ts下的主要基礎設施檔案:

const app = new cdk.App();
if (['ONLY_DEV'].includes(process.env.CDK_MODE || '')) {
  new Chapter5Stack(app, `Chapter5Stack-${process.env.NODE_ENV || ''}`, {
    env: {
      region: process.env.CDK_DEFAULT_REGION,
      account: process.env.CDK_DEFAULT_ACCOUNT,
    },
  });
}
if (['ONLY_PROD'].includes(process.env.CDK_MODE || '')) {
  new Chapter5Stack(app, `Chapter5Stack-${process.env.NODE_ENV || ''}`, {
    env: {
      region: process.env.CDK_DEFAULT_REGION,
      account: process.env.CDK_DEFAULT_ACCOUNT,
    },
  });
}
if (['ONLY_PIPELINE'].includes(process.env.CDK_MODE || '')) {
  new Chapter5PipelineStack(app, 'Chapter5PipelineStack', {
    env: {
      region: process.env.CDK_DEFAULT_REGION,
      account: process.env.CDK_DEFAULT_ACCOUNT,
    },
  });
}

內容解密:

這段程式碼根據CDK_MODE環境變數的不同值例項化不同的堆積疊。如果CDK_MODE被設定為ONLY_PIPELINE,則會建立Chapter5PipelineStack。這解釋了為什麼在定義cdk:pipeline yarn命令時,將其定義為"cross-env CDK_MODE=ONLY_PIPELINE cdk"

接下來,讓我們看看在infrastructure/lib/chapter-5-pipeline-stack.ts檔案中定義的Chapter5PipelineStack

export class Chapter5PipelineStack extends Stack {
  constructor(scope: Construct, id: string, props: PipelineProps) {
    super(scope, id, props);

    new PipelineStack(this, 'Chapter5-Pipeline-Prod', {
      environment: 'Production',
    });
    new PipelineStack(this, 'Chapter5-Pipeline-Dev', {
      environment: 'Development',
    });

    Tags.of(scope).add('Project', 'Chapter5-Pipeline');
  }
}

內容解密:

此堆積疊建立了兩個PipelineStack例項,分別對應生產和開發環境。它們分享大部分程式碼,但根據環境的不同有一些差異。最後,還增加了CDK標籤以幫助識別資源。

實作強健的CI/CD流程

lib/Pipeline/index.ts檔案中,我們定義了CI/CD流程的各個階段。讓我們逐步分析這些階段。

Source階段

this.pipeline.addStage({
  stageName: 'Source',
  actions: [
    new GitHubSourceAction({
      actionName: 'Source',
      owner: '<change to your username>',
      repo: '<change to your repo name>',
      branch: `${branch}`,
      oauthToken: secretToken,
      output: outputSource,
      trigger: GitHubTrigger.WEBHOOK,
    }),
  ],
});

這個階段主要負責從GitHub倉函式庫中取得原始碼。其中,secretToken是透過讀取GITHUB_TOKEN環境變數並儲存在Secrets Manager中來建立的。

內容解密:

  1. ownerrepobranch屬性用於指定GitHub倉函式庫的位置和分支。
  2. oauthToken屬性用於驗證GitHub倉函式庫的存取許可權。
  3. output屬性將原始碼傳遞給下一個階段。

Back-End-Test階段

this.pipeline.addStage({
  stageName: 'Back-End-Test',
  actions: [
    new CodeBuildAction({
      actionName: 'Back-End-Test',
      project: this.backEndTestProject,
      input: outputSource,
      outputs: undefined,
    }),
  ],
});

這個階段主要負責執行後端測試。其中,this.backEndTestProject變數定義了一個CodeBuild專案。

內容解密:

  1. project屬性指定了要使用的CodeBuild專案。
  2. input屬性接收來自前一階段的原始碼。
  3. outputs屬性未定義,表示沒有輸出結果。

CodeBuild專案定義

this.backEndTestProject = new PipelineProject(
  scope,
  `Chapter5-BackEndTest-PipelineProject-${props.environment}`,
  {
    projectName: `Chapter5-BackEndTest-PipelineProject-${props.environment}`,
    environment: {
      buildImage: LinuxBuildImage.fromCodeBuildImageId(
        'aws/codebuild/amazonlinux2-x86_64-standard:4.0',
      ),
    },
    buildSpec: BuildSpec.fromObject({
      version: '0.2',
      phases: {
        install: {
          'runtime-versions': {
            nodejs: '16',
          },
        },
        pre_build: {
          'on-failure': 'ABORT',
          commands: ['cd server/', 'yarn install'],
        },
        build: {
          'on-failure': 'ABORT',
          commands: ['echo Testing the Back-End...', 'yarn test'],
        },
      },
    }),
  },
);

這個CodeBuild專案定義了一個建置機器,執行後端測試。

內容解密:

  1. projectName屬性定義了專案名稱,包含環境變數。
  2. environment屬性定義了建置機器的環境,使用了aws/codebuild/amazonlinux2-x86_64-standard:4.0映像檔。
  3. buildSpec屬性定義了建置規格,包括安裝、預建置和建置階段。
    • install階段安裝了Node.js 16執行環境。
    • pre_build階段執行了yarn install指令。
    • build階段執行了後端測試,並在失敗時中止建置。

Front-End-Test階段和Build-and-Deploy階段

Front-End-Test階段與Back-End-Test階段類別似,但執行的是前端測試。Build-and-Deploy階段則執行建置和佈署指令。

pipelineConfig函式

export const pipelineConfig = (env: string) => {
  if (env === 'Production') {
    return {
      path: '.env.production',
      buildCommand: 'yarn build:prod',
      deployCommand: 'yarn cdk deploy',
      branch: 'master',
      tag: 'chapter5-production-pipeline',
    };
  }
  return {
    path: '.env.development',
    buildCommand: 'yarn build:dev',
    deployCommand: 'yarn cdk:dev deploy',
    branch: 'dev',
    tag: 'chapter5-development-pipeline',
  };
};

這個函式根據環境變數傳回不同的組態設定。

內容解密:

  1. 根據環境變數傳回不同的.env檔案路徑、建置指令、佈署指令、分支和標籤。