Lambda CI/CD アーキテクチャ - 2. 構成要素と役割

ドキュメント構成

免責事項

本記事はAI(Claude)を活用して執筆しています。内容の正確性については保証いたしかねますので、重要な情報は必ず一次情報源をご確認ください。


この章で理解すること

システム全体の構成と、各コンポーネントの責任範囲を明確にします。

  • アーキテクチャ全体図
  • リポジトリ構成
  • Terraform vs Lambrollの責任境界
  • リソース配置のルール
  • エイリアス管理の実際

システム全体図

アーキテクチャ概要

システム構成図

主要コンポーネント:

  1. GitHub Organization(2リポジトリ)

    • terraform-infrastructure: インフラ管理
    • lambda-applications: Lambda関数管理
  2. AWS Account

    • Terraform管理リソース(VPC、IAM、RDS等)
    • Lambda Functions + Versions + Aliases
    • S3(アーティファクト保管)
  3. 連携

    • Terraform outputs → 環境変数 → Lambroll

CI/CDフロー

CI/CDフロー図

3つのフェーズ:

  1. Development Flow: コミット → 自動デプロイ → staging環境
  2. Release Flow: 手動承認 → production環境
  3. Canary Release: 段階的トラフィック制御(10% → 100%)

リポジトリ構成

terraform-infrastructure(インフラリポジトリ)

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
terraform-infrastructure/
├── .github/workflows/
│ ├── terraform-plan.yml # PR時: plan実行
│ └── terraform-apply.yml # main merge時: apply実行

├── environments/
│ ├── production/
│ │ ├── backend.tf
│ │ ├── terraform.tfvars
│ │ └── main.tf
│ ├── staging/
│ └── development/

├── modules/
│ ├── vpc/
│ ├── rds/
│ ├── lambda-role/
│ └── lambda-layer/ # LayerのARN管理

├── iam/
│ ├── lambda-roles.tf # Lambda実行ロール
│ └── outputs.tf

├── vpc/
│ ├── main.tf
│ ├── subnets.tf
│ ├── security-groups.tf
│ └── outputs.tf

├── data-stores/
│ ├── rds.tf
│ ├── dynamodb.tf
│ └── s3.tf

├── messaging/
│ ├── sqs.tf
│ ├── sns.tf
│ └── eventbridge.tf

├── layers/ # Lambda Layer管理
│ ├── dependencies/
│ │ └── layer.tf
│ └── company-utils/
│ └── layer.tf

└── outputs.tf # 全体のoutput定義

Terraformの責任:

  • インフラストラクチャ全般
  • Lambda Layer(ARNのみ)
  • outputs経由でLambrollに情報提供

lambda-applications(アプリケーションリポジトリ)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
lambda-applications/
├── .github/workflows/
│ ├── deploy-staging.yml # mainへのpush → staging自動デプロイ
│ ├── deploy-production.yml # 手動承認 → production
│ └── cleanup-versions.yml # 週次: 古いVersion削除

├── functions/
│ ├── user-auth/
│ │ ├── function.jsonl # Lambroll設定
│ │ ├── index.py # 関数コード
│ │ ├── requirements.txt
│ │ └── tests/
│ ├── order-processing/
│ │ ├── function.jsonl
│ │ └── index.py
│ └── payment-service/

├── scripts/
│ ├── cleanup-old-versions.py # Version削除スクリプト
│ └── canary-release.sh # カナリアリリース

└── README.md

Lambrollの責任:

  • Lambda関数のコードとfunction.jsonl
  • エイリアス管理
  • デプロイ・バージョン発行

各コンポーネントの責任範囲

Terraform: インフラの真実の源泉

管理対象

カテゴリ リソース 理由
ネットワーク VPC、Subnet、Security Group インフラ基盤
IAM Lambda実行Role、Policy セキュリティ重要
データストア RDS、DynamoDB(共有)、S3 複数サービスで使用
メッセージング SQS/SNS(共有)、EventBridge 複数サービスで使用
Layer Lambda Layer(ARN管理) 依存関係の一元管理
シークレット Secrets Manager セキュリティ重要

Terraform outputs(Lambrollへの情報提供)

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
# outputs.tf

