前提条件
- 第1回から第11回までの構築が完了していること
- CI/CD対象のGitHubリポジトリが作成されていること
- こちらからDockerコンテナでの実行環境が準備できていること
Terraform実行環境の起動
前回と同様に、Dockerコンテナ内で作業を進めます。
# コンテナを起動してbashに入る
docker-compose run --rm terraform
これ以降のコマンドは、すべてこのコンテナ内で実行します。
基礎知識
CI/CD(Continuous Integration/Continuous Deployment)は、コード変更を自動的にビルド・テスト・デプロイする仕組みです。
WEBアプリケーション開発者の視点から見ると
ローカル開発では、コードを変更したら手動でビルドし、テストを実行し、サーバーにデプロイします。しかし、チーム開発や本番環境では以下の課題があります。
手動デプロイの課題 | CI/CDによる解決 | メリット |
---|---|---|
デプロイ手順を忘れる | 自動化されたワークフロー | 人的ミスの削減 |
テストの実行漏れ | プルリクエスト時に自動テスト | 品質の担保 |
環境による差異 | 同一のビルドプロセス | 再現性の確保 |
デプロイに時間がかかる | パイプライン並列処理 | リリース頻度の向上 |
GitHub Actionsの仕組み
GitHub Actionsは、GitHubが提供するCI/CDサービスです。リポジトリ内にワークフローファイルを配置するだけで動作します。
構成要素 | 説明 | 用途 |
---|---|---|
Workflow | 自動化プロセス全体 | ビルドからデプロイまでの一連の流れ |
Job | ワークフロー内の独立した処理単位 | ビルド、テスト、デプロイなど |
Step | ジョブ内の個別のタスク | コマンド実行、アクション実行 |
Runner | ワークフローを実行する仮想マシン | Ubuntu、Windows、macOS |
デプロイ戦略
戦略 | 説明 | 適用場面 |
---|---|---|
ブランチデプロイ | 特定ブランチへのプッシュでデプロイ | 開発環境への自動デプロイ |
タグデプロイ | Gitタグ作成でデプロイ | 本番環境への計画的リリース |
プルリクエストデプロイ | PR作成でプレビュー環境構築 | レビュー前の動作確認 |
手動承認デプロイ | 承認後にデプロイ実行 | 本番環境への慎重なリリース |
セキュリティの考慮事項
項目 | リスク | 対策 |
---|---|---|
認証情報の管理 | ハードコーディングによる漏洩 | GitHub Secretsで暗号化管理 |
最小権限の原則 | 過剰な権限による被害拡大 | デプロイ専用IAMロール |
監査ログ | 不正アクセスの見逃し | CloudTrailで操作記録 |
ブランチ保護 | 意図しない変更のマージ | 保護ルールとレビュー必須化 |
今回作成するリソース
リソース | 説明 | 数量 |
---|---|---|
GitHub Actions Workflow | CI/CDパイプライン定義 | 3個 |
IAM Role (GitHub Actions用) | OIDCによる認証 | 1個 |
IAM Policy | 必要最小限の権限 | 複数 |
S3 Bucket (アーティファクト保存) | ビルド結果の保存 | 1個 |
Parameter Store | 環境変数の管理 | 複数 |
Terraformコードの実装
変数の追加
CI/CD関連の変数を追加します。
# terraform/variables.tf に追加
# CI/CD関連
variable "enable_github_oidc" {
description = "GitHub Actions OIDCを有効にするか"
type = bool
default = true
}
variable "artifact_retention_days" {
description = "build artifact の保持期間"
type = number
default = 30
}
variable "github_repository" {
description = "GitHubリポジトリ(例: username/repository-name)"
type = string
default = ""
}
GitHub Actions用IAMロール(OIDC)
アクセスキーを使わず、OIDCで安全に認証します。
# terraform/cicd.tf
# GitHub OIDC Provider
resource "aws_iam_openid_connect_provider" "github" {
url = "https://token.actions.githubusercontent.com"
client_id_list = [
"sts.amazonaws.com"
]
# GitHub OIDCプロバイダーのサムプリント
thumbprint_list = [
"6938fd4d98bab03faadb97b34396831e3780aea1",
"1c58a3a8518e8759bf075b76b750d4f2df264fcd"
]
tags = {
Name = "${var.project_name}-${var.environment}-github-oidc"
}
}
# GitHub Actions用IAMロール
resource "aws_iam_role" "github_actions" {
count = var.enable_github_oidc ? 1 : 0
name = "${var.project_name}-${var.environment}-github-actions"
assume_role_policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Principal = {
Federated = aws_iam_openid_connect_provider.github.arn
}
Action = "sts:AssumeRoleWithWebIdentity"
Condition = {
StringEquals = {
"token.actions.githubusercontent.com:aud" = "sts.amazonaws.com"
}
StringLike = {
# GitHubリポジトリを指定
"token.actions.githubusercontent.com:sub" = "repo:${var.github_repository}:*"
}
}
}
]
})
tags = {
Name = "${var.project_name}-${var.environment}-github-actions"
}
}
OIDC設定パラメータの説明
パラメータ | 設定値 | 設定理由 |
---|---|---|
url | token.actions.githubusercontent.com | GitHub ActionsのOIDCプロバイダーURL |
client_id_list | sts.amazonaws.com | AWSのSTSサービスをクライアントとして指定 |
thumbprint_list | GitHub公式の値 | SSL証明書の検証用フィンガープリント |
Condition.StringLike | repo:org/repo:* | 特定リポジトリからのアクセスのみ許可 |
デプロイ用IAMポリシー
GitHub Actionsに必要な権限を付与します。
# terraform/cicd.tf
# GitHub Actions用のIAMポリシー
resource "aws_iam_role_policy" "github_actions" {
count = var.enable_github_oidc ? 1 : 0
name = "${var.project_name}-${var.environment}-github-actions-policy"
role = aws_iam_role.github_actions[0].id
policy = jsonencode({
Version = "2012-10-17"
Statement = [
# ECR関連の権限
{
Effect = "Allow"
Action = [
"ecr:GetAuthorizationToken",
"ecr:BatchCheckLayerAvailability",
"ecr:GetDownloadUrlForLayer",
"ecr:BatchGetImage",
"ecr:PutImage",
"ecr:InitiateLayerUpload",
"ecr:UploadLayerPart",
"ecr:CompleteLayerUpload"
]
Resource = [
aws_ecr_repository.app.arn,
"${aws_ecr_repository.app.arn}/*"
]
},
{
Effect = "Allow"
Action = [
"ecr:GetAuthorizationToken"
]
Resource = "*"
},
# ECS関連の権限
{
Effect = "Allow"
Action = [
"ecs:UpdateService",
"ecs:DescribeServices",
"ecs:DescribeTasks",
"ecs:ListTasks",
"ecs:RegisterTaskDefinition",
"ecs:DescribeTaskDefinition"
]
Resource = "*"
},
# S3関連の権限(フロントエンド用)
{
Effect = "Allow"
Action = [
"s3:PutObject",
"s3:PutObjectAcl",
"s3:GetObject",
"s3:DeleteObject",
"s3:ListBucket"
]
Resource = [
aws_s3_bucket.frontend.arn,
"${aws_s3_bucket.frontend.arn}/*"
]
},
# CloudFront関連の権限
{
Effect = "Allow"
Action = [
"cloudfront:CreateInvalidation"
]
Resource = aws_cloudfront_distribution.frontend.arn
},
# IAM PassRole権限(ECSタスク実行用)
{
Effect = "Allow"
Action = [
"iam:PassRole"
]
Resource = [
aws_iam_role.ecs_execution_role.arn,
aws_iam_role.ecs_task_role.arn
]
}
]
})
}
# ECRへのプッシュ権限
resource "aws_iam_role_policy" "github_actions_ecr" {
count = var.enable_github_oidc ? 1 : 0
name = "${var.project_name}-${var.environment}-github-ecr"
role = aws_iam_role.github_actions[0].id
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Action = [
"ecr:GetAuthorizationToken",
"ecr:BatchCheckLayerAvailability",
"ecr:GetDownloadUrlForLayer",
"ecr:BatchGetImage",
"ecr:PutImage",
"ecr:InitiateLayerUpload",
"ecr:UploadLayerPart",
"ecr:CompleteLayerUpload"
]
Resource = [
aws_ecr_repository.app.arn,
"${aws_ecr_repository.app.arn}/*"
]
},
{
Effect = "Allow"
Action = [
"ecr:GetAuthorizationToken"
]
Resource = "*"
}
]
})
}
# ECSデプロイ権限
resource "aws_iam_role_policy" "github_actions_ecs" {
count = var.enable_github_oidc ? 1 : 0
name = "${var.project_name}-${var.environment}-github-ecs"
role = aws_iam_role.github_actions[0].id
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Action = [
"ecs:UpdateService",
"ecs:DescribeServices",
"ecs:DescribeTaskDefinition",
"ecs:RegisterTaskDefinition",
"ecs:ListTaskDefinitions",
"ecs:DescribeClusters"
]
Resource = [
aws_ecs_cluster.main.arn,
aws_ecs_service.app.id,
"arn:aws:ecs:${var.aws_region}:*:task-definition/${var.project_name}-${var.environment}-app:*"
]
},
{
Effect = "Allow"
Action = [
"iam:PassRole"
]
Resource = [
aws_iam_role.ecs_execution_role.arn,
aws_iam_role.ecs_task_role.arn
]
}
]
})
}
# S3とCloudFrontデプロイ権限
resource "aws_iam_role_policy" "github_actions_frontend" {
count = var.enable_github_oidc ? 1 : 0
name = "${var.project_name}-${var.environment}-github-frontend"
role = aws_iam_role.github_actions[0].id
policy = jsonencode({
Version = "2012-10-17"
Statement = [
{
Effect = "Allow"
Action = [
"s3:PutObject",
"s3:PutObjectAcl",
"s3:GetObject",
"s3:DeleteObject",
"s3:ListBucket"
]
Resource = [
aws_s3_bucket.frontend.arn,
"${aws_s3_bucket.frontend.arn}/*"
]
},
{
Effect = "Allow"
Action = [
"cloudfront:CreateInvalidation"
]
Resource = aws_cloudfront_distribution.frontend.arn
}
]
})
}
IAMポリシー権限の説明
権限グループ | アクション | 必要な理由 |
---|---|---|
ECR権限 | PutImage, InitiateLayerUpload | Dockerイメージのプッシュ |
GetAuthorizationToken | ECRへのログイン | |
ECS権限 | UpdateService | 新しいタスク定義でサービス更新 |
RegisterTaskDefinition | 新しいタスク定義の登録 | |
PassRole | タスクロールの引き継ぎ | |
S3権限 | PutObject, DeleteObject | 静的ファイルのアップロード |
CloudFront権限 | CreateInvalidation | キャッシュの無効化 |
アーティファクト保存用S3バケット
ビルド結果を保存するバケットを作成します。
# terraform/cicd.tf
# アーティファクト保存用S3バケット
resource "aws_s3_bucket" "artifacts" {
bucket = "${var.project_name}-${var.environment}-artifacts"
force_destroy = true
tags = {
Name = "${var.project_name}-${var.environment}-artifacts"
}
}
# バケットの暗号化
resource "aws_s3_bucket_server_side_encryption_configuration" "artifacts" {
bucket = aws_s3_bucket.artifacts.id
rule {
apply_server_side_encryption_by_default {
sse_algorithm = "AES256"
}
}
}
# ライフサイクルポリシー
resource "aws_s3_bucket_lifecycle_configuration" "artifacts" {
bucket = aws_s3_bucket.artifacts.id
rule {
id = "delete-old-artifacts"
status = "Enabled"
filter {}
expiration {
days = var.artifact_retention_days
}
}
}
Parameter Store
環境変数を安全に管理します。
# terraform/cicd.tf
# デプロイ設定をParameter Storeに保存
resource "aws_ssm_parameter" "ecr_repository_url" {
name = "/${var.project_name}/${var.environment}/ecr-repository-url"
type = "String"
value = aws_ecr_repository.app.repository_url
tags = {
Name = "${var.project_name}-${var.environment}-ecr-url"
}
}
resource "aws_ssm_parameter" "ecs_cluster_name" {
name = "/${var.project_name}/${var.environment}/ecs-cluster-name"
type = "String"
value = aws_ecs_cluster.main.name
tags = {
Name = "${var.project_name}-${var.environment}-ecs-cluster"
}
}
resource "aws_ssm_parameter" "ecs_service_name" {
name = "/${var.project_name}/${var.environment}/ecs-service-name"
type = "String"
value = aws_ecs_service.app.name
tags = {
Name = "${var.project_name}-${var.environment}-ecs-service"
}
}
出力の追加
# terraform/outputs.tf に追加
# CI/CD関連の出力
output "github_actions_role_arn" {
description = "GitHub Actions用IAMロールARN"
value = var.enable_github_oidc ? aws_iam_role.github_actions[0].arn : ""
}
output "artifacts_bucket_name" {
description = "アーティファクト保存用S3バケット名"
value = aws_s3_bucket.artifacts.id
}
GitHub Actionsワークフローの作成
今回はdevelopブランチに、dev環境としてデプロイするように整備していきます。
自身もAIに手伝ってもらいつつCI/CDを書いたので、各々の環境に合わせて試行錯誤してみてください。
バックエンドAPI用ワークフロー
テストは書いていないので一旦コメントアウトです。
https://github.com/Yutahhhhh/aws-hands-on/blob/tf-dev/.github/workflows/backend-deploy.yml
# .github/workflows/backend-deploy.yml
name: Backend Deploy
on:
push:
branches:
- develop
paths:
- 'backend/**'
- '.github/workflows/backend-deploy.yml'
workflow_dispatch:
env:
AWS_REGION: ap-northeast-1
PROJECT_NAME: ${{ vars.PROJECT_NAME }}
ENVIRONMENT: dev
permissions:
id-token: write
contents: read
jobs:
# test:
# runs-on: ubuntu-latest
# steps:
# - uses: actions/checkout@v4
# - name: Setup pnpm
# uses: pnpm/action-setup@v4
# with:
# version: 9
# - name: Setup Node.js
# uses: actions/setup-node@v4
# with:
# node-version: '20'
# cache: 'pnpm'
# cache-dependency-path: backend/pnpm-lock.yaml
# - name: Install dependencies
# working-directory: backend
# run: pnpm install --frozen-lockfile
# - name: Run tests
# working-directory: backend
# run: pnpm test
# - name: Run linter
# working-directory: backend
# run: pnpm run lint
build-and-push:
# needs: test
runs-on: ubuntu-latest
outputs:
image-uri: ${{ steps.image.outputs.uri }}
steps:
- uses: actions/checkout@v4
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
role-session-name: github-actions
aws-region: ${{ env.AWS_REGION }}
- name: Login to Amazon ECR
id: login-ecr
uses: aws-actions/amazon-ecr-login@v2
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v3
- name: Docker meta
id: meta
uses: docker/metadata-action@v5
with:
images: ${{ steps.login-ecr.outputs.registry }}/${{ env.PROJECT_NAME }}-${{ env.ENVIRONMENT }}-app
tags: |
type=ref,event=branch
type=sha,prefix={{date 'YYYYMMDD'}}-
- name: Extract single image URI
id: image
run: |
# 最初のタグを取得(通常はsha形式のタグ)
IMAGE_URI=$(echo "${{ steps.meta.outputs.tags }}" | head -n1)
echo "uri=${IMAGE_URI}" >> $GITHUB_OUTPUT
- name: Build and push Docker image
uses: docker/build-push-action@v5
with:
context: backend
push: true
tags: ${{ steps.meta.outputs.tags }}
cache-from: type=gha
cache-to: type=gha,mode=max
platforms: linux/amd64
deploy:
needs: build-and-push
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
role-session-name: github-actions
aws-region: ${{ env.AWS_REGION }}
- name: Get current task definition
run: |
aws ecs describe-task-definition \
--task-definition ${{ env.PROJECT_NAME }}-${{ env.ENVIRONMENT }}-app \
--query taskDefinition > task-definition.json
- name: Update task definition
id: task-def
uses: aws-actions/amazon-ecs-render-task-definition@v1
with:
task-definition: task-definition.json
container-name: ${{ env.PROJECT_NAME }}-${{ env.ENVIRONMENT }}-app
image: ${{ needs.build-and-push.outputs.image-uri }}
- name: Deploy to ECS
uses: aws-actions/amazon-ecs-deploy-task-definition@v1
with:
task-definition: ${{ steps.task-def.outputs.task-definition }}
service: ${{ env.PROJECT_NAME }}-${{ env.ENVIRONMENT }}-app-service
cluster: ${{ env.PROJECT_NAME }}-${{ env.ENVIRONMENT }}-cluster
wait-for-service-stability: true
フロントエンド用ワークフロー
テストは書いていないので一旦コメントアウトです。
https://github.com/Yutahhhhh/aws-hands-on/blob/tf-dev/.github/workflows/frontend-deploy.yml
# .github/workflows/frontend-deploy.yml
name: Frontend Deploy
on:
push:
branches:
- develop
paths:
- 'frontend/**'
- '.github/workflows/frontend-deploy.yml'
workflow_dispatch:
env:
AWS_REGION: ap-northeast-1
PROJECT_NAME: ${{ vars.PROJECT_NAME }}
ENVIRONMENT: dev
permissions:
id-token: write
contents: read
jobs:
# test:
# runs-on: ubuntu-latest
# steps:
# - uses: actions/checkout@v4
# - name: Setup Node.js
# uses: actions/setup-node@v4
# with:
# node-version: '20'
# cache: 'npm'
# cache-dependency-path: frontend/package-lock.json
# - name: Install dependencies
# working-directory: frontend
# run: npm ci
# - name: Run tests
# working-directory: frontend
# run: npm test
build-and-deploy:
# needs: test
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup pnpm
uses: pnpm/action-setup@v2
with:
version: 8
run_install: false
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'pnpm'
cache-dependency-path: frontend/pnpm-lock.yaml
- name: Get pnpm store directory
shell: bash
run: |
echo "STORE_PATH=$(pnpm store path --silent)" >> $GITHUB_ENV
- name: Setup pnpm cache
uses: actions/cache@v3
with:
path: ${{ env.STORE_PATH }}
key: ${{ runner.os }}-pnpm-store-${{ hashFiles('frontend/pnpm-lock.yaml') }}
restore-keys: |
${{ runner.os }}-pnpm-store-
- name: Install dependencies
working-directory: frontend
run: pnpm install --frozen-lockfile
- name: Build application
working-directory: frontend
run: pnpm run build
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
role-session-name: github-actions
aws-region: ${{ env.AWS_REGION }}
- name: Deploy to S3
run: |
aws s3 sync frontend/dist s3://${{ env.PROJECT_NAME }}-${{ env.ENVIRONMENT }}-frontend \
--delete \
--cache-control "public, max-age=31536000" \
--exclude "index.html" \
--exclude "*.json"
aws s3 cp frontend/dist/index.html s3://${{ env.PROJECT_NAME }}-${{ env.ENVIRONMENT }}-frontend/ \
--cache-control "public, max-age=300"
- name: Invalidate CloudFront cache
run: |
DISTRIBUTION_ID=$(aws cloudfront list-distributions \
--query "DistributionList.Items[?Comment=='${{ env.PROJECT_NAME }} frontend distribution'].Id" \
--output text)
aws cloudfront create-invalidation \
--distribution-id $DISTRIBUTION_ID \
--paths "/*"
Terraform適用用ワークフロー
今回はコードとしてサンプルを用意していませんが、以下のようなコードが想定されると思います。
検証外で、terraformによるリソースの変更が頻繁に変わる場合はCI/CD化しておくと便利です。
# .github/workflows/terraform.yml
name: Terraform
on:
pull_request:
paths:
- 'terraform/**'
- '.github/workflows/terraform.yml'
push:
branches:
- main
paths:
- 'terraform/**'
env:
AWS_REGION: ap-northeast-1
TF_VERSION: 1.5.7
permissions:
id-token: write
contents: read
pull-requests: write
jobs:
plan:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Terraform
uses: hashicorp/setup-terraform@v3
with:
terraform_version: ${{ env.TF_VERSION }}
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
role-session-name: github-actions
aws-region: ${{ env.AWS_REGION }}
- name: Terraform Init
working-directory: terraform
run: terraform init -backend-config=backend.hcl
- name: Terraform Format Check
working-directory: terraform
run: terraform fmt -check
- name: Terraform Validate
working-directory: terraform
run: terraform validate
- name: Terraform Plan
id: plan
working-directory: terraform
run: terraform plan -no-color -out=tfplan
continue-on-error: true
- name: Comment PR
if: github.event_name == 'pull_request'
uses: actions/github-script@v7
with:
script: |
const output = `#### Terraform Plan 📖
\`\`\`
${{ steps.plan.outputs.stdout }}
\`\`\`
`;
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: output
});
apply:
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
needs: plan
runs-on: ubuntu-latest
environment: production
steps:
- uses: actions/checkout@v4
- name: Setup Terraform
uses: hashicorp/setup-terraform@v3
with:
terraform_version: ${{ env.TF_VERSION }}
- name: Configure AWS credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
role-session-name: github-actions
aws-region: ${{ env.AWS_REGION }}
- name: Terraform Init
working-directory: terraform
run: terraform init -backend-config=backend.hcl
- name: Terraform Apply
working-directory: terraform
run: terraform apply -auto-approve
環境変数の設定
# .env 追記
# GitHubのユーザー名またはOrganization名/GitHubリポジトリ名
TF_VAR_github_repository="ORG/repo"
今回環境変数を設定するため、以下のコマンドで再起動。
# exitで抜けた後に
docker-compose run --rm terraform
リソースを作成
Terraformコンテナ内で以下のコマンドを実行します。
# terraformディレクトリへ移動
cd terraform
# 実行計画の確認
terraform plan
# リソースの作成
terraform apply
GitHubリポジトリの設定
Secretsの設定
GitHubリポジトリの Settings > Secrets and variables > Actions で以下を設定します。
# IAMロールのARNを取得
terraform output github_actions_role_arn
Secret名 | 値 | 説明 |
---|---|---|
AWS_ROLE_ARN | arn:aws:iam::… | GitHub Actions用IAMロールのARN |
Variablesの設定
GitHubリポジトリの Settings > Secrets and variables > Actions > Variables で設定します。
これはterraformの環境変数(TF_VAR_project_name)で設定しているやつです。
Variable名 | 値 | 説明 |
---|---|---|
PROJECT_NAME | your-project | プロジェクト名 |
ブランチ保護ルール(推奨)
Settings > Branches で main ブランチの保護ルールを設定します。
ルール | 設定 | 理由 |
---|---|---|
Require pull request reviews | 有効 | 直接プッシュを防止 |
Require status checks | 有効 | テスト成功を必須化 |
Include administrators | 有効 | 管理者も例外なし |
Allow force pushes | 無効 | 履歴の改変を防止 |
動作確認
CI/CDのコードからデプロイされたことを確認したら、ディストリビューションドメイン名(https://d2vxxxxxxxx.cloudfront.net/)からアクセスして確認してみましょう。
基本的にはここでCRUDが機能していればOKです。
デプロイの確認
# ECSタスクの更新確認
aws ecs describe-services \
--cluster $(terraform output -raw ecs_cluster_id) \
--services $(terraform output -raw ecs_service_name) \
--query 'services[0].deployments[*].[status,taskDefinition,desiredCount,runningCount]' \
--output table
# CloudFront無効化の確認
aws cloudfront list-invalidations \
--distribution-id $(terraform output -raw cloudfront_distribution_id) \
--query 'InvalidationList.Items[0:3].[Id,Status,CreateTime]' \
--output table
ビルドアーティファクトの確認
# S3バケット内のアーティファクト確認
aws s3 ls s3://$(terraform output -raw artifacts_bucket_name)/ --recursive | head -10
トラブルシューティング
OIDC認証エラー
エラー | 原因 | 対処方法 |
---|---|---|
Error assuming role | IAMロールの信頼関係設定ミス | リポジトリ名の確認、sub条件の修正 |
Invalid OIDC token | OIDCプロバイダー未作成 | terraform applyでプロバイダー作成 |
AccessDenied | 権限不足 | IAMポリシーの見直し |
デプロイエラー
エラー | 原因 | 対処方法 |
---|---|---|
Task definition not found | タスク定義の名前相違 | 環境変数PROJECT_NAMEの確認 |
Service update failed | ヘルスチェック失敗 | アプリケーションログ確認 |
ECR push denied | ECRリポジトリ権限なし | IAMポリシーにECR権限追加 |
コスト管理
サービス | 項目 | 料金 |
---|---|---|
GitHub Actions | 実行時間(プライベートリポジトリ) | 2,000分/月まで無料 |
S3 (アーティファクト) | ストレージ | $0.025/GB・月 |
Parameter Store | 標準パラメータ | 無料 |
CloudWatch Logs | ログ保存 | $0.50/GB・月 |
開発環境では、以下の方法でコストを削減できます。
# terraform.tfvars
artifact_retention_days = 7 # アーティファクトを7日で削除
次のステップ
次回は、本番運用とスケーリングの設定を行います。
- Terraformコードのモジュール化
- 環境別設定
- Auto Scalingの設定
- RDS Performance Insightsの活用
- 復旧計画の策定