はじめに
前提として、AWSマネジメントコンソール上で作成した各種ECSサービスを
Terraform管理下とするために実施した内容となります。
今回はTerraform importを活用していきます。
また、コード記述時にfor_eachを活用することで重複コードも極力減らしていきます。
※key名、各種名称および定義の詳細は本来とは違う内容を記載してます。
Terraform importとは
Terraformで既存のインフラストラクチャを管理するための機能です。 この機能を使用すると、既存のインフラストラクチャをTerraformの管理下に置くことができます。
tfファイルに定義を記載する
各種サービスをimportするために定義を配列で記載します。
importした定義を紐づけるため、最低限のservice_nameは記載する。
その後resourceを定義し、先ほどの配列をループ処理するためfor_eachを記載します。
今回は例として4つのサービスをimportしていきます。
# locals:
locals {
service_map_fargate = [
{
service_name = "test-development"
},
{
service_name = "test-scheduler-development"
},
{
service_name = "test-api-development"
},
{
service_name = "test-api-queue-development"
},
]
}
resource "aws_ecs_service" "ecs-test-fargate" {
for_each = { for i in local.service_map_fargate : i.service_name => i }
}
上記定義が完了したら、importコマンドを実行します。import時も配列のように記載します。
terraform import 'aws_ecs_service.ecs-test-fargate["test-development"]' [クラスター名/サービス名]
terraform import 'aws_ecs_service.ecs-test-fargate["test-scheduler-development"]' [クラスター名/サービス名]
terraform import 'aws_ecs_service.ecs-test-fargate["test-api-development"]' [クラスター名/サービス名]
terraform import 'aws_ecs_service.ecs-test-fargate["test-api-queue-development"]' [クラスター名/サービス名]
importが成功しているか確認するためにterraform state listコマンドを実行します。
importした定義が表示されれば成功しています。
terraform state list
aws_ecs_service.ecs-test-fargate["test-development"]
aws_ecs_service.ecs-test-fargate["test-scheduler-development"]
aws_ecs_service.ecs-test-fargate["test-api-development"]
aws_ecs_service.ecs-test-fargate["test-api-queue-development"]
次にimportした定義に対してterraform state showをすることで詳細情報を取得します。
例としてtest-developmentの情報を取得しresource上に追記しています。
terraform state show 'aws_ecs_service.ecs-test-fargate["test-development"]'
resource "aws_ecs_service" "ecs-test-fargate" {
for_each = { for i in local.service_map_fargate : i.service_name => i }
cluster = "test-cluster"
deployment_maximum_percent = 200
deployment_minimum_healthy_percent = 100
desired_count = 1
enable_ecs_managed_tags = true
enable_execute_command = true
health_check_grace_period_seconds = 0
name = "test-development"
platform_version = "LATEST"
propagate_tags = "NONE"
scheduling_strategy = "REPLICA"
tags = {}
task_definition = "test-development-fargate:1"
triggers = {}
capacity_provider_strategy {
base = 0
capacity_provider = "FARGATE_SPOT"
weight = 1
}
deployment_circuit_breaker {
enable = true
rollback = true
}
deployment_controller {
type = "ECS"
}
load_balancer {
container_name = "web"
container_port = 8080
target_group_arn = "target_group.test-fargate.arn"
}
network_configuration {
assign_public_ip = false
security_groups = [
"data.security_groups.test.id",
]
subnets = [
"data.subnet.1atest.id",
"data.subnet.1ctest.id",
"data.subnet.1dtest.id",
]
}
}
サービス毎に差分がある項目に関して、詳細情報を確認しながらservice_map_fargateに定義し、resourceも合わせて変更します。
※細かい文法などに関しましては本題とは関係ないため割愛します。以下一例となります。
locals {
service_map_fargate = [
{
service_name = "test-development"
task_name = "test-development-fargate"
enable_execute_command = true
container_name = "web"
container_port_lb = 8080
target_group_arn = target_group.test-fargate.arn
},
{
service_name = "test-scheduler-development"
task_name = "test-scheduler-development-fargate"
enable_execute_command = true
},
{
service_name = "test-api-development"
task_name = "test-api-development-fargate"
enable_execute_command = true
container_name = "web"
container_port_lb = 80
target_group_arn = target_group.test-api-fargate.arn
},
{
service_name = "test-api-queue-development"
task_name = "test-api-queue-development-fargate"
enable_execute_command = false
},
]
}
data "aws_ecs_task_definition" "ecs-test-fargate" {
for_each = { for i in local.service_map_fargate : i.service_name => i }
task_definition = each.value
}
resource "aws_ecs_service" "ecs-test-fargate" {
for_each = { for i in local.ecs_service_map_fargate : i.service_name => i }
cluster = "test-cluster"
deployment_maximum_percent = 200
deployment_minimum_healthy_percent = 100
desired_count = 1
enable_ecs_managed_tags = true
enable_execute_command = lookup(each.value, "enable_execute_command", false)
health_check_grace_period_seconds = 0
name = each.value.service_name
platform_version = "LATEST"
propagate_tags = "NONE"
scheduling_strategy = "REPLICA"
tags = {}
task_definition = data.aws_ecs_task_definition.ecs-test-fargate[each.value.task_name].arn
triggers = {}
capacity_provider_strategy {
base = 0
capacity_provider = "FARGATE_SPOT"
weight = 1
}
deployment_circuit_breaker {
enable = true
rollback = true
}
deployment_controller {
type = "ECS"
}
dynamic "load_balancer" {
for_each = can(each.value.target_group_arn) ? [1] : []
content {
container_name = each.value.container_name
container_port = each.value.container_port_lb
target_group_arn = each.value.target_group_arn
}
}
network_configuration {
assign_public_ip = false
security_groups = [
"data.security_groups.test.id",
]
subnets = [
"data.subnet.1atest.id",
"data.subnet.1ctest.id",
"data.subnet.1dtest.id",
]
}
# 以下省略
}
後はterraform planを実行し、構成に問題がないか確認しましょう。
差分がある場合は確認して修正が必要です。
差分がないようでしたらterraform applyで反映して完了です。
以降に修正が必要な場合は、Terraform上から修正するようにしましょう。
まとめ
全体のコード量が減ると可読性が向上するため管理しやすいと感じました。
また、保守なども考えるとコード化できるメリットは大きいと思います。
今回は一例を紹介しましたがTerraform1.5からはimportブロックなども活用できるかと思います。