LambdaでECSタスクを実行するTerraformモジュールを作ってみました。
最近、DBマイグレーションを含むデプロイで脱StepFunctionsしてLambdaでECSタスクを実行するTerraformモジュールを作って公開したので紹介します。
AWSのCodePipelineを使ったよくあるデプロイで、ECRへのImage Pushをトリガーにして、DBマイグレーションの後にAppをデプロイするという流れがあります。
これに対して、よくある構成として、以下のようにDBマイグレーションをLambdaで行うという方法があります。
しかし、これだとLambda用にデプロイのコードを書くか、コンテナイメージを用意しなくてはなりません。
一方で、よくある構成ではDBマイグレーションのコードはAppと共通でAppのコンテナイメージに含まれていることが多いかと思います。
StepFunctionsを利用するとECS Taskを実行して待つことができます。
以下のような感じでStepFunctionsでECS Taskが実行されます。
一見良さそうですが、StepFunctionsでのECS Taskの実行ではTask Definitionを指定する必要があり、PushImageにより得られた新しいイメージをセットした新しいTask Definitionを動的にセットすることができません。
そうすると、予めlatestタグをセットしたTask Definitionを用意しておくなど、せっかくPushImageをトリガーにしている意味がなくなってしまいます。
整理すると、
PushImageで渡ってきたコンテナイメージでDBマイグレーションを行いたい。
AppのコンテナイメージをDBマイグレーションでも利用したい。
これらの点を考慮して、LambdaでDBマイグレーションをするのではなく、DBマイグレーションを行うECS Taskを実行するLambdaを作ることにしました。
このパターンはいろいろなところで使えるため、TerraformモジュールにしてGitHubで公開してみました。
仕組みは単純でLambda内で以下のステップで処理をします。
ImagePushソースで生成されたimageDetail.jsonから更新されたイメージを取得する。
取得したイメージで新しくECS Task Definitionを作成する。
作成したECS Task DefinitionでTaskを実行する。
Taskの実行が終わるまで待つ。
モジュールの使い方は以下のようなイメージです。
resource "aws_codepipeline" "app_deploy" {
name = "app-deploy"
...
stage {
name = "deploy"
action {
name = "DBMigration"
category = "Invoke"
owner = "AWS"
provider = "Lambda"
version = "1"
input_artifacts = ["SourceArtifact"]
run_order = 1
configuration = {
FunctionName = "LambdaFunctionName"
UserParameters = jsonencode({
cluster = "ClusterName"
taskDefinitionFamily = "TaskDefinitionFamily"
containerName = "db-migration"
})
}
}
}
}
CodePipelineの流れは以下のようになります。
これにより、ImagePushで渡ってきたコンテナイメージを使ってDBマイグレーションを行うことができるようになりました。
ざっと検索した感じ簡単な方法がなかったので自作してしまいましたが、自作せずとも簡単に実現できる方法があれば、それに乗っかりたいので教えてください!