# IAM
output "lambda_role_arn" {
description = "Lambda execution role ARN"
value = aws_iam_role.lambda_execution.arn
}

# VPC
output "private_subnet_ids" {
description = "Private subnet IDs for Lambda"
value = aws_subnet.private[*].id
}

output "lambda_security_group_ids" {
description = "Security group IDs for Lambda"
value = [aws_security_group.lambda.id]
}

# RDS
output "rds_endpoint" {
description = "RDS endpoint"
value = aws_db_instance.main.endpoint
sensitive = true
}

# Lambda Layer
output "layer_arns" {
description = "Lambda Layer ARNs"
value = {
dependencies = aws_lambda_layer_version.dependencies.arn
company_utils = aws_lambda_layer_version.company_utils.arn
}
}

# S3
output "artifact_bucket" {
description = "S3 bucket for Lambda artifacts"
value = aws_s3_bucket.artifacts.id
}

Lambroll: Lambda関数に特化

管理対象

  • Lambda関数のコード
  • function.jsonl(関数設定)
  • エイリアス(development、staging、production)

function.jsonl の構造

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
{
"FunctionName": "user-auth-function",
"Runtime": "python3.11",
"Handler": "index.handler",
"MemorySize": 512,
"Timeout": 30,
"Role": "{{ must_env `TF_ROLE_ARN` }}",
"Layers": {{ env `TF_LAYER_ARNS` | json_array }},
"VpcConfig": {
"SubnetIds": {{ env `TF_SUBNET_IDS` | json_array }},
"SecurityGroupIds": {{ env `TF_SG_IDS` | json_array }}
},
"Environment": {
"Variables": {
"DB_ENDPOINT": "{{ must_env `TF_RDS_ENDPOINT` }}",
"LOG_LEVEL": "INFO"
}
}
}

ポイント:

  • {{ must_env }}: 環境変数から必須値を取得
  • {{ env }}: 環境変数から任意値を取得
  • | json_array: 配列に変換

GitHub Actions: CI/CDパイプライン

Staging自動デプロイ

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
# .github/workflows/deploy-staging.yml

name: Deploy to Staging

on:
push:
branches: [main]
paths:
- 'functions/**'

jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4

# Terraform outputsを取得
- name: Get Terraform outputs
run: |
cd ../terraform-infrastructure
terraform output -json > outputs.json

# 環境変数に設定
echo "TF_ROLE_ARN=$(jq -r '.lambda_role_arn.value' outputs.json)" >> $GITHUB_ENV
echo "TF_SUBNET_IDS=$(jq -r '.private_subnet_ids.value | @json' outputs.json)" >> $GITHUB_ENV
echo "TF_SG_IDS=$(jq -r '.lambda_security_group_ids.value | @json' outputs.json)" >> $GITHUB_ENV

# Lambrollデプロイ
- name: Deploy with Lambroll
run: |
cd functions/user-auth
lambroll deploy --log-level info

# Versionを発行
- name: Publish Version
id: version
run: |
VERSION=$(aws lambda publish-version \
--function-name user-auth-function \
--description "Commit: ${{ github.sha }}" \
--query 'Version' --output text)
echo "version=$VERSION" >> $GITHUB_OUTPUT

# staging エイリアスを更新
- name: Update staging alias
run: |
aws lambda update-alias \
--function-name user-auth-function \
--name staging \
--function-version ${{ steps.version.outputs.version }}

Production手動リリース

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
# .github/workflows/deploy-production.yml

name: Release to Production

on:
workflow_dispatch:
inputs:
function_name:
description: 'Function name'
required: true
version:
description: 'Version number to release'
required: true

jobs:
release:
runs-on: ubuntu-latest
environment: production # 手動承認が必要
steps:
- name: Update production alias
run: |
aws lambda update-alias \
--function-name ${{ inputs.function_name }} \
--name production \
--function-version ${{ inputs.version }}

- name: Notify Slack
run: |
# Slack通知処理

リソース配置のルール

判断フローチャート

Q1: 変更頻度は?

  • 週1回以上 → Q2へ
  • 月1回以下 → Terraform

Q2: 共有されるか?

  • 複数サービスで使用 → Terraform
  • Lambda専用 → Lambroll

