AWS CDK Pipelinesを構築してみよう!

technologies

おはようございます!ベンジャミンの木村です!

今日はAWS CDKのCICD環境を構築するべく、CDK Pipelinesを構築したので、その方法について記載しようと思います。

目次

AWS CDK Pipelinesとは?

CDK Pipelinesは、AWS Cloud Development Kit (AWS CDK) の継続的デリバリー(CICD)を行うためのものです。CDK Pipelinesを構築することで、GitHubなどソース管理ツールにコードがPushされると自動的にスタックを再構成することが可能になります。

フォルダ構成

今回はCDK PipelinesでS3バケットを作成するような内容になります。それぞれのファイルの内容についてはこの後説明させていただきます。

.
├── README.md
├── bin
│   └── main.ts (エントリポイント用ファイル)
├── lib
│   └── stacks
│       ├── pipeline-stack.ts (CDK Pipeline用ファイル)
│       ├── pipeline-stage.ts (CDK Pipelineに読み取らせるStage用ファイル)
│       └── storage-stack.ts (S3バケットを作成するスタック用ファイル)
・・・

バージョン

  • AWS CDK :2.159.1
    ※AWS CDKはバージョン2以上でお願いいたします
  • Node:v18.18.2
  • npm:9.8.1

1. GitHubのアクセストークンを発行する

1-1. GitHubアカウントにログインし、右ペインの「Settings」をクリックする

1-2. 左ペインの「Developer settings」をクリックする

1-3. 左ペインの「Tokens (classic)」 →「Generate new token」→「Generate new token(classic)」を順にクリックする

1-4. 下記の通りに値を入力して、「Generate token」をクリックする

  • Note:任意の名前を入力する
  • Expiration:任意のトークン期限を選択する
  • serect scopes:「repo」にチェックを入れる

1-5. 表示されたトークンを控える

2. Secrets ManagerにGitHubのトークンを登録する

2-1. 下記URLよりSecrets Managerのコンソール画面へ移動する

https://ap-northeast-1.console.aws.amazon.com/secretsmanager/listsecrets?region=ap-northeast-1

2-2. 「新しいシークレットを保存する」をクリックする

2-3. 下記の通り値を入力し、「次」ボタンをクリックする

  • シークレットのタイプ:その他のシークレットタイプ
  • キー/値
    • キー:任意の名前
    • 値:項番1-5で控えたトークン

2-4. 任意のシークレット名を入力して、「次」ボタンをクリックする

2-5. 何も入力せずに「次」ボタンをクリックする

2-6. 設定値を確認して「保存」ボタンをクリックし、完了

3. CDK Pipelinesを構築する

3-1. AWS CDKの初期構築

※AWS CDKを利用するには、Node.jsとnpmが必要です。Node.jsのインストールがまだの場合、Node.js公式サイトからインストールしてください。(本記事作成時はNode v18.18.2、npm 9.8.1で実施しています。)

それでは下記手順を実行し、AWS CDKの初期構築を行ってください。

3-1-1. AWS CDKのインストール

npm install -g aws-cdk

3-1-2 AWS CDKのバージョン確認

cdk --version

3-1-3. 新しいCDKプロジェクトの作成

cdk init app --language typescript

3-1-4. 必要な依存パッケージのインストール
※用途に応じて必要なものをインストールしてください

npm install @aws-cdk/pipelines @aws-cdk/aws-secretsmanager @aws-cdk/aws-s3

※今回はCodePipeline , SecretsManager , S3の3サービスを利用するため3つのパッケージをインストールしています。

3-1-5. bin配下のファイル名を変更する

構成を揃えるため、bin配下のファイルをmain.tsにしましょう。

mv ./bin/<bin配下のファイル>.ts ./bin/main.ts

3-1-6. cdk.json を修正する

項番3-1-5でファイル名を変更した通りに、cdk.jsonの記載も下記の通りに変更します。

変更前

"app": "npx ts-node --prefer-ts-exts bin/<bin配下のファイル>.ts",

変更後

"app": "npx ts-node --prefer-ts-exts bin/main.ts",

3-1-7. aws configureを実行する

下記コマンドを実行し、ローカル環境からAWS CDKを実行するアカウントとの接続を行っておきましょう。

※事前にIAMのアクセスキーの作成が必要です。

aws configure

3-1-8. GitHubリポジトリの準備

GitHubリポジトリを作成し、ここまでの初期コードをpushしておいてください。作成せずに進めるとこの後の操作で、エラーとなる箇所がございます。

3-2. Pipelineスタックを記述する

次にエディタに移動し、下記コードをpipeline-stack.ts に記載します。

※緑文字のところは下記の通り値を入力してください。

  • <Secrets Managerの名前>:項番2-5で入力したSecrets Managerの名前を記載する
  • <GitHubリポジトリのOwrner>/<GitHubリポジトリ>:リポジトリを作った時に左上に表記されるリポジトリの作成者とそのリポジトリ名を記載する
    • ※GitHubのリポジトリはcdk deployを実行する前に作ってください、リポジトリがない状態でPipelineを作ろうとするとエラーとなります。
  • <ブランチ>:コードをpushするブランチ
    • ※こちらもGitHubのブランチはcdk deployを実行する前に作ってください。
  • <CDK Pipelinesの名前>:任意の名前を記載する
  • <Secrets Managerに登録したキー名>:項番2-3でSecrets Managerに記載したトークンのキーを記載する
