CodePipelineによるCI/CD
このガイドでは、MBC CQRS Serverlessアプリケーション用にAWS CodePipelineを使用したCI/CDパイプラインのセットアップ方法を説明します。
概要
AWS CodePipelineは、ビルド、テスト、デプロイのワークフローを自動化します。典型的なパイプラインは以下で構成されます:
- ソースステージ: リポジトリからコードを取得
- ビルドステージ: テストを実行しアプリケーションをビルド
- デプロイステージ: CDK/CloudFormationを使用してAWSにデプロイ
前提条件
- CodePipeline、CodeBuild権限を持つAWSアカウント
- ソースリポジトリ(GitHub、CodeCommit、またはBitbucket)
- 設定済みのAWS CDKプロジェクト
CDKによるパイプラインスタック
パイプラインスタックの作成
infra/libs/pipeline-stack.ts にパイプライン用のCDKスタックを作成します:
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';
import * as codebuild from 'aws-cdk-lib/aws-codebuild';
import { Construct } from 'constructs';
export interface PipelineStackProps extends cdk.StackProps {
repositoryName: string;
branchName: string;
connectionArn: string;
}
export class PipelineStack extends cdk.Stack {
constructor(scope: Construct, id: string, props: PipelineStackProps) {
super(scope, id, props);
// Source artifact
const sourceOutput = new codepipeline.Artifact();
// Build artifact
const buildOutput = new codepipeline.Artifact();
// CodeBuild project
const buildProject = new codebuild.PipelineProject(this, 'BuildProject', {
environment: {
buildImage: codebuild.LinuxBuildImage.STANDARD_7_0,
computeType: codebuild.ComputeType.MEDIUM,
},
buildSpec: codebuild.BuildSpec.fromSourceFilename('buildspec.yml'),
});
// Pipeline
const pipeline = new codepipeline.Pipeline(this, 'Pipeline', {
pipelineName: `${props.repositoryName}-pipeline`,
stages: [
{
stageName: 'Source',
actions: [
new codepipeline_actions.CodeStarConnectionsSourceAction({
actionName: 'GitHub_Source',
owner: 'your-org',
repo: props.repositoryName,
branch: props.branchName,
connectionArn: props.connectionArn,
output: sourceOutput,
}),
],
},
{
stageName: 'Build',
actions: [
new codepipeline_actions.CodeBuildAction({
actionName: 'Build',
project: buildProject,
input: sourceOutput,
outputs: [buildOutput],
}),
],
},
{
stageName: 'Deploy',
actions: [
new codepipeline_actions.CloudFormationCreateUpdateStackAction({
actionName: 'Deploy',
stackName: `${props.repositoryName}-app`,
templatePath: buildOutput.atPath('cdk.out/AppStack.template.json'),
adminPermissions: true,
}),
],
},
],
});
}
}
BuildSpec設定
基本的 なbuildspec.yml
プロジェクトルートに buildspec.yml ファイルを作成します:
version: 0.2
phases:
install:
runtime-versions:
nodejs: 18
commands:
- npm ci
pre_build:
commands:
- echo "Running tests..."
- npm run test
- npm run lint
build:
commands:
- echo "Building application..."
- npm run build
- echo "Synthesizing CDK..."
- cd infra && npm ci && npx cdk synth
post_build:
commands:
- echo "Build completed on $(date)"
artifacts:
files:
- '**/*'
base-directory: infra
cache:
paths:
- node_modules/**/*
- infra/node_modules/**/*
環境変数付きBuildSpec
環境固有の設定が必要なビルドの場合:
version: 0.2
env:
variables:
NODE_ENV: production
parameter-store:
DATABASE_URL: /your-app/database-url
secrets-manager:
API_KEY: your-app-secrets:api-key
phases:
install:
runtime-versions:
nodejs: 18
commands:
- npm ci
build:
commands:
- npm run build
- cd infra && npx cdk synth --context env=$ENVIRONMENT
artifacts:
files:
- 'infra/cdk.out/**/*'
マルチ環境パイプライン
開発環境と本番環境のステージ
各環境用に別々のステージを持つパイプラインを作成します:
const pipeline = new codepipeline.Pipeline(this, 'Pipeline', {
stages: [
// Source stage
{ stageName: 'Source', actions: [sourceAction] },
// Build stage
{ stageName: 'Build', actions: [buildAction] },
// Deploy to Development
{
stageName: 'Deploy_Dev',
actions: [
new codepipeline_actions.CloudFormationCreateUpdateStackAction({
actionName: 'Deploy_Dev',
stackName: 'myapp-dev',
templatePath: buildOutput.atPath('cdk.out/DevStack.template.json'),
adminPermissions: true,
}),
],
},
// Manual Approval for Production
{
stageName: 'Approval',
actions: [
new codepipeline_actions.ManualApprovalAction({
actionName: 'Approve_Production',
notifyEmails: ['team@your-company.com'],
}),
],
},
// Deploy to Production
{
stageName: 'Deploy_Prod',
actions: [
new codepipeline_actions.CloudFormationCreateUpdateStackAction({
actionName: 'Deploy_Prod',
stackName: 'myapp-prod',
templatePath: buildOutput.atPath('cdk.out/ProdStack.template.json'),
adminPermissions: true,
}),
],
},
],
});