Q3: セキュリティ重要度は?

  • 高い → Terraform
  • 普通 → Lambroll

リソース配置マトリックス

リソース 配置 理由
IAMロール Terraform セキュリティ、共有
VPC/Subnet/SG Terraform インフラ基盤
RDS/DynamoDB(共有) Terraform 複数サービスで使用
S3(共有) Terraform 複数サービスで使用
Secrets Manager Terraform セキュリティ
EventBridge Pipes Terraform 共有、監視重要
SQS/SNS(共有) Terraform 複数サービスで使用
Lambda関数 Lambroll 頻繁に変更
Lambda Layer Terraform 依存関係の一元管理
SQS/SNS(専用) Lambroll 関数と密結合
EventBridge(専用) Lambroll 関数と密結合

注意: Layerについて

LayerはTerraformで管理します。理由:

  • 変更頻度が低い(依存関係の更新は月1回程度)
  • 複数の関数で共有される
  • ARNをoutputsで提供 → Lambrollが参照

エイリアス管理戦略

エイリアス構成の実際

1
2
3
4
5
6
7
8
9
10
11
12
user-auth-function

├── Versions
│ ├── $LATEST
│ ├── 1, 2, 3, ..., 14
│ ├── 15(現在の production)
│ └── 16(最新、staging で検証中)

└── Aliases
├── development → $LATEST
├── staging → 16
└── production → 15

各環境のエイリアス戦略

Development

1
2
3
4
5
# 常に $LATEST を参照
aws lambda create-alias \
--function-name user-auth-function \
--name development \
--function-version '$LATEST'

特徴:

  • 最新コードを即座に反映
  • 不安定でも問題なし
  • デバッグ用

Staging

1
2
3
4
5
6
7
# デプロイ時に自動更新
VERSION=$(aws lambda publish-version ...)

aws lambda update-alias \
--function-name user-auth-function \
--name staging \
--function-version $VERSION

特徴:

  • mainへのpushで自動更新
  • QA・統合テスト用
  • 本番リリース前の最終確認

Production

1
2
3
4
5
# 手動承認後に更新
aws lambda update-alias \
--function-name user-auth-function \
--name production \
--function-version 16

特徴:

  • 手動承認が必須
  • エンドユーザー向け
  • 最も慎重に管理

カナリアリリース(段階的展開)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# Phase 1: 10%のトラフィックを新バージョンに
aws lambda update-alias \
--function-name user-auth-function \
--name production \
--function-version 16 \
--routing-config AdditionalVersionWeights={15=0.9}

# 10分間監視
sleep 600

# Phase 2: 問題なければ100%に
aws lambda update-alias \
--function-name user-auth-function \
--name production \
--function-version 16

連携メカニズム

Terraform → Lambroll の情報伝達

1. Terraform outputsを出力

1
2
cd terraform-infrastructure
terraform output -json > outputs.json

2. 環境変数に設定

1
2
3
export TF_ROLE_ARN=$(jq -r '.lambda_role_arn.value' outputs.json)
export TF_SUBNET_IDS=$(jq -r '.private_subnet_ids.value | @json' outputs.json)
export TF_LAYER_ARNS=$(jq -r '.layer_arns.value | to_entries | map(.value) | @json' outputs.json)

3. Lambrollがfunction.jsonlで参照

1
2
3
4
{
"Role": "{{ must_env `TF_ROLE_ARN` }}",
"Layers": {{ env `TF_LAYER_ARNS` | json_array }}
}

メリット:

  • SSM Parameter Store不要
  • シンプルで高速
  • Terraformが単一の真実の源泉

まとめ

責任範囲の明確化

コンポーネント 責任 変更頻度 管理チーム
Terraform インフラ全般 インフラチーム
Lambroll Lambda関数 アプリチーム
GitHub Actions CI/CD 両チーム

連携の要点

  1. Terraform outputsが橋渡し役
  2. stagingは自動、productionは手動
  3. エイリアスで環境を完全分離
  4. バージョンは不変、ロールバック容易

次のステップ

構成要素を理解したら、実装の詳細に進みましょう。

次へ: 3. 実装ガイドライン