概要
ECSで以下のようなざっくり要件でデプロイ準備してみた記録です。
- ECRにデプロイしたいタグイメージは事前に出来上がっている
- リリース担当者が任意のタイミングで手動デプロイ開始できる
- GitHubの特定ファイル更新でwebhookからデプロイ開始する形にもできる
出来上がりイメージ
ざっくりTerraform記載例
以下の環境で検証。
terraform v0.12.29
aws provider v2.69.0
github provider v2.9.2
ざっくり値はsampleになっていますが、イメージ的にはこんな感じ。
resource "aws_codepipeline" "sample" {
name = "sample"
role_arn = "arn:aws:iam::XXXXXXXXXXXX:role/SampleRole"
artifact_store {
type = "S3"
location = "sample-bucket"
}
stage {
name = "Source"
action {
name = "Source"
category = "Source"
owner = "ThirdParty"
provider = "GitHub"
version = "1"
output_artifacts = ["SourceArtifact"]
namespace = "SourceVariables"
configuration = {
Owner = "sample"
Repo = "sample-repo"
Branch = "master"
OAuthToken = aws_ssm_parameter.github_personal_access_token.value
PollForSourceChanges = "false"
}
}
}
stage {
name = "Deploy"
action {
name = "Deploy"
category = "Deploy"
owner = "AWS"
provider = "CodeDeployToECS"
version = "1"
input_artifacts = ["SourceArtifact"]
namespace = "DeployVariables"
configuration = {
AppSpecTemplateArtifact = "SourceArtifact"
AppSpecTemplatePath = "appspec.yml"
ApplicationName = "AppECS-cluster-sample-service"
DeploymentGroupName = "DgpECS-cluster-sample-service"
TaskDefinitionTemplateArtifact = "SourceArtifact"
TaskDefinitionTemplatePath = "taskdef.json"
}
}
}
lifecycle {
ignore_changes = [
stage[0].action[0].configuration
]
}
}
resource "random_id" "sample" {
keepers = {
codepipeline_name = aws_codepipeline.sample.name
}
byte_length = 32
}
resource "aws_codepipeline_webhook" "sample" {
name = "sample-webhook"
authentication = "GITHUB_HMAC"
target_action = "Source"
target_pipeline = aws_codepipeline.sample.name
authentication_configuration {
secret_token = random_id.sample.hex
}
filter {
json_path = "$.ref"
match_equals = "refs/heads/{Branch}"
}
filter {
json_path = "$.head_commit.modified.*"
match_equals = "placeholder-file"
}
}
resource "github_repository_webhook" "sample" {
repository = "sample-repo"
configuration {
url = aws_codepipeline_webhook.sample.url
content_type = "json"
insecure_ssl = false
secret = random_id.sample.hex
}
events = ["push"]
}
webhook部分の制御
CodePipelineがGitHubからのwebhook情報を受け取って判定している箇所は以下部分。
AWSのドキュメントだと、Branch部分が指定されているfilter例しか載っていないけれど、GitHubからはwebhook時に他の情報もやってくるので、それを使って判定条件にする。
resource "aws_codepipeline_webhook" "sample" {
〜略〜
filter {
json_path = "$.ref"
match_equals = "refs/heads/{Branch}"
}
filter {
json_path = "$.head_commit.modified.*"
match_equals = "placeholder-file"
}
}
上記だと、master
ブランチに変更があって、placeholder-file
というファイルに変更があった場合、CodePipeline側のデプロイが開始するような記述。
placeholder-file
が存在していなければ自動でデプロイは開始されないので手動開始が実現できる。
placeholder-file
をtaskdef.json
に変えておけば、イメージを更新したタスク定義でデプロイが自動開始される。
match_equals
の部分、正規表現使えると嬉しいケースがありそうだけど現状使えない模様。
https://stackoverflow.com/questions/56767494/aws-codepipeline-webhook-filter
https://docs.aws.amazon.com/codepipeline/latest/APIReference/API_WebhookFilterRule.html
webhookのシークレット情報
GitHubとCodePipelineのwebhook連携で使われているシークレット情報、どういう文字列でいいのかな?と思ってGitHubのドキュメントを見てもあまり具体的に載っていなかったので、サンプルを踏襲してhex文字列を使ってみています。
https://docs.github.com/en/developers/webhooks-and-events/securing-your-webhooks
resource "random_id" "sample" {
keepers = {
codepipeline_name = aws_codepipeline.sample.name
}
byte_length = 32
}
CodePipelineに設定するGitHub Personal Access Tokenの制御
検証したバージョンのaws provider(v2.69.0)だと、OAuthToken
部分の更新が毎回走ってしまうので、無理矢理感あるけど以下のように制御入れてある感じ。
lifecycle {
ignore_changes = [
stage[0].action[0].configuration
]
}
このissueで同じ課題持っているなーと思っていたら、aws provider v3.0.0で修正が入って、この記述を入れなくてもOAuthToken
の制御がうまくいくようになった。
https://github.com/terraform-providers/terraform-provider-aws/issues/2854
参考にさせて貰った情報
ECSデプロイについて全般については以下が参考になりました。
https://dev.classmethod.jp/articles/ecs-deploy-all/
GitHubとCodePipeleのwebhook挙動については以下が参考になりました。
https://qiita.com/techneconn/items/cff3e76301006f42c78f