在雲端環境中佈署和管理資料函式庫需要兼顧安全性和擴充套件性。本文將詳細說明如何運用 AWS CDK 建立和設定 AWS RDS MySQL 資料函式庫,並整合 Lambda 函式進行初始化,同時妥善管理敏感資訊,例如資料函式庫憑證。此外,我們也會探討如何設定 ECS 應用程式容器的許可權,使其能夠安全地存取資料函式庫,並利用 ACM 憑證自動化驗證流程,簡化佈署作業。最後,文章還會介紹如何利用 AWS CDK 建構 CI/CD Pipeline,實作自動化佈署和更新。

使用AWS RDS的MySQL資料函式庫佈署

在現代的雲端運算架構中,資料函式庫的安全性和可擴充套件性是至關重要的。AWS RDS(Relational Database Service)提供了一個強大且易於管理的資料函式庫解決方案。在本章中,我們將探討如何使用AWS CDK(Cloud Development Kit)佈署一個由AWS RDS支援的MySQL資料函式庫。

初始化資料函式庫的Lambda函式

首先,我們來看看用於初始化資料函式庫的Lambda函式的Dockerfile,位於infrastructure/lib/constructs/RDS/init

FROM amazon/aws-lambda-nodejs:14
WORKDIR ${LAMBDA_TASK_ROOT}
COPY package.json ./
RUN npm install --only=production
COPY index.js ./
COPY script.sql ./
CMD [ "index.handler" ]

內容解密:

  1. 我們根據amazon/aws-lambda-nodejs:14映像檔建立Lambda函式的執行環境。
  2. 設定工作目錄為${LAMBDA_TASK_ROOT},這是Lambda函式執行所需的環境變數。
  3. 複製package.jsonindex.js檔案到容器中,並執行npm install安裝依賴套件。
  4. script.sql檔案複製到容器中,以便Lambda函式執行SQL指令碼。

接下來,我們來看看Lambda函式的處理程式程式碼,位於index.js檔案中:

try {
  const { config } = e.params;
  const { password, username, host } = await getSecretValue(
    config.credentials_secret_name,
  );
  const connection = mysql.createConnection({
    host,
    user: username,
    password,
    multipleStatements: true,
  });
  connection.connect();
  
  const sqlScript = fs
    .readFileSync(path.join(__dirname, 'script.sql'))
    .toString();
  const res = await query(connection, sqlScript);
  
  return {
    status: 'OK',
    results: res,
  };
} catch (err) {
  return {
    status: 'ERROR',
    err,
    message: err.message,
  };
}

內容解密:

  • 從AWS Secrets Manager取得資料函式庫連線引數,包括主機名稱、使用者名稱和密碼。
  • 建立MySQL連線並執行SQL指令碼。
  • 如果執行成功,回傳狀態為’OK’的結果;否則,回傳狀態為’ERROR’的錯誤訊息。

儲存敏感資訊

在佈署過程中,我們需要儲存敏感資訊,如資料函式庫憑證。AWS Secrets Manager提供了一個安全的方式來管理這些敏感資訊。

const instance_id = 'my-sql-instance';
const credentials_secret_name = `chapter-4/rds/${instance_id}`;
this.credentials = new rds.DatabaseSecret(scope, 'MySQLCredentials', {
  secretName: credentials_secret_name,
  username: 'admin',
});

內容解密:

  • 使用DatabaseSecret建構函式建立一個新的秘密,包含資料函式庫的使用者名稱和自動生成的密碼。
  • 將這個秘密儲存在AWS Secrets Manager中。

為了讓Lambda函式能夠存取這個秘密,我們需要授予它讀取秘密的許可權:

this.credentials.grantRead(initializer.function);

內容解密:

  • 使用grantRead方法授予Lambda函式讀取秘密的許可權。

同樣地,我們也需要為ECS應用程式容器授予存取秘密的許可權:

this.ecs.task_definition.taskRole.addToPrincipalPolicy(
  new PolicyStatement({
    actions: ['secretsmanager:GetSecretValue'],
    resources: [this.rds.credentials.secretArn],
  }),
);

內容解密:

  • 為ECS任務角色新增一個策略陳述式,允許它執行secretsmanager:GetSecretValue動作,以存取指定的秘密。

使用AWS CDK實作完整的Web應用程式佈署

在上一章中,我們學習瞭如何使用AWS CDK來佈署一個完整的Web應用程式。本章將重點介紹如何使用AWS CDK來實作持續整合和持續交付(CI/CD)。

ACM憑證的自動化驗證

在前一章中,我們手動驗證了網域名稱以取得ACM TLS憑證。然而,使用AWS CDK可以自動完成這項工作。以下程式碼展示瞭如何使用CDK來驗證網域名稱:

this.certificate = new Certificate(scope, 'Certificate', {
  domainName: domain_name,
  validation: CertificateValidation.fromDns(props.hosted_zone),
  subjectAlternativeNames: ['*.cdkbook.click'],
});

