CDK PipelineのソースにGitHubを接続してみた(CodeConnections編)
あしざわです。
CDK Pipeline のソースにGitHub リポジトリを設定する機会がありました。
GitHub との接続方法は以下の2種類あります。
- GitHub アクセストークンを利用したOAuth 認証
- AWS Connector for GitHub を経由したCodeConnections による接続
前者はトークンの管理が必要になるため、今回のケースでは後者を選びました。
このブログでは、CDK Pipelines のソースにGitHub リポジトリを設定する流れを順を追って紹介します。
CDKについてはそこまで深く触れないので、CDK をある程度触れたことがある人向けの説明となっています、ご了承ください。
概要
CDK Pipelines は、CDK アプリケーションの継続的デリバリーを簡単にデプロイできるコンストラクトライブラリです。
CloudFormation を使用してCDK アプリケーションの複数のコピーを最小限の労力でデプロイするために設計されています。アプリケーションステージを定義し、パイプラインにステージを追加するだけで、テスト環境や本番環境など、複数の環境へのデプロイを自動化できます。パイプラインは自己変異するため、ソースコードに変更を加えると、パイプライン自体が自動的に再構成され、新しいステージやスタックをデプロイします。
続いて、今回GitHub との接続のために利用するAWS CodeConnections について説明します。
AWS CodeConnections はGitHub, GitLab などのサードパーティのGit ベースのソースプロバイダーと統合し、AWS Code Pipelineなどと接続してソースコードをビルド・テスト・デプロイできるようにするサービスです。
このサービスは以前はAWS CodeStar Connection と呼ばれていました。CI/CD環境をまとめて作成・管理できるサービスであるAWS CodeStarの名を冠したサービス(ただし実体としては別物)でしたが、AWS CodeStar のサービス終了と合わせて名称変更されました。
やってみた
検証の流れはこちらです:
- CodeConnections 接続の作成
- 初回の手動デプロイ
- 自動デプロイのテスト
最初にCodeConnections 接続を作成し、AWS Connector for GitHub を使ってAWSアカウントとGitHubリポジトリを接続します。
続いて、CDKコードを手動で作成・デプロイします。最後にソースリポジトリへのPushすることで自動デプロイが動作するかをチェックして終わりです。
なお、以下については手順に含めていません。事前に準備しておいてください。
- ソースとなるGitHubのアカウントの準備
- GitHub リポジトリの作成
CodeConnections 接続の作成
はじめに、AWSマネジメントコンソールからCodeConnections 接続を作成します。
CodeConnections は個別のマネジメントコンソールを持っておらず、Code Pipeline コンソールの設定 > 接続
からリソースを作成します。
プロバイダーと任意の接続名を入力してください。プロバイダーはGitHub を選択しています。他のプロバイダーを利用している場合は他を選択してください。
AWS Connector for GitHub の画面が表示されます。接続したいGitHubリポジトリへの権限を持つGitHub ユーザーを選択しましょう。
新しいアプリをインストールする
をクリックしてAWS Connector for GitHub の設定を進めていきます。既に接続がある場合は虫眼鏡ボタンから既存の接続を選ぶことも可能でした。
再度、AWS Connector for GitHub の画面が出るので、先ほどと同じユーザーを選択します。画面は同じなので割愛します。
AWS Connector for GitHub をインストールするGitHub Organizations を選択します。複数のOrganizationsに所属している場合は複数表示されます。
既にAWS Connector for GitHub の設定がある場合はConfigure と表示されるようです
AWS Connector for GitHub の設定をここで実施します。
選択できるのはリポジトリのアクセス範囲で、全てのリポジトリ(All repositories)
か特定のリポジトリ(Only select repositories)
から選びました。今回の検証では1つのリポジトリのみを選べば良かったため、後者を選択しています。
設定後、忘れずにSaveをクリックすれば、元の画面に戻ります。
GitHubアプリ欄に文字列が入力されていますが特に触れず、接続をクリックします。
接続が完了すると、ステータスが利用可能となった接続設定の画面に移動します。
ここで接続のARNをメモしておきます(後で利用します)
CodeConnections 接続の設定はこれで完了です。
初回の手動デプロイ
続いて、CDKのコード作成とデプロイを行います。
検証で使っているCDK のバージョンはこちらです。
> cdk --version
2.1001.0 (build 130445d)
その他利用しているライブラリのバージョンはこちらです。
package.json
{
"name": "cdk-pipelines-test",
"version": "0.1.0",
"bin": {
"cdk-pipelines-test": "bin/cdk-pipelines-test.js"
},
"scripts": {
"build": "tsc",
"watch": "tsc -w",
"test": "jest",
"cdk": "cdk"
},
"devDependencies": {
"@types/jest": "^29.5.14",
"@types/node": "22.7.9",
"jest": "^29.7.0",
"ts-jest": "^29.2.5",
"aws-cdk": "2.1001.0",
"ts-node": "^10.9.2",
"typescript": "~5.6.3"
},
"dependencies": {
"aws-cdk-lib": "2.180.0",
"constructs": "^10.0.0"
}
}
主に作成したコードは以下の4つです。 ※cdk init
すると生成されるその他のコードは割愛します
bin/base.ts
#!/usr/bin/env node
import * as cdk from 'aws-cdk-lib';
import { CdkPipelinesStack } from '../lib/pipeline-stack';
const app = new cdk.App();
new CdkPipelinesStack(app, 'CdkPipelinesStack', {env:{region: 'ap-northeast-1'}});
エントリーポイントの役割をするコードです。
ここではパイプラインのみを作成します。
lib/pipeline-stack.ts
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import { CodePipeline, CodePipelineSource, ShellStep } from 'aws-cdk-lib/pipelines';
import { PipelineStage } from "../lib/pipeline-stage"
export class CdkPipelinesStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
// GitHubリポジトリ情報
const repo = '<GitHubユーザー名>/<GitHubリポジトリ名>';
const branch = '<ターゲットブランチ名>';
const pipeline = new CodePipeline(this, 'Pipeline', {
synth: new ShellStep('Synth', {
input: CodePipelineSource.connection(repo, branch, {
connectionArn:
// 事前にコンソールで作成した、CodeConnectionsのARN
'<CodeConnectionsのARN>',
}
),
commands: ['npm ci', 'npm run build', 'npx cdk synth'],
}),
});
// デプロイ
const deploy = new PipelineStage(this, "Deploy");
pipeline.addStage(deploy);
}
}
パイプラインの定義をここで行います。
GitHubリポジトリ・ターゲットブランチに関する情報を入力したり、事前作成したCodeConnections接続のARNの入力が必要になります。
パイプライン以外のリソースのデプロイは一番下の箇所です。デプロイするリソースの詳細はlib/pipeline-stage.ts
で定義しています。
lib/pipeline-stage.ts
import { Construct } from 'constructs';
import { Stage, StageProps } from 'aws-cdk-lib';
import { S3Stack } from '../lib/s3-stack';
export class PipelineStage extends Stage {
constructor(scope: Construct, id: string, props?: StageProps) {
super(scope, id, props);
new S3Stack(this, 'S3Stack', {
env: { region: 'ap-northeast-1' },
});
}
}
パイプラインでデプロイするリソースの呼び出しをここで行います。
作成するS3の定義はlib/s3-stack.ts
で行い、このコードから呼び出すかたちで実行します。
lib/s3-stack.ts
import * as cdk from 'aws-cdk-lib';
import * as s3 from 'aws-cdk-lib/aws-s3';
import { Construct } from 'constructs';
export class S3Stack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
// S3 バケットを作成
new s3.Bucket(this, 'TestBucket');
}
}
パイプラインでデプロイするリソースの定義の詳細をここで定義しています。
今はS3バケットを1つ作成するだけになっています。
CDK PipelineとS3バケット1つを構築するシンプルなものです。用途に合わせてカスタマイズしてください。
初回は手動デプロイでパイプラインやその他のリソースを作成します。2回目以降はソースのターゲットブランチへのPushでパイプラインが動作し、自動デプロイが実行されます。
手動デプロイ前の注意点は「ターゲットブランチのコードと手動デプロイするコードを同じものにしておくこと」です。ターゲットブランチと手動デプロイしたコードに差分があると、正しく自動デプロイが実行できなかったことがありました。
コードの準備やターゲットブランチの最新化ができたら、CDKコードを手動デプロイします。
手動デプロイ時に利用したコマンドがこちらです。
> npm run build
> cdk-pipelines-test@0.1.0 build
> tsc
> cdk deploy
〜略〜
✨ Deployment time: 78.07s
Stack ARN:
arn:aws:cloudformation:ap-northeast-1:123456789012:stack/S3Stack/xxxxxxxx
✨ Total time: 82.02s
デプロイが完了しました。
CodePipeline のコンソールから作成したCDK Pipelines を確認してみましょう。
既にパイプラインが動き出しており、正常に完了していることがわかりました。ソース → ビルド → パイプライン更新 → デプロイという流れで処理されていますね。
developブランチにPushした直近のコミット「feat: S3バケットを1個に変更」でパイプラインが動作していました
CloudFormation コンソールを確認すると、コードで定義したCdkPipelinesStack
とDeploy-S3Stack
が作成されていました。
S3バケットが1つ作成されていた、ということを覚えておきましょう
自動デプロイのテスト
パイプラインの基本的な動作が問題ないとわかったため、ソースへのPushでパイプラインが正常に動作するかテストしてみます。
以下のコードでは、S3を作成する関数を別のスタックとして呼び出してみました。
lib/pipeline-stage.ts
import { Construct } from 'constructs';
import { Stage, StageProps } from 'aws-cdk-lib';
import { S3Stack } from '../lib/s3-stack';
export class PipelineStage extends Stage {
constructor(scope: Construct, id: string, props?: StageProps) {
super(scope, id, props);
new S3Stack(this, 'S3Stack', {
env: { region: 'ap-northeast-1' },
});
// 2つ目のS3バケットを追加
new S3Stack(this, 'S3Stack2', {
env: { region: 'ap-northeast-1' },
});
}
}
このコードをソースのターゲットブランチにPushしました。
しばらく待つと、パイプラインが自動で動作していました。成功しているようですがパイプラインが2回動いていますね。
1回目はUpdatePipeline
までが実行され、そのあとはキャンセルになっています。
2回目ではDeployまで実行されていますが、DeployのフェーズがS3Stack,S3Stack2という2スタック分のデプロイが実行されるようになったことがわかります。
CloudFormation もみておきましょう。
既存のS3Stackとは別のスタックとして、S3Stack2が新規で生成されていました。
これで終わります。
参考
最後に
以上、「CodePipelineのソースにGitHubを接続してみた(CodeConnections編)」でした。
あまりCDK 慣れしていないため色々と大変でしたが、手を動かしてトライアンドエラーしたことで学べたことが多かったです。
終わります。