はじめに
本記事では、CodeCommitで管理する単一リポジトリ(モノレポ)において、
変更されたディレクトリに応じて、実行するCodePipelineを振り分けるCIパイプラインをTerraformで構築する方法について記載しています。
Terraform で構築する全体構成図
構成の概要
- Systems Managerの Parameter Storeには、
リポジトリ内のディレクトリ名
と実行する CodePipeline名
がJSON形式で格納されています。 - 開発者がCodeCommit のリポジトリにコードをプッシュすると EventBridgeがリポジトリの変更イベントを検知してLambda関数をトリガー実行します。
- Lambda関数は、Systems Managerのパラメータを読み取って、変更があったディレクトリに応じたCodePipeline を実行します。
- 変更があったディレクトリが複数の場合は、複数のCodePipelineが同時に実行されます。
Terraform のコードと構成
ディレクトリ構成
aws-tf-monorepo-codepipeline-trigger
├── main.tf
├── provider.tf
└── modules
├── codecommit
│ ├── codecommit.tf
│ └── variables.tf
├── codepipeline
│ ├── buildspec.yml
│ ├── codebuild.tf
│ ├── codepipeline.tf
│ ├── iam.tf
│ ├── s3.tf
│ └── variables.tf
├── eventbridge
│ ├── event_rule.tf
│ └── variables.tf
├── lambda
│ ├── dist
│ ├── iam.tf
│ ├── lambda.tf
│ ├── src
│ │ └── codepipeline_trigger.py
│ └── variables.tf
└── ssm
├── ssm.tf
└── variables.tf
main.tf
main.tf
locals {
aws_region = "ap-northeast-1"
repository_name = "monorepo"
branch_name = "main"
ssm_parameter_name = "codepipeline-trigger"
ssm_parameter_value = jsonencode({
"project1" : "project1-codepipeline",
"project2" : "project2-codepipeline"
})
event_rule_name = "monorepo-change-event"
function_name = "codepipeline-trigger"
project1_codepipeline_name = "project1-codepipeline"
project2_codepipeline_name = "project2-codepipeline"
}
module "ssm" {
source = "./modules/ssm"
ssm_parameter_name = local.ssm_parameter_name
ssm_parameter_value = local.ssm_parameter_value
}
module "codecommit" {
source = "./modules/codecommit"
repository_name = local.repository_name
}
module "eventbridge" {
source = "./modules/eventbridge"
event_rule_name = local.event_rule_name
function_name = local.function_name
repository_name = local.repository_name
branch_name = local.branch_name
}
module "lambda" {
source = "./modules/lambda"
function_name = local.function_name
ssm_parameter_name = local.ssm_parameter_name
}
module "project1_codepipeline" {
source = "./modules/codepipeline"
codepipeline_name = local.project1_codepipeline_name
repository_name = local.repository_name
branch_name = local.branch_name
}
module "project2_codepipeline" {
source = "./modules/codepipeline"
codepipeline_name = local.project2_codepipeline_name
repository_name = local.repository_name
branch_name = local.branch_name
}
CodePipeline を実行するLambda関数
codepipeline_trigger.py
import json
import boto3
import os
codepipeline = boto3.client('codepipeline')
ssm = boto3.client('ssm')
PARAMETER_NAME = os.environ['PARAMETER_NAME']
def lambda_handler(event, context):
project_pipelines = load_project_pipelines_from_parameter_store(PARAMETER_NAME)
commit_id = event['detail']['commitId']
repository_name = event['detail']['repositoryName']
changed_files = get_changed_files(repository_name, commit_id)
for project_dir, pipeline_name in project_pipelines.items():
if any(file.startswith(project_dir) for file in changed_files):
start_pipeline(pipeline_name)
def load_project_pipelines_from_parameter_store(parameter_name):
response = ssm.get_parameter(Name=parameter_name, WithDecryption=True)
parameter_value = response['Parameter']['Value']
project_pipelines = json.loads(parameter_value)
return project_pipelines
def get_changed_files(repository_name, commit_id):
codecommit = boto3.client('codecommit')
response = codecommit.get_commit(
repositoryName=repository_name,
commitId=commit_id
)
commit = response['commit']
parent_commit_id = commit['parents'][0]
response = codecommit.get_differences(
repositoryName=repository_name,
afterCommitSpecifier=commit_id,
beforeCommitSpecifier=parent_commit_id
)
changed_files = [difference['afterBlob']['path'] for difference in response['differences']]
return changed_files
def start_pipeline(pipeline_name):
response = codepipeline.start_pipeline_execution(name=pipeline_name)
print(f"Started pipeline: {pipeline_name}, executionId: {response['pipelineExecutionId']}")
本構成で想定しているCodedCommit リポジトリ
monorepo
├── project1
│ └── code
└── project2
└── code
使い方
Terraform の動作確認環境
$ terraform -version
Terraform v1.4.4
on darwin_amd64
+ provider registry.terraform.io/hashicorp/aws v4.62.0
変数の設定
main.tf
内の Local Values
を設定します。
変数名 | 説明 |
---|---|
aws_region | リージョン |
repository_name | リポジトリ名 |
branch_name | ブランチ名 |
ssm_parameter_name | SSMのParameter Storeのパラメータ名 |
ssm_parameter_value | リポジトリ内のディレクトリ名(Key)と実行する CodePipeline名(Value)をJSON形式で設定します |
event_rule_name | EventBridgeのイベントルール名 |
function_name | Lambda関数名 |
project1_codepipeline_name | CodePipeline名 |
project2_codepipeline_name | CodePipeline名 |
Terraform の実行
$ export AWS_PROFILE= [ YOUR AWS ACCOUNT PROFILE NAME ]
$ terraform init
$ terraform plan
Plan: 39 to add, 0 to change, 0 to destroy.
$ terraform apply
Apply complete! Resources: 39 added, 0 changed, 0 destroyed.
動作確認
以上で、変更されたディレクトリに応じて、実行するCodePipelineが振り分けられていることを確認できました。
さいごに
こちらは、あくまでサンプルコードになります。参考になれば幸いです。