內容解密:

這段程式碼建立了一個ACM憑證,並使用DNS驗證來驗證網域名稱。其中,domainName指定了要驗證的網域名稱,validation指定了驗證方法,subjectAlternativeNames指定了其他需要驗證的網域名稱。

Glue程式碼

要將所有這些構件結合在一起,我們需要一些額外的程式碼。以下程式碼展示瞭如何初始化S3、RDS和ECS自定義構件:

this.s3 = new S3(this, 'S3', {
  acm: this.acm,
  route53: this.route53,
});
this.rds = new RDS(this, 'RDS', {
  vpc: this.vpc,
});
this.ecs = new ECS(this, 'ECS', {
  vpc: this.vpc,
  acm: this.acm,
  route53: this.route53,
});

內容解密:

這段程式碼初始化了S3、RDS和ECS自定義構件。其中,S3RDSECS是自定義構件,分別用於建立S3儲存桶、RDS資料函式庫和ECS叢集。這些構件需要傳遞相關引數,例如acmroute53vpc等。

VPC和子網的組態

在建立RDS資料函式庫和ECS叢集之前,我們需要建立一個VPC和相關的子網。以下程式碼展示瞭如何建立VPC和子網:

this.vpc = new Vpc(this, 'MyVPC', {
  subnetConfiguration: [
    {
      cidrMask: 24,
      name: 'ingress',
      subnetType: SubnetType.PUBLIC,
    },
    {
      cidrMask: 24,
      name: 'compute',
      subnetType: SubnetType.PRIVATE_WITH_NAT,
    },
    {
      cidrMask: 28,
      name: 'rds',
      subnetType: SubnetType.PRIVATE_ISOLATED,
    },
  ],
});

內容解密:

這段程式碼建立了一個VPC和三個子網。其中,subnetConfiguration指定了子網的組態,包括子網的型別、名稱和CIDR遮罩。這裡建立了一個公有子網、一個私有子網(帶有NAT閘道)和一個隔離子網(用於RDS資料函式庫)。

RDS資料函式庫的安全性

為了確保RDS資料函式庫的安全性,我們需要允許ECS叢集存取RDS資料函式庫。以下程式碼展示瞭如何允許ECS叢集存取RDS資料函式庫:

this.rds.instance.connections.allowFrom(this.ecs.cluster, Port.tcp(3306));

內容解密:

這段程式碼允許ECS叢集存取RDS資料函式庫。其中,allowFrom方法指定了允許存取RDS資料函式庫的來源,Port.tcp(3306)指定了允許存取的埠號。

CI/CD簡介

CI/CD是一種軟體開發實踐,旨在提高軟體開發的效率和品質。在本章中,我們將介紹如何使用AWS CDK來實作CI/CD。

使用AWS CodeBuild和CodePipeline實作CI/CD

AWS CodeBuild和CodePipeline是AWS提供的CI/CD工具。以下程式碼展示瞭如何使用CodeBuild和CodePipeline來實作CI/CD:

// CodeBuild和CodePipeline的組態

內容解密:

這段程式碼展示瞭如何使用CodeBuild和CodePipeline來實作CI/CD。其中,CodeBuild用於編譯和測試程式碼,CodePipeline用於自動化佈署流程。

持續交付與CDK驅動的應用程式

CI/CD簡介

在開始實作之前,我們需要花一些時間介紹CI/CD的概念,並解釋為什麼AWS的CI/CD工具集雖然不完美,卻最適合CDK專案。

什麼是持續整合(CI)?

簡單來說,CI是為修復錯誤和新增功能而在專案中建立不同分支的過程。一旦結果令人滿意,就可以將這些變更合併到主分支。所謂的滿意結果,是指程式碼經過審查和充分測試。

什麼是持續交付(CD)?

一旦CI過程完成,CD就會自動將這些變更佈署到開發、預發和生產環境。變更通常會在環境中傳播,一旦透過開發者的檢查和產品團隊在預發環境中的審查,就會被提升到下一個環境。這個提升過程因團隊而異。

AWS的CI/CD工具集

有多種相當先進的CI/CD工具集。就像程式語言和框架一樣,這些工具具有多種功能,可能滿足特定型別專案的需求。一些例子包括GitHub Actions、Travis和CircleCI。

技術需求

既然我們已經瞭解了CI/CD是什麼,以及AWS的CodeBuild和CodePipeline與其他產品的不同之處,讓我們開始為我們的TODO應用程式實作一個簡單而強壯的CI/CDPipeline。

技術需求

GitHub個人存取權杖

CodePipeline是一種需要從程式碼倉函式庫取得最新變更的CI/CD工具。AWS有自己的GitHub倉函式庫託管平台,名為CodeCommit。

為了避免每次推播程式碼到主倉函式庫時觸發每個人的CI/CDPipeline,請將本章的程式碼fork到您帳戶下的私有GitHub倉函式庫中。請記住,只有第5章的程式碼在這個fork的倉函式庫中。