// lib/stacks/pipeline-stack.ts
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import { CodePipeline, CodePipelineSource, ShellStep } from 'aws-cdk-lib/pipelines';
import * as secretsmanager from 'aws-cdk-lib/aws-secretsmanager';

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

    // Secrets ManagerからGitHubトークンを取得
    const githubToken = secretsmanager.Secret.fromSecretNameV2(this, 'GitHubToken', '<Secrets Managerの名前>');
    // GitHubリポジトリ情報
    const repo = '<GitHubリポジトリのOwrner>/<GitHubリポジトリ>';
    const branch = '<ブランチ>';

    const pipeline = new CodePipeline(this, 'Pipeline', {   ・・・★
      pipelineName: '<CDK Pipelinesの名前>',
      synth: new ShellStep('Synth', {
        input: CodePipelineSource.gitHub(repo, branch, {
          authentication: githubToken.secretValueFromJson('<Secrets Managerに登録したキー名>'),
        }),
        commands: ['npm ci', 'npm run build', 'npx cdk synth']
      })
    });
  }
}

の説明は下記に記載させていただきます。

  • CodePipeline コンストラクトを使ってのpipeline定義部分について
    • pipelineName: パイプラインの名前を指定します。
    • synth: パイプラインの合成(synthesis)ステップを定義します。これは、CDKアプリケーションを構築してCloudFormationテンプレートを生成するステップです。
      • ShellStep の設定
        • input: パイプラインのソースとしてGitHubリポジトリを指定します。
          • CodePipelineSource.gitHub: GitHubのリポジトリからソースを取得する設定を行います。
          • authentication: GitHub APIにアクセスするための認証情報(シークレット)を指定します。secretValueFromJson メソッドを使用して、シークレットマネージャに登録されているキー名からGitHubトークンを取得します。
        • commands: パイプライン内で実行されるコマンドのリストです。
          • ‘npm ci’: 依存パッケージのインストールを行います。
          • ‘npm run build’: プロジェクトをビルドします。
          • ‘npx cdk synth’: CDKアプリケーションを合成してCloudFormationテンプレートを生成します。

3-3. エントリポイント(main.ts)にCDK Pipelinesのスタックを定義する

エントリポイントとは、CDKの実行を開始する場所です。

ここにスタックを定義する記述を書くことで、cdk deployコマンドを実行したときに、CDKの記述がCloudFormationテンプレートとして読み取られ、デプロイすることが可能となります。

// bin/main.ts
import 'source-map-support/register';
import * as cdk from 'aws-cdk-lib';

import { PipelineStack } from '../lib/stacks/pipeline-stack';

const app = new cdk.App();
const pipelineStack = new PipelineStack(app, 'PipelineStack', {
  env: {
    account: process.env.CDK_DEFAULT_ACCOUNT, 
    region: process.env.CDK_DEFAULT_REGION,
  }
});

app.synth();

※CDK_DEFAULT_ACCOUNT、CDK_DEFAULT_REGIONはAWSからデフォルトで提供される環境変数でデプロイ時に自動で値が入ります。

※stackのid名(’PipelineStack’)は項番3-2のextends cdk.Stack されるclass 名(PipelineStack)と同じにしないとエラーとなります。

3-4. CDK Pipelinesをデプロイする

下記コマンドを実行し、cdk pipelinesをデプロイする

3-4-1. cdk Bootstrapを実行する

cdk bootstrap

3-4-2. cdk deployを実行する

cdk deploy --all --require-approval never
  • –all:スタックを全てデプロイするオプション
  • -require-approval never:Yes/Noを聞かないようにするオプション

デプロイが成功すると下記のようにCodePipelineが構築される

※この状態では空のCDK Pipelinesが構築されたに過ぎません。この後のStageへのスタック登録によって、CDK Pipelinesから、スタックのデプロイができるようになります。

4. Stageを作成し、CDK Pipelinesに登録する

次にCDK PipelinesでデプロイするスタックをStageに登録していきます。先ほども述べたように現段階ではCDK Pipelinesは空のPipelineになり、何もデプロイしません。

Stageを作成し、それをCDK Pipelinesに登録することで、CDK Pipelinesからデプロイすることが可能です。

4-1. デプロイするスタックの作成(今回はS3を作成します)

// lib/stacks/storage-stack.ts
import * as cdk from 'aws-cdk-lib';
import * as s3 from 'aws-cdk-lib/aws-s3';
import { Construct } from 'constructs';

export class StorageStack extends cdk.Stack {
  public readonly testBucket: s3.Bucket;
  
