terraform
株の自動取引関連の話。 各種取引のバッチ処理のためによくECS + Event Schedulerの構成を利用している。 Fargateの上でECSを動かすと高くなるイメージだが、短時間の処理+低スペックのインスタンスを使えば殆ど気にならない。 短時間のバッチであればlambdaのほうが良いという意見もあるかもしれないが、 lambdaは多重起動の問題と処理時間が最長15分という制約があるため株取引のバッチ処理としてはやや使いづらい。
ただterraformでECSとEvent Schedulerを組み合わせたタスクを定義しようとするとaws_ecs_task_definition
とaws_scheduler_schedule
の2つを都度定義する必要があり記述が冗長になる。
気軽にタスクを作成してあれこれ動かせるようにしたいので、ECSタスク定義の心理的なハードルを下げたい。
そこでこれら2つをまとめたlocal moduleを作成し、見通し良くECSタスクを定義できるようにした。
公式のドキュメント見ながら勉強する。
moduleを作るためにはディレクトリを作って、その中にresourceとvariableとoutputを定義していく。 resourceは使い慣れているが、これまで基本的にベタでresourceを書いてきたのでvariable句やoutput句を使ったことが無かった。
variable句はその名前の通りmoduleに対して外部から与える変数を定義する。 variable句を駆使することでmoduleから多様なリソースを生成できる。
output句ではmodule外部に対して公開するresourceの属性などを定義する。 呼び出し側からmodule内で作成したresourceのarnを使いたい場合にoutput句で公開しているイメージだろう。
ドキュメントではresource, variable, outputをそれぞれmain.tf, variables.tf, outputs.tfというファイル名で管理することを推奨している。
なんとなく全体像がつかめたので実際にaws_ecs_task_definition
とaws_scheduler_schedule
をまとめたlocal moduleを作ってみる。
今回はECSの定期実行用のmoduleなのでcronjobというフォルダを作ってそこに必要なファイルを配置する。
外部に対して公開したい情報は無いのでoutputは使わずにresourceとvariableだけを定義していく。
まずはresourceの定義。
特に気にすることなくresourceを定義していく。
可変にしたいところはvar.変数名
という形で記載しておいてvariable.tfで具体的な型定義を与える。
resource "aws_ecs_task_definition" "cronjob_ecs" {
family = var.ecs_family_name
container_definitions = file(var.task_definition)
execution_role_arn = var.deployment_role_arn
task_role_arn = var.execution_role_arn
network_mode = "awsvpc"
requires_compatibilities = ["FARGATE"]
cpu = 1024
memory = 8192
}
resource "aws_scheduler_schedule" "cronjob_schedule" {
name = format("%s%s", var.ecs_family_name, "scheduler")
group_name = "default"
schedule_expression_timezone = "Asia/Tokyo"
flexible_time_window {
mode = "OFF"
}
schedule_expression = var.schedule_expression
target {
# ecs clusterの名前
arn = var.cluster_name
role_arn = var.eventbridge_role_arn
ecs_parameters {
enable_ecs_managed_tags = true
enable_execute_command = false
launch_type = "FARGATE"
task_definition_arn = aws_ecs_task_definition.cronjob_ecs.arn
network_configuration {
assign_public_ip = true
security_groups = var.security_groups
subnets = var.subnets
}
}
retry_policy {
maximum_event_age_in_seconds = 86400
maximum_retry_attempts = 0
}
}
}
次に各引数の定義。名称と型を定義していく。 descriptionは任意だが、インフラをコード化して管理可能性を高めるというterraformの目的を考えれば定義したほうが無難だろう。 ただ正直めんどくさくて割と適当。
variable "cluster_name" {
type = string
description = "deployment target cluster name"
}
variable "ecs_family_name" {
type = string
description = "ecs task family name"
}
variable "task_definition" {
type = string
description = "path to the ecs task definition file"
}
variable "eventbridge_role_arn" {
type = string
description = "IAM role used to trigger ecs in the eventbridge"
}
variable "deployment_role_arn" {
type = string
description = "IAM role used when ECS task is deployed"
}
variable "execution_role_arn" {
type = string
description = "IAM role used in the ECS task"
}
variable "schedule_expression" {
type = string
description = "cron like schedule expression. e.g. cron(00 8 ? * * *)"
}
variable "security_groups" {
type = set(string)
description = "security group id list"
}
variable "subnets" {
type = set(string)
description = "subnet id list"
}
これでmoduleの定義が終わったのでroot moduleから呼び出す。
moduleを呼び出す際はmoduleを使う。sourceで作成したmoduleのパスを指定してあげて、他にも必要な変数があれば渡してあげる。
moduleを定義した後の初回実行時はterraform plan
を実行する前にterraform init
を実行が必要になる。
無事terraform init
が終われば、terraform plan
で差分が見えるようになる。
module "daily_report" {
source = "./crobjob"
cluster_name = aws_ecs_cluster.walker-ecs-cluster.arn
ecs_family_name = "walker-daily-report"
task_definition = "./tasks/task_daily_report.json"
schedule_expression = "cron(00 17 ? * * *)"
eventbridge_role_arn = aws_iam_role.iam_role_for_event_bridge.arn
deployment_role_arn = aws_iam_role.iam_role_for_ecs_task_deployment.arn
execution_role_arn = aws_iam_role.iam_role_for_ecs_task_execution.arn
security_groups = [aws_security_group.security-group.id]
subnets = [aws_subnet.subnet-2.id, aws_subnet.subnet-3.id, aws_subnet.subnet-4.id]
}
moduleを用意できたのでかなり気軽にECSのタスクを定義できるようになった。 terraformのドキュメントを読むと知らない機能が結構あったので、どこかでまとめてキャッチアップしたい。