AWS CDK(TypeScript)を使用して CodePipeline を構築する

公開日 2025年4月27日
更新日 2025年4月27日
19 分で読める
AWS

マイクロサービスとコンテナ化の時代が到来し、AWS サービスを利用してエンドツーエンドの継続的インテグレーション/継続的デプロイ(CI/CD)パイプラインを構築することが一般的な要件となっています。本記事では AWS CDK(TypeScript)を例に、CodeCommit から CodeBuild、そして S3 へのアーティファクト公開までの CodePipeline をステップバイステップで構築する方法を解説します。

1. プロジェクト構成の概要

開始にあたり、AWS CDK をインストールし、TypeScript プロジェクトを初期化済みであるものとします。ディレクトリ構成の例は以下の通りです:

my-cdk-project/
├── bin/
│   └── my-cdk-project.ts       // CDK アプリケーションのエントリポイント
├── lib/
│   └── code-pipeline-stack.ts  // これから実装する Stack
├── build-spec.yaml             // CodeBuild 用ビルド仕様
├── package.json
└── tsconfig.json

2. コアの CDK コード

import * as cdk from 'aws-cdk-lib';
import { Duration } from 'aws-cdk-lib';
import * as codebuild from 'aws-cdk-lib/aws-codebuild';
import * as codecommit from 'aws-cdk-lib/aws-codecommit';
import * as codepipeline from 'aws-cdk-lib/aws-codepipeline';
import * as actions from 'aws-cdk-lib/aws-codepipeline-actions';
import * as iam from 'aws-cdk-lib/aws-iam';
import * as s3 from 'aws-cdk-lib/aws-s3';
import type { Construct } from 'constructs';

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

    // 1. 既存の S3 バケットをアーティファクトストレージとして参照
    const artifactBucket = s3.Bucket.fromBucketArn(this, 'ArtifactBucket', 'arn:aws:s3:::your-artifact-bucket');

    // 2. 既存の IAM ロールを参照し、Pipeline 実行権限を付与
    const pipelineRole = iam.Role.fromRoleArn(this, 'PipelineRole', 'arn:aws:iam::123456789012:role/CodePipelineRole', {
      mutable: false,
    });
    const eventBridgeRole = iam.Role.fromRoleArn(
      this,
      'EventBridgeRole',
      'arn:aws:iam::123456789012:role/EventBridgeRole',
      { mutable: false },
    );

    // 3. CodeCommit リポジトリを作成
    const repository = new codecommit.Repository(this, 'MyRepo', {
      repositoryName: 'my-app-repo',
    });

    // 4. CodeBuild プロジェクトを定義
    const buildProject = new codebuild.PipelineProject(this, 'BuildProject', {
      projectName: 'my-app-build',
      role: pipelineRole,
      queuedTimeout: Duration.hours(1),
      timeout: Duration.hours(1),
      buildSpec: codebuild.BuildSpec.fromSourceFilename('build-spec.yaml'),
      environment: {
        buildImage: codebuild.LinuxBuildImage.AMAZON_LINUX_2_5,
        computeType: codebuild.ComputeType.SMALL,
        privileged: true,
        environmentVariables: {
          ENV: {
            type: codebuild.BuildEnvironmentVariableType.PLAINTEXT,
            value: 'prod',
          },
        },
      },
    });

    // 5. Pipeline 用アーティファクトを定義
    const sourceArtifact = new codepipeline.Artifact('SourceArtifact');
    const buildArtifact = new codepipeline.Artifact('BuildArtifact');

    // 6. Source ステージを設定:CodeCommit の prod ブランチを監視
    const sourceAction = new actions.CodeCommitSourceAction({
      actionName: 'Fetch_Source',
      repository,
      branch: 'prod',
      output: sourceArtifact,
      role: pipelineRole,
      eventRole: eventBridgeRole,
      trigger: actions.CodeCommitTrigger.EVENTS,
      runOrder: 1,
    });

    // 7. Build ステージを設定:CodeBuild を呼び出し
    const buildAction = new actions.CodeBuildAction({
      actionName: 'Run_Build',
      project: buildProject,
      input: sourceArtifact,
      outputs: [buildArtifact],
      role: pipelineRole,
      runOrder: 2,
    });

    // 8. Pipeline を作成し、各ステージを追加
    const pipeline = new codepipeline.Pipeline(this, 'CodePipeline', {
      pipelineName: 'MyAppPipeline',
      artifactBucket,
      role: pipelineRole,
    });
    pipeline.addStage({ stageName: 'Source', actions: [sourceAction] });
    pipeline.addStage({ stageName: 'Build', actions: [buildAction] });
  }
}

3. サンプル build-spec.yaml

version: 0.2

phases:
  install:
    runtime-versions:
      nodejs: 22
  pre_build:
    commands:
      - npm run lint
      - npm run test
  build:
    commands:
      - npm ci
      - npm run build
      - npx cdk deploy <StackName> --require-approval never

4. クロスアカウント CodePipeline