  constructor(scope: Construct, id: string, props?: cdk.StackProps) {
    super(scope, id, props);
    // test bucket
    this.testBucket = new s3.Bucket(this, 'ArtifactBucket', {
      bucketName: "dev-bjm-test-cdk-bucket",
      versioned: true,
      encryption: s3.BucketEncryption.S3_MANAGED,
      removalPolicy: cdk.RemovalPolicy.DESTROY,
      autoDeleteObjects: true, 
    });
  }
}

コードの内容は下記にて説明させていただきます。

  • bucketName: “dev-bjm-test-cdk-bucket”:
    • バケットの名前を指定しています。
  • versioned: true:
    • バケットのバージョニングを有効にします。
  • encryption: s3.BucketEncryption.S3_MANAGED:
    • S3が管理する暗号化 (S3 Managed Keys) を使ってバケット内のオブジェクトを暗号化します。
  • removalPolicy: cdk.RemovalPolicy.DESTROY:
    • スタック削除時にバケットを削除する設定です。
  • autoDeleteObjects: true:
    • バケット削除時にバケット内のオブジェクトも自動的に削除します。

4-2. Stageの作成

先ほど作成したStorageスタックを、Stageに登録する記述を行います。

下記、緑色でハイライトしている部分がStorageスタックをデプロイするときの記載になります。cdk deployのコマンドでデプロイするときは、同じインスタンス化の記述をエントリポイント(bin/main.ts)に記述すれば、コマンドでデプロイが可能です。

// lib/stacks/pipeline-stage.ts
import { Stage, StageProps } from 'aws-cdk-lib';
import { Construct } from 'constructs';
import { StorageStack } from './storage-stack';

export class PipelineStage extends Stage {
  constructor(scope: Construct, id: string, props?: StageProps) {
    super(scope, id, props);
    const storageStack = new StorageStack(this, 'StorageStack',{
      env: { 
        region: process.env.CDK_DEFAULT_REGION 
      },
    });
  }
}

※他のスタックをCDK Pipelinesでデプロイするときは、上記と同様にPipelineStage内でスタックをインスタンス化してください。

4-3. CDK PipelinesでStageを登録する

下記緑色にハイライトした記述をpipeline-stack.tsに追加してください。

// lib/stacks/pipeline-stack.ts
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import { CodePipeline, CodePipelineSource, ShellStep } from 'aws-cdk-lib/pipelines';
import * as secretsmanager from 'aws-cdk-lib/aws-secretsmanager';
import { PipelineStage } from './pipeline-stage'; //追記箇所

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

    // Secrets ManagerからGitHubトークンを取得
    const githubToken = secretsmanager.Secret.fromSecretNameV2(this, 'GitHubToken', '<Secrets Managerの名前>');
    // GitHubリポジトリ情報
    const repo = '<GitHubリポジトリのOwrner>/<GitHubリポジトリ>';
    const branch = '<ブランチ>';

    const pipeline = new CodePipeline(this, 'Pipeline', {
      pipelineName: '<CDK Pipelinesの名前>',
      synth: new ShellStep('Synth', {
        input: CodePipelineSource.gitHub(repo, branch, {
          authentication: githubToken.secretValueFromJson('<Secrets Managerに登録したキー名>'),
        }),
        commands: ['npm ci', 'npm run build', 'npx cdk synth']
      })
    });

    const deploy = new PipelineStage(this, "Deploy"); //追記箇所
    const deployStage = pipeline.addStage(deploy); //追記箇所
  }
}

4-4. GitHubにコードをpushする

いつもGitHubにpushするコマンドを実行し、GitHubにコードを上げてください。コマンドの例は下記にて記載いたします。

git init
git add -A
git commit -m "<コメント>"
git remote add origin <リモートURL>
git push -u origin <branch>

4-5. CodePipelineを確認する

下記URLをクリックし、CodePipelineのコンソールに移動します。

https://ap-northeast-1.console.aws.amazon.com/codesuite/codepipeline/pipelines?region=ap-northeast-1

作成したCDK Pipelinesを確認するとパイプラインが動いていると思います。しばらく待ち、Deployまで緑色になれば、Deployは成功となります。

4-6. 作成物の確認

まず、CloudFormationのスタックを確認します。

無事定義したStorageスタックが作成されていることが確認できればOKです。

また、今回はS3を作成する記述を書いたので、次にS3バケットを確認します。

下記のように目的のリソースが作成されていれば全て完了です。

まとめ

いかがでしたでしょうか?

今回はCDK Pipelinesを構築する記事を記載しました。

CDK Pipelinesを使うことで、下記のようなことがができるようになります。

  • デプロイしたリソースの追加設定/設定の修正が楽になる
  • 他のリソースを追加するときのデプロイが楽になる
  • AWSサポートに不明点を確認できる
  • クロスアカウントやリージョンをまたぐデプロイの設定可能になる
  • 開発、検証、本番のような環境の複製が楽になる

cdk deployでコマンド打ってデプロイするより色々と利点があるので、この記事で一度CDK Pipelinesの構築して、試していただけますと幸いです!

Related posts