Amazon S3 へのソースコードの配置をトリガーにして AWS CodePipeline を動かす方法はいくつかあります。
- S3 を CodePipeline からポーリングして変更を検知する
- S3 への操作を CloudTrail で検知してイベントを発行して EventBridge 経由で CodePipeline を動作させる
- S3 からイベントを EventBridge に送って CodePipeline を動作させる
それぞれについて Terraform で書く場合の要点をまとめておきます。
なお、Terraform AWS Provider はv3を前提にした記述になっています(3番目の方法についてはv3.74.0以上が必要です)。v4などを使う場合は適宜読み替えてください。
また、CodePipeline を動かす部分に焦点を置いているため、
- S3 にどうソースコードを配置するか
- CodePipeline をどう設定するか(トリガーされたあとの挙動)
については省略するか簡易にしか記述しません。
S3 を CodePipeline からポーリングして変更を検知する
1番目の方法で、以前から利用できる方法です。勝手にポーリングしてくれるので簡単。
PollForSourceChanges
を true にすることで有効化できます。
たとえば以下のように記述します。
resource "aws_codepipeline" "my_pipeline" { name = "my-pipeline" role_arn = aws_iam_role.my_pipeline_role.arn artifact_store { location = aws_s3_bucket.my_source.bucket type = "S3" } stage { name = "Source" action { category = "Source" configuration = { PollForSourceChanges = "true" // ここが肝 S3Bucket = aws_s3_bucket.my_source_s3.bucket S3ObjectKey = "my_artifact.zip" } name = "Source" output_artifacts = ["SourceArtifact"] owner = "AWS" provider = "S3" run_order = "1" version = "1" } } stage { name = "Deploy" action { category = "Deploy" configuration = { ApplicationName = aws_codedeploy_app.my_deployment.name DeploymentGroupName = aws_codedeploy_deployment_group.my_deployment.deployment_group_name } input_artifacts = ["SourceArtifact"] name = "Deploy" owner = "AWS" provider = "CodeDeploy" run_order = "1" version = "1" } } }
S3 への操作を CloudTrail で検知してイベントを発行して EventBridge 経由で CodePipeline を動作させる
2番目のやり方です。前掲の公式ドキュメントで、1番目の方法よりも推奨されている方法です。イベントドリブンなので、ポーリングによる方法に比べて迅速に CodePipeline を起動することができます。
PollForSourceChanges
Required: No
PollForSourceChanges controls whether CodePipeline polls the Amazon S3 source bucket for source changes. We recommend that you use CloudWatch Events and CloudTrail to detect source changes instead. For more information about configuring CloudWatch Events, see Update pipelines for push events (Amazon S3 source) (CLI) or Update pipelines for push events (Amazon S3 source) (AWS CloudFormation template).
難点は設定が面倒なことで、AWS CloudTrail という典型的には監査などの目的で利用されるサービスを間に噛ませる必要があります。以下のような流れになります。
- S3 上のオブジェクトへの操作
- CloudTrail が検知
- CloudTrail がイベントを発行
- EventBridge で定義しておいたルールに基づいて CodePipeline を起動
こちらの方法を採用する場合は、二重でパイプラインが起動するのを避けるため、先述の PollForSourceChanges
を false に設定しておく必要があります。
1番目の方法で用いるリソースにさらに追加で以下のリソースが必要になります。
- CloudTrail
aws_cloudtrail
- CloudTrail のログ出力先となる S3 バケット
aws_s3_bucket
- バケットポリシーで CloudTrail からの読み書きを許可する必要があります
- 説明は省略します
- EventBridge のルール定義
aws_cloudwatch_event_rule
- EventBridge のイベントターゲット定義
aws_cloudwatch_event_target
- EventBridge が CodePipeline を起動するためのIAMロール
aws_iam_role
- 説明は省略します
CloudTrail はたとえば以下のように記述します。
resource "aws_cloudtrail" "start_my_pipeline" { name = "start-my-pipeline" s3_bucket_name = aws_s3_bucket.start_codepipeline.id // CloudTrailがログを出力する先のS3バケットを指定 event_selector { read_write_type = "WriteOnly" data_resource { type = "AWS::S3::Object" values = ["arn:aws:s3:::my_source_s3"] // ソースコードを配置する S3 を指定する } } }
EventBridge のルールとターゲットはそれぞれ以下のように記述します。
resource "aws_cloudwatch_event_rule" "start_my_pipeline" { name = "start-pipeline-from-s3-rule" event_pattern = <<EOF { "source": ["aws.s3"], "detail-type": ["AWS API Call via CloudTrail"], "detail": { "eventSource": ["s3.amazonaws.com"], "eventName": ["PutObject", "CompleteMultipartUpload", "CopyObject"], "requestParameters": { "bucketName": ["${aws_s3_bucket.my_source_s3.bucket}"], "key": ["my_artifact.zip"] } } } EOF }
resource "aws_cloudwatch_event_target" "start_pipeline" { rule = aws_cloudwatch_event_rule.start_my_pipeline.name arn = aws_codepipeline.my_pipeline.arn role_arn = aws_iam_role.my_pipeline_role_for_event_bridge.arn }
S3からイベントを EventBridge に送って CodePipeline を動作させる
3番目のやり方です。2021年11月のAWSのアップデートでサポートされた方法です。こちらでも PollForSourceChanges
は false に設定しておく必要があります。
S3 へのソースコードの配置のイベントを CloudTrail を介することなく直接 EventBridge に送ることができるようになりました。これにより、2番目の方法で必要だった CloudTrail 関係のリソースが不要になります。 CloudTrall は細かく設定ができるのですが、リソースの数などについての制約事項があるため、個人的にはあまりパイプラインのために利用するのは嬉しくないのでは?と感じています。とはいえ、 EventBridge への S3 からのイベント発行が CloudTrail でやる場合に比べて増えるというデメリットもこちらにはあります。
1番目の方法との差分として必要なリソースは、以下になります。
- EventBridge のルール定義
aws_cloudwatch_event_rule
- 少し設定の書き方が変わります
- EventBridge のイベントターゲット定義
aws_cloudwatch_event_target
- 2番目の方法と同じ
- EventBridge が CodePipeline を起動するためのIAMロール
aws_iam_role
- 2番目の方法と同じ
- 説明は省略します
- S3 から EventBridge への通知設定
aws_s3_bucket_notification
aws_cloudwatch_event_rule
はたとえば以下のように記述します。
resource "aws_cloudwatch_event_rule" "start_my_pipeline" { name = "start-pipeline-from-s3-rule" event_pattern = <<EOF { "source": ["aws.s3"], "detail-type": ["Object Created"], "detail": { "eventSource": ["s3.amazonaws.com"], "eventName": ["PutObject", "CompleteMultipartUpload", "CopyObject"], "bucket": { "name": ["${aws_s3_bucket.my_source_s3.bucket}"] }, "object": { "key": ["my_artifact.zip"] }, "reason": ["PutObject", "CompleteMultipartUpload", "CopyObject"] } } EOF }
また、 S3 から EventBridge へのイベント発行はデフォルトでは無効になっているので、 aws_s3_bucket_notification
を追加する必要があります。
resource "aws_s3_bucket_notification" "bucket_notification" { bucket = aws_s3_bucket.my_source_s3.id eventbridge = true }
なお、 aws_s3_bucket_notification
リソースの eventbridge
プロパティは、Terraform AWS provider の v3.74.0 以降でサポートされています。
Release v3.74.0 · hashicorp/terraform-provider-aws · GitHub
まとめ
この記事を執筆している2022年8月現在では、公式ドキュメント上は2番目の方法が推奨されているのですが、仕組みのシンプルさを欠いている印象が強く、ゆくゆくは3番目の方法や、それを更に発展させた方法が標準になっていくのではないかなと感じました。