見出し画像

AWS CDKでCodeCommitのGitタグをトリガーにしたCodePipelineを構築する方法



はじめに


こんにちは、SHIFT DAAE(ダーエ)テクノロジーグループの千田です。
今回はAWS CDKを使って、CodeCommitのGitタグをトリガーにしたCodePipelineを構築する方法をご紹介します。

CodePipelineでは指定したブランチの変更がデフォルトのトリガーになります。
通常、Pull Requestのマージがトリガーになることが多いですが、マージのタイミングとデプロイしたいタイミングが異なることがあります。また、デプロイのタイミング(とくにリリースタイミング)ではGitタグを作成しますよね。

そこでGitタグをトリガーにすることで、特定のリリースやバージョンを明確に識別できるようになります。これにより、リリース管理が簡素化され、特定のバージョンに対するデプロイが容易になります。
また、CodePipelineのV2ではGitタグのトリガーがサポートされていますが、CodeCommitは対象外となっているため、EventBridgeを使って自分で設定する必要があります。
(参考:AWS CodePipeline で git タグでのトリガーのサポートを開始

前提条件

このブログは、AWS CDKを使ったことがあり、CodePipelineの設定に興味がある方を対象としています。
CDK環境のセットアップは省略しますので、公式ドキュメント を参照してください。

使用環境

今回使用する環境は以下の通りです。

  • Node.js: 20

  • TypeScript: 5.4.5

  • AWS CDK: 2.146.0

CDK Pipeline


CodeBuildはビルドとS3バケットへのデプロイを行う想定にしています。CDKで作成するリソースは以下のとおりです。

  • S3

    • バケットの新規作成

    • ライフサイクルルールの設定

  • CodeBuild

    • ビルドプロジェクトの作成

    • ビルドログの保持期間設定(CloudWatch Logs)

    • サービスロールへのIAMポリシー追加

  • CodePipeline

    • パイプラインの作成

    • PREFIX(v)がついたGitタグのプッシュをトリガーに設定(EventBridge)

S3アーティファクトバケットの作成

まずは、ソースコードやビルド成果物を受け渡すためのアーティファクトバケットを作成方法を説明します。

以下のようにautoDeleteObjectremovalPolicyの設定を行うことで、スタック削除時にバケットが自動的に空にされ、削除されるようになります。
また、オブジェクトが3日間で削除されるようにライフサイクルルールも設定します。

    const artifactBucket = new s3.Bucket(this, "PipelineArtifactBucket", {
      bucketName: "bucket-name",
      autoDeleteObjects: true,
      removalPolicy: cdk.RemovalPolicy.DESTROY,
      lifecycleRules: [
        {
          id: "expire-after-3-days",
          expiration: cdk.Duration.days(3),
        },
      ],
    });

CodeBuildプロジェクトの作成

次に、CodeBuildプロジェクトの作成方法を説明します。

CloudWatch Logsに出力されるビルドログを3日間保持するように設定しています。
CDKでCodeBuildのプロジェクトを作成するとデフォルトでCodeBuildのサービスロールが作成されますが、ビルド時のコマンドによっては権限が不足する場合があります。
今回はs3 syncを使うことを想定して、S3のFullAccessを追加しています。

    const project = new codebuild.PipelineProject(this, "MyProject", {
      projectName: "project-name",
      environment: {
        buildImage: codebuild.LinuxBuildImage.AMAZON_LINUX_2_5,
        computeType: codebuild.ComputeType.SMALL,
      },
      // ログ保持期間の設定
      logging: {
        cloudWatch: {
          logGroup: new logs.LogGroup(this, "LogGroup", {
            retention: logs.RetentionDays.THREE_DAYS,
            removalPolicy: cdk.RemovalPolicy.DESTROY,
          }),
        },
      },
    });
    // CodeBuildのサービスロールに必要なIAMポリシーを追加
    project.addToRolePolicy(
      new iam.PolicyStatement({
        actions: ["s3:*"],
        resources: ["*"],
      })
    );

CodePipelineのトリガーをGitタグに設定

今回のメインである、CodePipelineのトリガーをGitタグにする方法を説明します。

CodePipelineでソースアクションをCodeCommitに指定すると、デフォルトでブランチの変更をトリガーとしたイベントが作成されるため、別でイベントを作成してしまうとデフォルトのものと2つ作成されてしまいます。
そのため、customEventRuleを使ってデフォルトのイベントをGitタグがトリガーになるよう変更します。

トリガーになるGitタグはセマンティックバージョン(例: v1.0.0)で作成することを想定したprefixを設定しています。
ワイルドカード(*)は無効なのでprefixの文字列のみを設定します。

Gitタグがトリガーになるのでbranchの設定はあまり関係ないですが、パイプライン作成時の初回実行やコンソール上からの実行で参照されます。
基本的にはGitタグを作成するブランチを設定しておくのが無難だと思います。

    const sourceAction = new codepipeline_actions.CodeCommitSourceAction({
      actionName: "Source",
      repository,
      output: sourceOutput,
      branch: "main",
      // プレフィックスのついたGitタグをパイプラインのトリガーに設定
      customEventRule: {
        eventPattern: {
          source: ["aws.codecommit"],
          detailType: ["CodeCommit Repository State Change"],
          detail: {
            event: ["referenceCreated", "referenceUpdated"],
            referenceType: ["tag"],
            referenceName: [
              {
                prefix: "v",
              },
            ],
          },
        },
        target: new events_targets.CodePipeline(pipeline),
      },
    });

ソースコード全体

スタック部分のソースコード全体は以下のとおりです。

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 events_targets from "aws-cdk-lib/aws-events-targets";
import * as iam from "aws-cdk-lib/aws-iam";
import * as logs from "aws-cdk-lib/aws-logs";
import * as s3 from "aws-cdk-lib/aws-s3";
import { Construct } from "constructs";

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

    // アーティファクトバケットとライフサイクルルールの作成
    const artifactBucket = new s3.Bucket(this, "PipelineArtifactBucket", {
      bucketName: "bucket-name",
      autoDeleteObjects: true,
      removalPolicy: cdk.RemovalPolicy.DESTROY,
      lifecycleRules: [
        {
          id: "expire-after-3-days",
          expiration: cdk.Duration.days(3),
        },
      ],
    });

    // CodeCommit リポジトリの取得
    const repository = codecommit.Repository.fromRepositoryName(
      this,
      "Repository",
      "repository-name"
    );

    // CodeBuild ビルドプロジェクトの作成
    const project = new codebuild.PipelineProject(this, "MyProject", {
      projectName: "project-name",
      environment: {
        buildImage: codebuild.LinuxBuildImage.AMAZON_LINUX_2_5,
        computeType: codebuild.ComputeType.SMALL,
      },
      // ログ保持期間の設定
      logging: {
        cloudWatch: {
          logGroup: new logs.LogGroup(this, "LogGroup", {
            retention: logs.RetentionDays.THREE_DAYS,
            removalPolicy: cdk.RemovalPolicy.DESTROY,
          }),
        },
      },
    });
    // CodeBuildのサービスロールに必要なIAMポリシーを追加
    project.addToRolePolicy(
      new iam.PolicyStatement({
        actions: ["s3:*"],
        resources: ["*"],
      })
    );

    // CodePipeline パイプラインの作成
    const pipeline = new codepipeline.Pipeline(this, "Pipeline", {
      pipelineName: "pipeline-name",
      artifactBucket,
      pipelineType: codepipeline.PipelineType.V2,
    });

    // ソースステージの追加
    const sourceOutput = new codepipeline.Artifact("SourceOutput");
    const sourceAction = new codepipeline_actions.CodeCommitSourceAction({
      actionName: "Source",
      repository,
      output: sourceOutput,
      branch: "main",
      // プレフィックスのついたGitタグをパイプラインのトリガーに設定
      customEventRule: {
        eventPattern: {
          source: ["aws.codecommit"],
          detailType: ["CodeCommit Repository State Change"],
          detail: {
            event: ["referenceCreated", "referenceUpdated"],
            referenceType: ["tag"],
            referenceName: [
              {
                prefix: "v",
              },
            ],
          },
        },
        target: new events_targets.CodePipeline(pipeline),
      },
    });
    pipeline.addStage({
      stageName: "Source",
      actions: [sourceAction],
    });

    // ビルドステージの追加
    const buildOutput = new codepipeline.Artifact("BuildOutput");
    const buildAction = new codepipeline_actions.CodeBuildAction({
      actionName: "Build",
      project,
      input: sourceOutput,
      outputs: [buildOutput],
    });
    pipeline.addStage({
      stageName: "Build",
      actions: [buildAction],
    });
  }
}

おわりに


以上が、AWS CDKを使ってCodeCommitのGitタグをトリガーにしたCodePipelineを構築する方法です。

最後まで読んでいただき、ありがとうございました。
この記事が皆さんの参考になれば幸いです。

\もっと身近にもっとリアルに!DAAE公式X/​


執筆者プロフィール: Chida Akihiro
DAAE所属のエンジニアです。最近昇降式のテーブルを使い始めました。

お問合せはお気軽に
https://service.shiftinc.jp/contact/

SHIFTについて(コーポレートサイト)
https://www.shiftinc.jp/

SHIFTのサービスについて(サービスサイト)
https://service.shiftinc.jp/

SHIFTの導入事例
https://service.shiftinc.jp/case/

お役立ち資料はこちら
https://service.shiftinc.jp/resources/

SHIFTの採用情報はこちら
https://recruit.shiftinc.jp/career/

PHOTO:UnsplashAndras Vas