はじめに#
コンテナアプリケーションを本番環境で運用する際、デプロイの自動化は開発効率と品質の両面で不可欠な要素です。手動でDockerイメージをビルドし、ECRへプッシュし、ECSサービスを更新するワークフローは、ヒューマンエラーのリスクが高く、リリースサイクルのボトルネックになります。
AWSでは、CodePipelineとCodeBuildを組み合わせることで、Gitリポジトリへのコードプッシュから本番デプロイまでを完全に自動化できます。本記事では、GitHub連携からECSへの自動デプロイまで、実運用に必要なCI/CDパイプラインの構築手順を体系的に解説します。
この記事を読むことで、以下のことが理解できるようになります。
- コンテナCI/CDパイプラインの全体アーキテクチャと各サービスの役割
- CodePipelineによるパイプラインの設計と構築手順
- CodeBuildでのDockerイメージビルドとECRプッシュの設定
- ECSサービスへの自動ローリングデプロイの実装
- パイプラインのセキュリティと運用のベストプラクティス
コンテナCI/CDパイプラインの全体像#
パイプラインアーキテクチャ#
AWSでコンテナCI/CDパイプラインを構築する場合、以下のサービスが連携して動作します。
flowchart LR
subgraph Source["ソース管理"]
GitHub["GitHub"]
CodeCommit["CodeCommit"]
end
subgraph Build["ビルドステージ"]
CodeBuild["AWS CodeBuild"]
end
subgraph Registry["レジストリ"]
ECR["Amazon ECR"]
end
subgraph Deploy["デプロイステージ"]
ECS["Amazon ECS"]
end
subgraph Orchestration["オーケストレーション"]
CodePipeline["AWS CodePipeline"]
end
GitHub --> CodePipeline
CodeCommit --> CodePipeline
CodePipeline --> CodeBuild
CodeBuild --> ECR
CodeBuild --> CodePipeline
CodePipeline --> ECS各サービスの役割#
| サービス |
役割 |
主な機能 |
| CodePipeline |
パイプライン管理 |
ステージ間のワークフロー制御、トリガー管理 |
| CodeBuild |
ビルド実行 |
Dockerイメージのビルド、テスト実行、ECRプッシュ |
| ECR |
イメージ保存 |
コンテナイメージのバージョン管理、脆弱性スキャン |
| ECS |
アプリケーション実行 |
コンテナのデプロイ、ローリングアップデート |
CI/CDパイプラインのフロー#
具体的なパイプラインの処理フローは以下のようになります。
sequenceDiagram
participant Dev as 開発者
participant Git as GitHub
participant CP as CodePipeline
participant CB as CodeBuild
participant ECR as Amazon ECR
participant ECS as Amazon ECS
Dev->>Git: git push
Git->>CP: Webhook通知
CP->>CP: Sourceステージ開始
CP->>CB: Buildステージ開始
CB->>CB: ソースコード取得
CB->>CB: docker build
CB->>CB: docker tag
CB->>ECR: docker push
CB->>CP: ビルド成功通知
CP->>ECS: Deployステージ開始
ECS->>ECS: 新タスク起動
ECS->>ECS: ヘルスチェック
ECS->>ECS: 旧タスク停止
ECS->>CP: デプロイ完了通知前提条件と準備#
必要なリソース#
CI/CDパイプラインを構築する前に、以下のリソースが準備されている必要があります。
| リソース |
用途 |
事前準備 |
| ECRリポジトリ |
Dockerイメージの保存先 |
リポジトリ作成済み |
| ECSクラスター |
コンテナ実行環境 |
クラスター作成済み |
| ECSサービス |
アプリケーションの実行管理 |
サービス作成済み |
| GitHubリポジトリ |
ソースコード管理 |
リポジトリ作成済み |
| IAMロール |
各サービスの権限管理 |
本記事で作成 |
プロジェクト構成#
サンプルプロジェクトの構成は以下のとおりです。
my-container-app/
├── Dockerfile
├── buildspec.yml # CodeBuild設定
├── taskdef.json # ECSタスク定義テンプレート
├── appspec.yaml # CodeDeploy設定(オプション)
├── src/
│ └── index.js
└── package.json
サンプルDockerfile#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
FROM node:20-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --only=production
COPY src/ ./src/
EXPOSE 3000
USER node
CMD ["node", "src/index.js"]
|
CodeBuildプロジェクトの設定#
buildspec.ymlの作成#
CodeBuildの動作を定義するbuildspec.ymlを作成します。このファイルでは、Dockerイメージのビルド、タグ付け、ECRへのプッシュを行います。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
version: 0.2
env:
variables:
AWS_DEFAULT_REGION: ap-northeast-1
IMAGE_REPO_NAME: my-container-app
parameter-store:
DOCKERHUB_USER: /codebuild/dockerhub-user
DOCKERHUB_TOKEN: /codebuild/dockerhub-token
phases:
pre_build:
commands:
- echo Logging in to Amazon ECR...
- aws ecr get-login-password --region $AWS_DEFAULT_REGION | docker login --username AWS --password-stdin $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com
- REPOSITORY_URI=$AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com/$IMAGE_REPO_NAME
- COMMIT_HASH=$(echo $CODEBUILD_RESOLVED_SOURCE_VERSION | cut -c 1-7)
- IMAGE_TAG=${COMMIT_HASH:=latest}
# Docker Hub認証(レートリミット対策)
- echo $DOCKERHUB_TOKEN | docker login --username $DOCKERHUB_USER --password-stdin
build:
commands:
- echo Build started on `date`
- echo Building the Docker image...
- docker build -t $REPOSITORY_URI:latest .
- docker tag $REPOSITORY_URI:latest $REPOSITORY_URI:$IMAGE_TAG
post_build:
commands:
- echo Build completed on `date`
- echo Pushing the Docker images...
- docker push $REPOSITORY_URI:latest
- docker push $REPOSITORY_URI:$IMAGE_TAG
- echo Writing image definitions file...
- printf '[{"name":"app","imageUri":"%s"}]' $REPOSITORY_URI:$IMAGE_TAG > imagedefinitions.json
artifacts:
files:
- imagedefinitions.json
|
buildspec.ymlの各セクション解説#
| セクション |
役割 |
主な処理 |
| env.variables |
環境変数定義 |
リージョン、リポジトリ名の設定 |
| env.parameter-store |
Secrets取得 |
Docker Hub認証情報の取得 |
| pre_build |
ビルド前処理 |
ECR/Docker Hub認証、変数設定 |
| build |
ビルド処理 |
Dockerイメージのビルドとタグ付け |
| post_build |
ビルド後処理 |
ECRプッシュ、成果物ファイル生成 |
| artifacts |
成果物定義 |
次ステージへ渡すファイルの指定 |
imagedefinitions.jsonの重要性#
imagedefinitions.jsonは、CodePipelineのECSデプロイアクションが参照するファイルです。このファイルにより、デプロイ時に使用するイメージURIが決定されます。
1
2
3
4
5
6
|
[
{
"name": "app",
"imageUri": "123456789012.dkr.ecr.ap-northeast-1.amazonaws.com/my-container-app:abc1234"
}
]
|
nameフィールドは、ECSタスク定義内のコンテナ名と一致させる必要があります。
IAMロールの設定#
CodeBuild用IAMロール#
CodeBuildがECRへイメージをプッシュするために必要なIAMロールを作成します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
|
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"ecr:GetAuthorizationToken"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"ecr:BatchCheckLayerAvailability",
"ecr:GetDownloadUrlForLayer",
"ecr:BatchGetImage",
"ecr:PutImage",
"ecr:InitiateLayerUpload",
"ecr:UploadLayerPart",
"ecr:CompleteLayerUpload"
],
"Resource": "arn:aws:ecr:ap-northeast-1:123456789012:repository/my-container-app"
},
{
"Effect": "Allow",
"Action": [
"logs:CreateLogGroup",
"logs:CreateLogStream",
"logs:PutLogEvents"
],
"Resource": "arn:aws:logs:ap-northeast-1:123456789012:log-group:/aws/codebuild/*"
},
{
"Effect": "Allow",
"Action": [
"ssm:GetParameters"
],
"Resource": "arn:aws:ssm:ap-northeast-1:123456789012:parameter/codebuild/*"
}
]
}
|
信頼ポリシーは以下のように設定します。
1
2
3
4
5
6
7
8
9
10
11
12
|
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Principal": {
"Service": "codebuild.amazonaws.com"
},
"Action": "sts:AssumeRole"
}
]
}
|
CodePipeline用IAMロール#
CodePipelineには、各ステージのサービスを操作する権限が必要です。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
|
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": [
"codebuild:BatchGetBuilds",
"codebuild:StartBuild"
],
"Resource": "arn:aws:codebuild:ap-northeast-1:123456789012:project/my-container-build"
},
{
"Effect": "Allow",
"Action": [
"ecs:DescribeServices",
"ecs:DescribeTaskDefinition",
"ecs:DescribeTasks",
"ecs:ListTasks",
"ecs:RegisterTaskDefinition",
"ecs:UpdateService"
],
"Resource": "*"
},
{
"Effect": "Allow",
"Action": [
"iam:PassRole"
],
"Resource": [
"arn:aws:iam::123456789012:role/ecsTaskExecutionRole",
"arn:aws:iam::123456789012:role/ecsTaskRole"
],
"Condition": {
"StringEquals": {
"iam:PassedToService": "ecs-tasks.amazonaws.com"
}
}
},
{
"Effect": "Allow",
"Action": [
"s3:GetObject",
"s3:GetObjectVersion",
"s3:PutObject"
],
"Resource": "arn:aws:s3:::codepipeline-ap-northeast-1-*/*"
},
{
"Effect": "Allow",
"Action": [
"codestar-connections:UseConnection"
],
"Resource": "arn:aws:codestar-connections:ap-northeast-1:123456789012:connection/*"
}
]
}
|
CodePipelineの構築#
パイプラインの全体構成#
CodePipelineは3つのステージで構成します。
flowchart TB
subgraph Pipeline["CodePipeline"]
subgraph Source["Sourceステージ"]
S1["GitHub Connection"]
S2["ソースコード取得"]
end
subgraph Build["Buildステージ"]
B1["CodeBuild起動"]
B2["Docker Build"]
B3["ECR Push"]
B4["artifacts生成"]
end
subgraph Deploy["Deployステージ"]
D1["imagedefinitions.json読込"]
D2["タスク定義更新"]
D3["ECSサービス更新"]
end
end
Source --> Build
Build --> DeployAWS CLIによるパイプライン作成#
以下のJSONファイルを使用してパイプラインを作成します。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
|
{
"pipeline": {
"name": "my-container-pipeline",
"roleArn": "arn:aws:iam::123456789012:role/CodePipelineRole",
"artifactStore": {
"type": "S3",
"location": "codepipeline-ap-northeast-1-123456789012"
},
"stages": [
{
"name": "Source",
"actions": [
{
"name": "Source",
"actionTypeId": {
"category": "Source",
"owner": "AWS",
"provider": "CodeStarSourceConnection",
"version": "1"
},
"configuration": {
"ConnectionArn": "arn:aws:codestar-connections:ap-northeast-1:123456789012:connection/xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx",
"FullRepositoryId": "your-org/my-container-app",
"BranchName": "main",
"OutputArtifactFormat": "CODE_ZIP"
},
"outputArtifacts": [
{
"name": "SourceOutput"
}
],
"runOrder": 1
}
]
},
{
"name": "Build",
"actions": [
{
"name": "Build",
"actionTypeId": {
"category": "Build",
"owner": "AWS",
"provider": "CodeBuild",
"version": "1"
},
"configuration": {
"ProjectName": "my-container-build",
"EnvironmentVariables": "[{\"name\":\"AWS_ACCOUNT_ID\",\"value\":\"123456789012\",\"type\":\"PLAINTEXT\"}]"
},
"inputArtifacts": [
{
"name": "SourceOutput"
}
],
"outputArtifacts": [
{
"name": "BuildOutput"
}
],
"runOrder": 1
}
]
},
{
"name": "Deploy",
"actions": [
{
"name": "Deploy",
"actionTypeId": {
"category": "Deploy",
"owner": "AWS",
"provider": "ECS",
"version": "1"
},
"configuration": {
"ClusterName": "my-cluster",
"ServiceName": "my-service",
"FileName": "imagedefinitions.json"
},
"inputArtifacts": [
{
"name": "BuildOutput"
}
],
"runOrder": 1
}
]
}
]
}
}
|
パイプラインを作成するコマンドは以下のとおりです。
1
|
aws codepipeline create-pipeline --cli-input-json file://pipeline.json
|
GitHub接続の設定#
CodePipelineとGitHubを連携するには、AWS CodeStar Connectionsを使用します。
1
2
3
4
5
6
7
|
# 接続の作成
aws codestar-connections create-connection \
--provider-type GitHub \
--connection-name my-github-connection
# 作成された接続はPENDING状態
# AWSコンソールで接続を承認する必要がある
|
接続の承認手順は以下のとおりです。
- AWS マネジメントコンソールで「Developer Tools」から「Connections」を選択
- 作成した接続を選択し、「Update pending connection」をクリック
- GitHubの認証画面でアクセスを許可
- 接続ステータスが「Available」になることを確認
CodeBuildプロジェクトの作成#
プロジェクト設定#
CodeBuildプロジェクトをAWS CLIで作成します。
1
2
3
4
5
6
|
aws codebuild create-project \
--name my-container-build \
--source type=CODEPIPELINE \
--artifacts type=CODEPIPELINE \
--environment type=LINUX_CONTAINER,computeType=BUILD_GENERAL1_SMALL,image=aws/codebuild/amazonlinux2-x86_64-standard:5.0,privilegedMode=true \
--service-role arn:aws:iam::123456789012:role/CodeBuildRole
|
環境設定のポイント#
| 設定項目 |
推奨値 |
理由 |
| privilegedMode |
true |
Docker daemonを使用するため必須 |
| computeType |
BUILD_GENERAL1_SMALL |
一般的なビルドには十分 |
| image |
amazonlinux2-x86_64-standard:5.0 |
Docker対応の最新イメージ |
| buildTimeout |
30分 |
イメージサイズに応じて調整 |
キャッシュの活用#
ビルド時間を短縮するために、Dockerレイヤーキャッシュを活用できます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
version: 0.2
phases:
pre_build:
commands:
- echo Logging in to Amazon ECR...
- aws ecr get-login-password --region $AWS_DEFAULT_REGION | docker login --username AWS --password-stdin $AWS_ACCOUNT_ID.dkr.ecr.$AWS_DEFAULT_REGION.amazonaws.com
# キャッシュ用にlatestイメージをプル
- docker pull $REPOSITORY_URI:latest || true
build:
commands:
# キャッシュを利用したビルド
- docker build --cache-from $REPOSITORY_URI:latest -t $REPOSITORY_URI:latest .
cache:
paths:
- '/root/.docker/**/*'
|
ECSサービスへの自動デプロイ#
デプロイの仕組み#
CodePipelineのECSデプロイアクションは、以下の処理を自動的に実行します。
flowchart TB
subgraph DeployProcess["ECSデプロイプロセス"]
A["imagedefinitions.json読込"]
B["新タスク定義リビジョン作成"]
C["ECSサービス更新"]
D["新タスク起動"]
E["ヘルスチェック待機"]
F["旧タスクドレイン"]
G["旧タスク停止"]
H["デプロイ完了"]
end
A --> B
B --> C
C --> D
D --> E
E -->|成功| F
E -->|失敗| Rollback["ロールバック"]
F --> G
G --> Hデプロイ設定の最適化#
ECSサービスのデプロイ設定により、ローリングデプロイの挙動を制御できます。
1
2
3
4
5
6
7
8
9
10
|
{
"deploymentConfiguration": {
"deploymentCircuitBreaker": {
"enable": true,
"rollback": true
},
"maximumPercent": 200,
"minimumHealthyPercent": 100
}
}
|
| パラメータ |
設定値 |
説明 |
| maximumPercent |
200 |
デプロイ中のタスク最大数(希望数の200%) |
| minimumHealthyPercent |
100 |
最低限稼働させるタスク数(希望数の100%) |
| deploymentCircuitBreaker |
enable: true |
デプロイ失敗時の自動ロールバック有効化 |
ヘルスチェックの設定#
ALBのヘルスチェック設定は、デプロイの成否判定に直結します。
1
2
3
4
5
6
7
8
9
10
|
{
"healthCheck": {
"path": "/health",
"protocol": "HTTP",
"interval": 30,
"timeout": 5,
"healthyThreshold": 2,
"unhealthyThreshold": 3
}
}
|
アプリケーション側でヘルスチェックエンドポイントを実装します。
1
2
3
4
5
|
// Express.jsの例
app.get('/health', (req, res) => {
// 依存サービスのチェックを含めることも可能
res.status(200).json({ status: 'healthy' });
});
|
Blue/Greenデプロイの実装#
Blue/Greenデプロイの概要#
より安全なデプロイを実現するために、CodeDeployを使用したBlue/Greenデプロイも選択できます。
flowchart TB
subgraph BlueGreen["Blue/Greenデプロイ"]
subgraph Blue["Blue環境(現行)"]
B1["タスクセット"]
B2["ターゲットグループ"]
end
subgraph Green["Green環境(新規)"]
G1["新タスクセット"]
G2["新ターゲットグループ"]
end
ALB["Application Load Balancer"]
ALB -->|本番トラフィック| B2
ALB -.->|テストトラフィック| G2
endappspec.yamlの作成#
Blue/Greenデプロイにはappspec.yamlが必要です。
1
2
3
4
5
6
7
8
9
10
|
version: 0.0
Resources:
- TargetService:
Type: AWS::ECS::Service
Properties:
TaskDefinition: <TASK_DEFINITION>
LoadBalancerInfo:
ContainerName: "app"
ContainerPort: 3000
PlatformVersion: "LATEST"
|
CodeDeployの設定#
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
|
{
"applicationName": "my-ecs-app",
"deploymentGroupName": "my-ecs-dg",
"deploymentConfigName": "CodeDeployDefault.ECSLinear10PercentEvery1Minutes",
"ecsServices": [
{
"serviceName": "my-service",
"clusterName": "my-cluster"
}
],
"loadBalancerInfo": {
"targetGroupPairInfoList": [
{
"targetGroups": [
{
"name": "my-tg-blue"
},
{
"name": "my-tg-green"
}
],
"prodTrafficRoute": {
"listenerArns": [
"arn:aws:elasticloadbalancing:ap-northeast-1:123456789012:listener/app/my-alb/xxx/yyy"
]
}
}
]
},
"blueGreenDeploymentConfiguration": {
"terminateBlueInstancesOnDeploymentSuccess": {
"action": "TERMINATE",
"terminationWaitTimeInMinutes": 5
},
"deploymentReadyOption": {
"actionOnTimeout": "CONTINUE_DEPLOYMENT",
"waitTimeInMinutes": 0
}
}
}
|
パイプラインの監視とトラブルシューティング#
CloudWatchによる監視#
パイプラインの実行状況をCloudWatchで監視します。
flowchart LR
subgraph Pipeline["CodePipeline"]
Stage1["Source"]
Stage2["Build"]
Stage3["Deploy"]
end
subgraph Monitoring["監視"]
CW["CloudWatch Metrics"]
Alarm["CloudWatch Alarms"]
SNS["Amazon SNS"]
end
Pipeline --> CW
CW --> Alarm
Alarm --> SNS
SNS --> Email["Email通知"]
SNS --> Slack["Slack通知"]主要なメトリクス#
| メトリクス |
説明 |
アラーム閾値例 |
| ActionExecution |
アクション実行状態 |
Failed状態の検知 |
| StageExecution |
ステージ実行状態 |
Failed状態の検知 |
| PipelineExecution |
パイプライン全体の実行状態 |
実行時間の異常 |
EventBridgeによる通知設定#
パイプラインの状態変化をEventBridgeでキャプチャし、通知を送信します。
1
2
3
4
5
6
7
|
{
"source": ["aws.codepipeline"],
"detail-type": ["CodePipeline Pipeline Execution State Change"],
"detail": {
"state": ["FAILED", "SUCCEEDED"]
}
}
|
Lambda関数でSlack通知を実装する例は以下のとおりです。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
|
import json
import urllib3
import os
http = urllib3.PoolManager()
def lambda_handler(event, context):
webhook_url = os.environ['SLACK_WEBHOOK_URL']
pipeline_name = event['detail']['pipeline']
state = event['detail']['state']
execution_id = event['detail']['execution-id']
color = '#36a64f' if state == 'SUCCEEDED' else '#ff0000'
message = {
'attachments': [
{
'color': color,
'title': f'Pipeline: {pipeline_name}',
'fields': [
{'title': 'State', 'value': state, 'short': True},
{'title': 'Execution ID', 'value': execution_id, 'short': True}
]
}
]
}
http.request(
'POST',
webhook_url,
body=json.dumps(message),
headers={'Content-Type': 'application/json'}
)
return {'statusCode': 200}
|
よくあるエラーと対処法#
| エラー |
原因 |
対処法 |
| ECR認証エラー |
IAMロール権限不足 |
ecr:GetAuthorizationToken権限を追加 |
| Docker pushエラー |
リポジトリ権限不足 |
ECRリポジトリポリシーを確認 |
| ECSデプロイタイムアウト |
ヘルスチェック失敗 |
ヘルスチェック設定とアプリケーションを確認 |
| タスク起動失敗 |
イメージ取得エラー |
タスク実行ロールのECR権限を確認 |
CodeBuildログの確認#
ビルド失敗時は、CloudWatch Logsで詳細を確認します。
1
2
3
4
5
6
7
8
9
10
|
# 最新のビルドログを取得
aws logs get-log-events \
--log-group-name /aws/codebuild/my-container-build \
--log-stream-name $(aws logs describe-log-streams \
--log-group-name /aws/codebuild/my-container-build \
--order-by LastEventTime \
--descending \
--limit 1 \
--query 'logStreams[0].logStreamName' \
--output text)
|
セキュリティのベストプラクティス#
最小権限の原則#
IAMロールには必要最小限の権限のみを付与します。
flowchart TB
subgraph Principals["プリンシパル"]
CodePipeline["CodePipeline"]
CodeBuild["CodeBuild"]
ECS["ECS Task"]
end
subgraph Roles["IAMロール"]
CPRole["CodePipelineRole"]
CBRole["CodeBuildRole"]
TaskExecRole["TaskExecutionRole"]
TaskRole["TaskRole"]
end
subgraph Resources["リソース"]
S3["S3 Artifacts"]
ECR["ECR"]
Logs["CloudWatch Logs"]
SSM["Parameter Store"]
end
CodePipeline --> CPRole
CodeBuild --> CBRole
ECS --> TaskExecRole
ECS --> TaskRole
CPRole --> S3
CBRole --> ECR
CBRole --> Logs
CBRole --> SSM
TaskExecRole --> ECR
TaskExecRole --> Logsシークレット管理#
認証情報はParameter StoreまたはSecrets Managerで管理します。
1
2
3
4
5
6
7
8
9
10
|
# Parameter Storeにシークレットを保存
aws ssm put-parameter \
--name /codebuild/dockerhub-token \
--type SecureString \
--value "your-dockerhub-token"
# buildspec.ymlで参照
# env:
# parameter-store:
# DOCKERHUB_TOKEN: /codebuild/dockerhub-token
|
イメージスキャンの有効化#
ECRの脆弱性スキャンをビルドプロセスに組み込みます。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
|
# buildspec.ymlに追加
phases:
post_build:
commands:
- echo Initiating vulnerability scan...
- aws ecr start-image-scan --repository-name $IMAGE_REPO_NAME --image-id imageTag=$IMAGE_TAG
- echo Waiting for scan results...
- aws ecr wait image-scan-complete --repository-name $IMAGE_REPO_NAME --image-id imageTag=$IMAGE_TAG
- |
SCAN_FINDINGS=$(aws ecr describe-image-scan-findings \
--repository-name $IMAGE_REPO_NAME \
--image-id imageTag=$IMAGE_TAG \
--query 'imageScanFindings.findingSeverityCounts' \
--output json)
echo "Scan findings: $SCAN_FINDINGS"
# CRITICALまたはHIGHがあればビルドを失敗させる
CRITICAL=$(echo $SCAN_FINDINGS | jq '.CRITICAL // 0')
HIGH=$(echo $SCAN_FINDINGS | jq '.HIGH // 0')
if [ "$CRITICAL" -gt 0 ] || [ "$HIGH" -gt 0 ]; then
echo "Critical or High vulnerabilities found!"
exit 1
fi
|
まとめ#
本記事では、AWSでコンテナCI/CDパイプラインを構築する方法を解説しました。主なポイントは以下のとおりです。
| 項目 |
要点 |
| パイプライン構成 |
CodePipeline + CodeBuild + ECR + ECSの連携 |
| ビルド設定 |
buildspec.ymlでDocker build/push/artifacts生成を定義 |
| デプロイ方式 |
ローリングデプロイまたはBlue/Greenデプロイを選択 |
| 権限管理 |
最小権限のIAMロールを各サービスに設定 |
| 監視 |
CloudWatch + EventBridgeで状態監視と通知を実装 |
| セキュリティ |
シークレット管理とイメージスキャンの組み込み |
CI/CDパイプラインの構築により、コードの変更から本番デプロイまでを自動化し、開発チームの生産性とリリース品質を向上させることができます。まずはシンプルなローリングデプロイから始め、運用が安定したらBlue/Greenデプロイへの移行を検討してください。
参考リンク#