「コードの変更を本番環境に反映するのに毎回手作業が必要で、ミスが怖い」「テスト実行を忘れて不具合がリリースされた」――開発・運用現場でこうした問題を抱えていませんか。
この記事では、AWS CodePipelineを中心としたCI/CD(継続的インテグレーション/継続的デリバリー)パイプラインの構築方法を解説します。コードのプッシュからビルド、テスト、本番デプロイまでを自動化し、リリースの品質と速度を向上させる実践的な手順を紹介します。
CI/CDとは?自動化がもたらす開発効率の向上
CI/CDは、ソフトウェア開発におけるビルド・テスト・デプロイの自動化プロセスです。
CI(Continuous Integration:継続的インテグレーション)は、開発者がコードをリポジトリにプッシュするたびに、自動でビルドとテストを実行する仕組みです。コードの問題を早期に発見し、統合の手間を減らします。
CD(Continuous Delivery/Deployment:継続的デリバリー/デプロイメント)は、CIで検証されたコードを、ステージング環境や本番環境へ自動でデプロイする仕組みです。
手動デプロイとCI/CDの比較
| 項目 | 手動デプロイ | CI/CD自動化 |
|---|---|---|
| デプロイ時間 | 30分〜数時間 | 5〜15分 |
| ヒューマンエラー | 手順漏れ・設定ミスが発生 | 自動化により排除 |
| テスト実行 | 忘れることがある | 毎回必ず実行 |
| リリース頻度 | 週1回〜月1回 | 1日複数回も可能 |
| ロールバック | 手動で戻す必要 | 自動ロールバック可能 |
| 監査証跡 | 記録が残りにくい | 全履歴を自動記録 |
AWS CI/CDサービスの全体像
AWSは、CI/CDパイプラインを構成するための複数のマネージドサービスを提供しています。
| サービス | 役割 | 対応する工程 |
|---|---|---|
| CodeCommit | Gitリポジトリ | ソースコード管理 |
| CodeBuild | ビルド・テスト環境 | ビルド、ユニットテスト |
| CodeDeploy | デプロイ自動化 | EC2/ECS/Lambdaへのデプロイ |
| CodePipeline | パイプラインのオーケストレーション | 各工程の連携・順序制御 |
CodePipelineが全体のオーケストレーターとして機能し、ソース取得、ビルド、デプロイの各ステージを連携させます。ソースリポジトリにはCodeCommitの代わりにGitHubやBitBucketを使うこともできます。
パイプラインの基本フロー
コードプッシュ
│
▼
┌─Source Stage──────────┐
│ CodeCommit / GitHub │
│ コード取得 │
└────────────────────────┘
│
▼
┌─Build Stage───────────┐
│ CodeBuild │
│ ビルド・テスト実行 │
└────────────────────────┘
│
▼
┌─Deploy Stage(Staging)─┐
│ CodeDeploy │
│ ステージング環境デプロイ │
└────────────────────────┘
│
▼
┌─Approval Stage────────┐
│ 手動承認 │
│ 動作確認後に承認 │
└────────────────────────┘
│
▼
┌─Deploy Stage(Prod)────┐
│ CodeDeploy │
│ 本番環境デプロイ │
└────────────────────────┘
CodeBuildでビルド・テストを自動化する
CodeBuildは、ソースコードのコンパイル、テスト実行、デプロイ用アーティファクトの作成を行うフルマネージドのビルドサービスです。ビルド環境のサーバー管理は不要で、使った分だけの課金です。
buildspec.ymlの作成
CodeBuildの動作は、リポジトリのルートに配置するbuildspec.ymlで定義します。
Node.jsアプリケーションの場合:
version: 0.2
phases:
install:
runtime-versions:
nodejs: 20
commands:
- npm ci
pre_build:
commands:
- echo "Running lint..."
- npm run lint
- echo "Running unit tests..."
- npm test
build:
commands:
- echo "Building application..."
- npm run build
post_build:
commands:
- echo "Build completed on $(date)"
artifacts:
files:
- '**/*'
base-directory: dist
reports:
test-reports:
files:
- 'test-results/junit.xml'
file-format: JUNITXML
cache:
paths:
- 'node_modules/**/*'
各フェーズの役割は以下の通りです。
- install:ランタイムの指定と依存パッケージのインストール
- pre_build:リント・テストの実行(ここで失敗するとビルドは中断)
- build:アプリケーションのビルド
- post_build:ビルド後の処理(通知やクリーンアップ)
Dockerイメージのビルドとプッシュ
ECS/Fargateにデプロイする場合、CodeBuildでDockerイメージをビルドしてECR(Elastic Container Registry)にプッシュします。
version: 0.2
env:
variables:
AWS_ACCOUNT_ID: "123456789012"
IMAGE_REPO_NAME: "my-app"
IMAGE_TAG: "latest"
phases:
pre_build:
commands:
- echo "Logging in to Amazon ECR..."
- aws ecr get-login-password --region ap-northeast-1 |
docker login --username AWS --password-stdin
${AWS_ACCOUNT_ID}.dkr.ecr.ap-northeast-1.amazonaws.com
- COMMIT_HASH=$(echo $CODEBUILD_RESOLVED_SOURCE_VERSION | cut -c 1-7)
- IMAGE_TAG=${COMMIT_HASH:-latest}
build:
commands:
- echo "Building Docker image..."
- docker build -t ${IMAGE_REPO_NAME}:${IMAGE_TAG} .
- docker tag ${IMAGE_REPO_NAME}:${IMAGE_TAG}
${AWS_ACCOUNT_ID}.dkr.ecr.ap-northeast-1.amazonaws.com/${IMAGE_REPO_NAME}:${IMAGE_TAG}
post_build:
commands:
- echo "Pushing Docker image to ECR..."
- docker push
${AWS_ACCOUNT_ID}.dkr.ecr.ap-northeast-1.amazonaws.com/${IMAGE_REPO_NAME}:${IMAGE_TAG}
- printf '[{"name":"my-app","imageUri":"%s"}]'
${AWS_ACCOUNT_ID}.dkr.ecr.ap-northeast-1.amazonaws.com/${IMAGE_REPO_NAME}:${IMAGE_TAG}
> imagedefinitions.json
artifacts:
files:
- imagedefinitions.json
出力されるimagedefinitions.jsonをCodePipelineのデプロイステージに渡すことで、ECSのタスク定義を自動更新できます。
CodeDeployでデプロイを安全に自動化する
CodeDeployは、EC2インスタンスやECSサービス、Lambda関数へのデプロイを自動化するサービスです。特にゼロダウンタイムでのデプロイ戦略が充実しています。
デプロイ戦略の選択
| 戦略 | 概要 | 適用先 | リスク |
|---|---|---|---|
| AllAtOnce | 全インスタンスに一括デプロイ | 開発環境 | 高(ダウンタイムあり) |
| Rolling | 一定数ずつ順次デプロイ | EC2 | 中 |
| Blue/Green | 新環境を別に作成して切り替え | EC2/ECS | 低 |
| Canary | 一部トラフィックから段階的に移行 | ECS/Lambda | 最低 |
本番環境ではBlue/GreenまたはCanaryデプロイを推奨します。問題が発生した場合に即座にロールバックできるためです。
ECSへのBlue/Greenデプロイ設定
ECSサービスへのBlue/Greenデプロイでは、2つのターゲットグループを使い、新しいタスク定義でタスクを起動した後、ALBのリスナーを切り替えます。
CodeDeployのappspec.ymlの例です。
version: 0.0
Resources:
- TargetService:
Type: AWS::ECS::Service
Properties:
TaskDefinition: "arn:aws:ecs:ap-northeast-1:123456789012:task-definition/my-app:1"
LoadBalancerInfo:
ContainerName: "my-app"
ContainerPort: 8080
Hooks:
- BeforeInstall: "LambdaFunctionToValidateBeforeInstall"
- AfterInstall: "LambdaFunctionToValidateAfterInstall"
- AfterAllowTestTraffic: "LambdaFunctionToRunIntegrationTests"
- BeforeAllowTraffic: "LambdaFunctionToValidateBeforeTraffic"
- AfterAllowTraffic: "LambdaFunctionToRunSmokeTests"
Hooksでは、各デプロイステップの前後にLambda関数を実行してバリデーションを行えます。テストトラフィックを送って動作確認した後に、本番トラフィックを切り替える安全なフローを構築できます。
CodePipelineでパイプラインを統合する
各サービスの設定ができたら、CodePipelineで全体を統合します。
パイプライン作成の手順
AWS CLIでパイプラインを作成する場合、JSON形式でパイプライン定義を記述します。
{
"pipeline": {
"name": "my-app-pipeline",
"roleArn": "arn:aws:iam::123456789012:role/CodePipelineServiceRole",
"stages": [
{
"name": "Source",
"actions": [
{
"name": "SourceAction",
"actionTypeId": {
"category": "Source",
"owner": "AWS",
"provider": "CodeCommit",
"version": "1"
},
"configuration": {
"RepositoryName": "my-app",
"BranchName": "main"
},
"outputArtifacts": [{"name": "SourceOutput"}]
}
]
},
{
"name": "Build",
"actions": [
{
"name": "BuildAction",
"actionTypeId": {
"category": "Build",
"owner": "AWS",
"provider": "CodeBuild",
"version": "1"
},
"configuration": {
"ProjectName": "my-app-build"
},
"inputArtifacts": [{"name": "SourceOutput"}],
"outputArtifacts": [{"name": "BuildOutput"}]
}
]
},
{
"name": "DeployStaging",
"actions": [
{
"name": "DeployStagingAction",
"actionTypeId": {
"category": "Deploy",
"owner": "AWS",
"provider": "CodeDeploy",
"version": "1"
},
"configuration": {
"ApplicationName": "my-app",
"DeploymentGroupName": "staging"
},
"inputArtifacts": [{"name": "BuildOutput"}]
}
]
},
{
"name": "Approval",
"actions": [
{
"name": "ManualApproval",
"actionTypeId": {
"category": "Approval",
"owner": "AWS",
"provider": "Manual",
"version": "1"
},
"configuration": {
"NotificationArn": "arn:aws:sns:ap-northeast-1:123456789012:approval-notifications"
}
}
]
},
{
"name": "DeployProduction",
"actions": [
{
"name": "DeployProductionAction",
"actionTypeId": {
"category": "Deploy",
"owner": "AWS",
"provider": "CodeDeploy",
"version": "1"
},
"configuration": {
"ApplicationName": "my-app",
"DeploymentGroupName": "production"
},
"inputArtifacts": [{"name": "BuildOutput"}]
}
]
}
]
}
}
ステージング環境へのデプロイ後に手動承認ステージを入れることで、動作確認を行ってから本番にリリースできます。完全自動化が目標ですが、最初はこのように承認ステップを入れておくと安心です。
GitHubとの連携
ソースリポジトリにGitHubを使う場合、CodePipelineのソースステージでGitHub(バージョン2)接続を設定します。AWS CodeStar Connectionsを通じてGitHubと連携し、プルリクエストのマージやブランチへのプッシュをトリガーにパイプラインを起動できます。
CI/CDパイプラインのセキュリティと権限管理
CI/CDパイプラインは本番環境へのデプロイ権限を持つため、セキュリティの確保が極めて重要です。
IAMロールの最小権限設計
各サービスのIAMロールには、必要最小限の権限のみを付与します。IAMのベストプラクティスに従い、以下のようにロールを分離してください。
- CodePipeline実行ロール:パイプラインの各ステージを呼び出す権限のみ
- CodeBuildサービスロール:ビルドに必要なリソース(ECR、S3など)へのアクセス権限
- CodeDeployサービスロール:デプロイ先(ECS、EC2、Lambda)の操作権限
シークレット管理
ビルドやデプロイで使う機密情報(APIキー、データベースパスワードなど)は、buildspec.ymlにハードコードしてはいけません。以下の方法で安全に管理します。
- AWS Systems Manager Parameter Store:暗号化されたパラメータとして保存
- AWS Secrets Manager:自動ローテーション機能付きのシークレット管理
# buildspec.ymlでのParameter Store参照例
env:
parameter-store:
DB_PASSWORD: /production/database/password
API_KEY: /production/external-api/key
パイプラインの監視とトラブルシューティング
CI/CDパイプラインも他のシステムと同様に、監視体制の構築が必要です。
パイプライン失敗時の通知設定
CodePipelineの状態変化をCloudWatch Eventsでキャプチャし、SNS経由で通知を送ります。
# パイプライン失敗時のCloudWatch Eventsルール
{
"source": ["aws.codepipeline"],
"detail-type": ["CodePipeline Pipeline Execution State Change"],
"detail": {
"state": ["FAILED"]
}
}
CloudWatchの監視設定ガイドで通知の詳細設定方法も確認してください。
よくあるトラブルと対処法
- ビルド失敗:CodeBuildのログを確認し、依存関係の問題やテスト失敗の原因を特定する
- 権限エラー:IAMロールのポリシーを確認し、不足している権限を追加する
- デプロイタイムアウト:ヘルスチェックの設定を見直し、アプリケーションの起動時間に合った値に調整する
- アーティファクトの受け渡しエラー:ステージ間のアーティファクト名が一致しているか確認する
まとめ:小さく始めて段階的に自動化を進めよう
AWS CodePipelineを使ったCI/CDパイプラインの構築方法を解説しました。
- CodeBuildでビルドとテストを自動化し、品質を担保する
- CodeDeployでBlue/Greenデプロイにより安全にリリースする
- CodePipelineで全体を統合し、コードプッシュから本番反映までを自動化する
- 手動承認ステージを入れて、段階的に自動化レベルを上げていく
- IAMの最小権限とシークレット管理でセキュリティを確保する
最初は手動承認ありのシンプルなパイプラインから始め、自動テストの充実に合わせて承認ステップを減らしていくのが現実的なアプローチです。インフラのコード管理についてはTerraformによるインフラ管理も合わせて導入を検討してください。
関連記事
AWS CloudFrontでサイト高速化|CDN設定からキャッシュ戦略まで実践解説
AWS CloudWatchで監視・アラート設定|運用担当者のための実践ガイド
AWS Cost Explorerでコスト可視化|ムダを見つけて月額費用を削減する実践術
AWS ECS/Fargateでコンテナ運用|Docker→本番デプロイの実践ガイド
AWS IAMのベストプラクティス|最小権限の原則を実務で実装する方法
AWS RDSの実務ガイド|データベース構築・バックアップ・パフォーマンスチューニング
AWS S3の実務活用ガイド|バケット設計・アクセス制御・コスト最適化の実践
AWS VPCのネットワーク設計入門|サブネット・セキュリティグループの実践構成