### GitHub 倉函式庫 Fork 步驟
1. 點選 GitHub 個人頭像,然後點選 Settings。
2. 在左側選單中,點選 Developer settings。
3. 接下來,點選 Personal access tokens 並選擇 Fine-grained tokens。
4. 在右上角,點選 Generate new token 按鈕。
5. 填寫 token 名稱,例如 aws-cdk-book。
6. 將到期時間設為 30 天。
7. 在 Repository access 部分,選擇 Only select repositories,並從下拉清單中選擇剛剛 fork 的倉函式庫。
8. 在 Permissions 中,點選 Repository,並給予 CodeBuild 正確的存取許可權。
9. 從清單中選擇以下專案,並給予 CodeBuild 讀取和寫入存取許可權:Commit statuses、Metadata、Contents 和 Webhooks。
10. 點選 Generate token。
11. 在下一頁,您將收到一個以 github_pat_ 開頭的 token,後面跟著一些隨機的英數字元。複製它並妥善儲存。

Slack整合步驟

為了接收建置狀態的通知,我們需要一個Slack工作區。如果您目前沒有一個,或者無法更改您當前工作區的組態,請使用以下網址註冊並建立一個工作區:https://slack.com/get-started#/createnew。


### Slack 整合步驟
1. 建立一個工作區或使用具有必要管理存取權的工作區。
2. 點選左側的工作區名稱,進入 Settings & administration,然後進入 Manage apps。
3. 您將被重新導向到 Slack 網頁,在此您可以管理工作區的所有應用程式。在此頁面上,首先複製網址並提取其中的 ID,這是您的工作區 ID,請將其儲存在某處,例如記事本中,因為稍後您將需要它來整合Pipeline通知。
4. 在同一頁上,搜尋 AWS Chatbot。
5. 您將被重新導向到該應用程式的頁面。點選 Add to Slack。
6. 然後,您將被重新導向到 AWS Chatbot 網頁,在 AWS 中點選 Get started with AWS Chatbot 並登入您的帳戶,您將被重新導向到其控制檯儀錶板。
7. 對於 Chat client,選擇 Slack 並點選 Configure client。然後,您將被重新導向到 Slack 網頁,在此您需要確認此整合。

程式碼解析

以下是一個簡單的 CDK 程式碼範例,用於建立 CodePipeline:

import * as cdk from 'aws-cdk-lib';
import * as codepipeline from 'aws-cdk-lib/aws-codepipeline';
import * as codepipeline_actions from 'aws-cdk-lib/aws-codepipeline-actions';

export class CdkPipelineStack extends cdk.Stack {
  constructor(scope: cdk.Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);

    const sourceArtifact = new codepipeline.Artifact();
    const cloudAssemblyArtifact = new codepipeline.Artifact();

    const pipeline = new codepipeline.Pipeline(this, 'Pipeline', {
      pipelineName: 'MyCdkPipeline',
      stages: [
        {
          stageName: 'Source',
          actions: [
            new codepipeline_actions.GitHubSourceAction({
              actionName: 'GitHub',
              owner: 'your-github-username',
              repo: 'your-github-repo',
              oauthToken: cdk.SecretValue.secretsManager('your-github-token'),
              output: sourceArtifact,
            }),
          ],
        },
        {
          stageName: 'Build',
          actions: [
            new codepipeline_actions.CloudFormationCreateUpdateStackAction({
              actionName: 'CDKDeploy',
              stackName: 'MyCdkStack',
              adminPermissions: true,
              templatePath: cloudAssemblyArtifact.s3ObjectKey('MyCdkStack.template.json'),
            }),
          ],
        },
      ],
    });
  }
}

#### 內容解密:

上述程式碼建立了一個名為 MyCdkPipeline 的 CodePipeline,該Pipeline包含兩個階段:SourceBuild。在 Source 階段,使用 GitHubSourceAction 從指定的 GitHub 倉函式庫取得原始碼。在 Build 階段,使用 CloudFormationCreateUpdateStackAction 佈署 CDK 堆積疊。

圖表翻譯:

@startuml
skinparam backgroundColor #FEFEFE
skinparam defaultTextAlignment center
skinparam rectangleBackgroundColor #F5F5F5
skinparam rectangleBorderColor #333333
skinparam arrowColor #333333

title 圖表翻譯:

rectangle "Source Code" as node1
rectangle "Build" as node2
rectangle "Deploy" as node3

node1 --> node2
node2 --> node3

@enduml

此圖表呈現了從 GitHub 到 CodePipeline 再到 CloudFormation 最終佈署到 CDK 堆積疊的流程。

圖表翻譯: 上圖展示了一個 CI/CD Pipeline的流程,首先從 GitHub 取得原始碼,然後透過 CodePipeline 進行建置,最後使用 CloudFormation 將 CDK 堆積疊佈署到 AWS 環境中。