CDK で別の AWS アカウント(以下、Account A)にある CodeCommit リポジトリを利用し、自アカウント(Account B)で CodePipeline を実行する手順は以下の通りです。

4.1. Account A でクロスアカウントアクセス用ロールを作成

  • Account A の IAM コンソールで新規ロール(例:cross-account-access-role)を作成
  • 信頼ポリシーに Account B のルートアカウントまたは Pipeline サービスロールによる sts:AssumeRole を許可
{
  "Version": "2012-10-17",
  "Statement": [
    {
      "Effect": "Allow",
      "Principal": { "AWS": "arn:aws:iam::ACCOUNT_B_ID:root" },
      "Action": "sts:AssumeRole"
    }
  ]
}

4.2. リポジトリ読み取り用権限をロールに付与

  • AWS 管理ポリシー AWSCodeCommitReadOnly
  • KMS 暗号化を利用する場合は kms:Decryptkms:GenerateDataKey* などの許可を付与し、CMK のキーポリシーにもロール使用を許可

4.3. Account B で外部リソースをインポート

// Account A の CodeCommit リポジトリをインポート
const externalRepo = codecommit.Repository.fromRepositoryArn(
  this,
  'ExternalRepo',
  'arn:aws:codecommit:ap-northeast-1:ACCOUNT_A_ID:MySharedDemoRepo',
);

// Account A のクロスアカウントアクセスロールをインポート
const crossAccountRole = iam.Role.fromRoleArn(
  this,
  'CrossAccountRole',
  'arn:aws:iam::ACCOUNT_A_ID:role/cross-account-access-role',
);

4.4. Source アクションにクロスアカウントロールを設定

const sourceArtifact = new codepipeline.Artifact('SourceArtifact');

const crossAccountSource = new codepipeline_actions.CodeCommitSourceAction({
  actionName: 'CrossAccount_Source',
  repository: externalRepo,
  branch: 'main',
  output: sourceArtifact,
  role: crossAccountRole,
  trigger: codepipeline_actions.CodeCommitTrigger.EVENTS,
});

pipeline.addStage({
  stageName: 'Source',
  actions: [crossAccountSource],
});

これにより、CodePipeline は Account A で作成したロールの権限でリポジトリからコードを取得します。


5. GitHub をリポジトリとして使用する場合

CodePipeline は GitHub のリポジトリからもコードを取得可能です。

5.1. GitHub 側で Personal Access Token を作成

  • GitHub にログイン → 右上のアバター → Settings → Developer settings → Personal access tokens → Fine-grained personal access tokens → Generate new token
  • 少なくとも repo(プライベートリポジトリ読み取り)または public_repo(公開リポジトリ読み取り)の権限を選択し、トークンを生成してコピー

5.2. AWS Secrets Manager にトークンを保存

aws secretsmanager create-secret \
  --name my-github-token \
  --description "GitHub OAuth token for CodePipeline" \
  --secret-string "<YOUR_TOKEN_HERE>"

5.3. CDK で Secret を参照し、GitHubSourceAction を設定

import * as cdk from 'aws-cdk-lib';
import * as codebuild from 'aws-cdk-lib/aws-codebuild';
import * as codecommit from 'aws-cdk-lib/aws-codecommit';
import * as codepipeline from 'aws-cdk-lib/aws-codepipeline';
import * as codepipeline_actions from 'aws-cdk-lib/aws-codepipeline-actions';
import * as iam from 'aws-cdk-lib/aws-iam';
import * as s3 from 'aws-cdk-lib/aws-s3';
import type { Construct } from 'constructs';

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

    // ... 前段の設定 ...

    const oauthToken = cdk.SecretValue.secretsManager('my-github-token');

    // GitHubSourceAction を設定
    const githubSource = new codepipeline_actions.GitHubSourceAction({
      actionName: 'Checkout_From_GitHub',
      owner: 'あなたの GitHub ユーザー名または組織名',
      repo: 'あなたのリポジトリ名',
      branch: 'main', // 追跡したいブランチ
      oauthToken: oauthToken, // Secrets Manager から読み込んだトークン
      output: sourceOutput,
      trigger: codepipeline_actions.GitHubTrigger.WEBHOOK, // Webhook でリアルタイムにトリガー
    });

    // Source ステージに追加
    pipeline.addStage({
      stageName: 'Source',
      actions: [githubSource],
    });
  }
}

6. まとめ

本記事では AWS CDK(TypeScript)を用いて以下を実現する方法を紹介しました。

  1. CodeCommit → CodeBuild を基本とするパイプラインの構築
  2. クロスアカウントで CodeCommit リポジトリを取得する方法
  3. GitHub リポジトリからのコード取得とビルドの自動トリガー

この基盤の上に、テストステージの追加や Elastic Beanstalk、ECS、Lambda へのデプロイなど、より多彩な Stage を組み込むことで、堅牢かつ効率的な CI/CD ワークフローを構築できます。

概要

技術的洞察、経験、思考を共有する個人ブログ

クイックリンク

お問い合わせ

  • Email: hushukang_blog@proton.me
  • GitHub

© 2025 CODE赤兎. 無断転載禁止