12
6
お題は不問!Qiita Engineer Festa 2024で記事投稿!
Qiita Engineer Festa20242024年7月17日まで開催中!

重複コードは極力減らしつつ複数のECSサービスをTerraformの管理下としたい

Last updated at Posted at 2024-07-11

はじめに

前提として、AWSマネジメントコンソール上で作成した各種ECSサービスを
Terraform管理下とするために実施した内容となります。
今回はTerraform importを活用していきます。
また、コード記述時にfor_eachを活用することで重複コードも極力減らしていきます。
※key名、各種名称および定義の詳細は本来とは違う内容を記載してます。

Terraform importとは

Terraformで既存のインフラストラクチャを管理するための機能です。 この機能を使用すると、既存のインフラストラクチャをTerraformの管理下に置くことができます。

tfファイルに定義を記載する

各種サービスをimportするために定義を配列で記載します。
importした定義を紐づけるため、最低限のservice_nameは記載する。
その後resourceを定義し、先ほどの配列をループ処理するためfor_eachを記載します。
今回は例として4つのサービスをimportしていきます。

aws_ecs_service_fargate.tf
# 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"]'
aws_ecs_service_fargate.tf
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も合わせて変更します。
※細かい文法などに関しましては本題とは関係ないため割愛します。以下一例となります。

aws_ecs_service_fargate.tf
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ブロックなども活用できるかと思います。

12
6
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
12
6