SourceにECRをしたものを設定する機会があったので書いておきます。
SourceにGitHubを指定しているサンプルはよく見かけますが、ECRを指定しているものはあまりなかったので参考になれば。
CodePipeline
resource "aws_codepipeline" "example" {
name = "example"
role_arn = aws_iam_role.codepipeline.arn
artifact_store {
location = aws_s3_bucket.artifact.bucket
type = "S3"
}
stage {
name = "Source"
action {
name = "Source"
category = "Source"
owner = "AWS"
provider = "ECR"
version = "1"
output_artifacts = ["source"]
configuration = {
RepositoryName = "example"
ImageTag = "stage"
}
}
}
stage {
name = "Build"
action {
name = "Build"
category = "Build"
owner = "AWS"
provider = "CodeBuild"
version = "1"
input_artifacts = ["source"]
output_artifacts = ["build"]
configuration = {
ProjectName = aws_codebuild_project.example.id
}
}
}
stage {
name = "Deploy"
action {
name = "Deploy"
category = "Deploy"
owner = "AWS"
provider = "ECS"
input_artifacts = ["build"]
version = "1"
configuration = {
ClusterName = aws_ecs_cluster.example.arn
ServiceName = aws_ecs_service.ecample.name
FileName = "imagedefinitions.json"
}
}
}
}
Sourceの部分は provider = "ECR"
を設定して、configurationにトリガーしたいECRのリポジトリ名、イメージタグ名を設定します。(ImageTagはオプショナル)
ここでは example
リポジトリの stage
タグのプッシュをトリガーにする設定をしています。
buildspec.yml
version: 0.2
phases:
install:
runtime-versions:
python: 3.7
build:
commands:
- echo Build started on `date`
- REPOSITORY_URI=$(cat imageDetail.json | python -c "import sys, json; print(json.load(sys.stdin)['ImageURI'].split('@')[0])")
- IMAGE_TAG=$(cat imageDetail.json | python -c "import sys, json; print(json.load(sys.stdin)['ImageTags'][0])")
- echo $REPOSITORY_URI:$IMAGE_TAG
post_build:
commands:
- echo Build completed on `date`
- echo Writing image definitions file...
- printf '[{"name":"web","imageUri":"%s"}]' $REPOSITORY_URI:$IMAGE_TAG > imagedefinitions.json
artifacts:
files: imagedefinitions.json
output として imageDetail.json が生成されるので、そこから imagedefinitions.json を作成します。
ECS Blue/Greenデプロイを選択する場合は、imageDetail.json そのままで大丈夫かと思いますが、今回は標準デプロイを選択したので imagedefinitions.json を作成しています。
stackoverflow.com
これで設定完了!ECRにプッシュすればCodePipelineが起動する!
と思ったのですが、Terraform等から作成する場合はCloudWatch Events等は自前で用意しなきゃいけないんですね...(マネージメントコンソールから作成すれば勝手に作ってくれる)
docs.aws.amazon.com
CloudWatch Events & CloudTrail
data "aws_iam_policy_document" "cloudwatch_events" {
statement {
effect = "Allow"
resources = ["*"]
actions = [
"codepipeline:StartPipelineExecution"
]
}
}
data "aws_iam_policy_document" "cloudwatch_events_assume_role" {
statement {
actions = ["sts:AssumeRole"]
principals {
type = "Service"
identifiers = ["events.amazonaws.com"]
}
}
}
resource "aws_iam_role" "cloudwatch_events" {
name = "codepipeline-cloudwatch-events"
assume_role_policy = data.aws_iam_policy_document.cloudwatch_events_assume_role.json
}
resource "aws_iam_policy" "cloudwatch_events" {
name = "codepipeline-cloudwatch-events"
policy = data.aws_iam_policy_document.cloudwatch_events.json
}
resource "aws_iam_role_policy_attachment" "cloudwatch_events" {
role = aws_iam_role.cloudwatch_events.name
policy_arn = aws_iam_policy.cloudwatch_events.arn
}
resource "aws_cloudwatch_event_rule" "ecr" {
name = "codepipeline-ecr-event-rule"
description = "Amazon CloudWatch Events rule to automatically start your pipeline when a change occurs in the Amazon ECR image tag."
event_pattern = <<-JSON
{
"source": [
"aws.ecr"
],
"detail-type": [
"AWS API Call via CloudTrail"
],
"detail": {
"eventSource": [
"ecr.amazonaws.com"
],
"eventName": [
"PutImage"
],
"requestParameters": {
"repositoryName": [
"example"
],
"imageTag": [
"stage"
]
}
}
}
JSON
depends_on = ["aws_codepipeline.example"]
}
resource "aws_cloudwatch_event_target" "ecr" {
rule = aws_cloudwatch_event_rule.ecr.name
target_id = aws_cloudwatch_event_rule.ecr.name
arn = aws_codepipeline.example.arn
role_arn = aws_iam_role.cloudwatch_events.arn
}
data "aws_caller_identity" "current" {}
resource "aws_cloudtrail" "example" {
name = "example"
s3_bucket_name = aws_s3_bucket.example.id
event_selector {
read_write_type = "All"
include_management_events = true
data_resource {
type = "AWS::S3::Object"
values = ["arn:aws:s3:::"]
}
}
}
resource "aws_s3_bucket" "example" {
bucket = "cloudtrail"
acl = "private"
policy = <<-POLICY
{
"Version": "2012-10-17",
"Statement": [
{
"Sid": "AWSCloudTrailAclCheck",
"Effect": "Allow",
"Principal": {
"Service": "cloudtrail.amazonaws.com"
},
"Action": "s3:GetBucketAcl",
"Resource": "arn:aws:s3:::cloudtrail"
},
{
"Sid": "AWSCloudTrailWrite",
"Effect": "Allow",
"Principal": {
"Service": "cloudtrail.amazonaws.com"
},
"Action": "s3:PutObject",
"Resource": "arn:aws:s3:::cloudtrail/AWSLogs/${data.aws_caller_identity.current.account_id}/*",
"Condition": {
"StringEquals": {
"s3:x-amz-acl": "bucket-owner-full-control"
}
}
}
]
}
POLICY
}
CloudWatch Events の設定だけではうまくいかなくて、↓を参考に CloudTrail も設定したらうまくいきました!
https://forums.aws.amazon.com/thread.jspa?threadID=306306&tstart=0
今後もしかしたら CloudWatch Events の作成までしてくれる可能性もあるかも?
github.com
CodePipelineのことは書いてないですが、この本かなり良かったです!
Second Edition は v0.12 に対応していて、まだ 発売前 ですが O'Reilly の Safari Books Online では読めます!
www.oreilly.com
自分も Safari Books Online で読んだのですが、 Free Trial の 10日で読める分量だと思うのでもし興味があれば是非!