본문 바로가기

AWS

테라폼 맨땅에서 부터 적용하기 3

한동안 테라폼에 큰 작업을 하질 못했다.

테라폼 톡방에서 정보를 보던 중 테라폼 구성을 더 편한 방법이 있을지 문의하다가 honglab님께서 도움을 주셔서 이 섹션을 작업할 수 있었다.

 

기존 구성

- 리소스를 일일이 하나씩 만들고 있었음.

resource "aws_service_discovery_service" "discovery_service_test1" {
  name = "test1"
  namespace_id = aws_service_discovery_private_dns_namespace.prod.id
  dns_config {
    namespace_id = aws_service_discovery_private_dns_namespace.prod.id

    dns_records {
      ttl  = 300
      type = "A"
    }
    routing_policy = "MULTIVALUE"
  }

  health_check_custom_config {
    failure_threshold = 1
  }
  tags = {
    Environment = var.env_tag
  }
}

resource "aws_service_discovery_service" "discovery_service_test2" {
  name = "test2"
  namespace_id = aws_service_discovery_private_dns_namespace.prod.id
  dns_config {
    namespace_id = aws_service_discovery_private_dns_namespace.prod.id

    dns_records {
      ttl  = 300
      type = "A"
    }
    routing_policy = "MULTIVALUE"
  }

  health_check_custom_config {
    failure_threshold = 1
  }
  tags = {
    Environment = var.env_tag
  }
}

 

ECS의 Mesh 구성을 위해서 discovery service를 추가했다.

하지만 내가 넣어야 할 서비스는 총 9개였다.

 

이걸 다 늘어뜨려 넣자니 귀찮기도 하고 output을 일일이 다 지정해줘야 해서 결론적으로 코딩이 과하게 늘어나는 문제점이 있었다.

 

이런 반복문제는 이것 뿐만이 아니라 내가 사용하는 여러가지 모듈과 환경에서 복합적으로 발생한다는게 문제였다.

 

이 부분을 해결하기 위해 두가지를 추가하여 진행하기로 했다.

1. for_each

2. yaml로 환경 변수 분기

 

1. 일단 환경 변수를 만드는 과정이다.

yaml 파일을 이용해서 배열 데이터를 yaml로 만들어 준다.

위 config.yaml처럼 생성하면 main.tf에서 배열을 읽어서 처리할 수 환경이 된다.

# config.yaml

discovery_service:
  test1:
    name: "test1"
    ttl: 10
    type: "A"
    routing_policy: "MULTIVALUE"
    failure_threshold: 1
  test2:
    name: "test2"
    ttl: 10
    type: "A"
    routing_policy: "MULTIVALUE"
    failure_threshold: 1

 

2. main.tf에서 변수값을 넣을수 있도록 설정한다.

# main.tf

module "cloudmap" {
  source = "../modules/prod/cloudmap"
  vpc_id = module.network.vpc_id  # network 모듈에서 출력한 VPC ID를 가져옵니다.
  env_tag = yamldecode(file("config.yaml"))["env_tag"]
  discovery_service = yamldecode(file("config.yaml"))["discovery_service"]
}

 

3. module에서 사용할수 있게 variables.tf를 설정한다.

variable "discovery_service" {
    type = map(object({
        name = string
        ttl = number
        type = string
        routing_policy = string
        failure_threshold = number
    }))
}

 

4. 이제 for_each를 통해 loop형태로 작성한다.

# discovery_for_each_statement

resource "aws_service_discovery_service" "discovery_service" {
  for_each = var.discovery_service
  name = each.value.name
  namespace_id = aws_service_discovery_private_dns_namespace.prod.id
  dns_config {
    namespace_id = aws_service_discovery_private_dns_namespace.prod.id

    dns_records {
      ttl  = each.value.ttl
      type = each.value.type
    }
    routing_policy = each.value.routing_policy
  }

  health_check_custom_config {
    failure_threshold = each.value.failure_threshold
  }
  tags = {
    Environment = var.env_tag
  }
}

 

5. 기존의 terraform state를 기존 배열에 들어가도록 mv 한다.

 

terraform state mv module.cloudmap.aws_service_discovery_service.test1 module.cloudmap.aws_service_discovery_service.discovery_service\[\"test1\"\]

 

5번의 작업을 무한대로 해주어야 한다.

 

참고로 이번에 작업한 항목은 다음과 같다.

  • acm
  • alb target group
  • alb listener rule
  • cloudwatch log group
  • ssm variables
  • s3

EC2나 고객사 커스텀 ACM은 양이 좀 많아 바꾸기가 위험해서 아직 작업하진 않았지만, 회사에서 공용으로 사용하는 도메인에 대해선 ACM이 고정되므로 바로 for_each로 묶어버렸다.

 

이 작업하면서 코딩된 량이 꽤 많이 줄었고 변수하나만 바꿔서 plan 또는 apply를 돌려도 알아서 연관 로직까지 전부 갱신되는 이점이 있어서 손이 많이 줄긴 했다.

 

적용시 장점

  • 생성 코드 재사용 가능
  • 획기적으로 코딩량이 감소
  • 환경변수만 바꿔도 알아서 관련 모듈이 전부 수정됨

적용시 단점

  • 마이그레이션에 엄청나게 시간이 증가함
  • 모든 리소스가 mv 되어야 함

 

아직 남은 작업이 몇개가 있다.

- iam role 기반으로 연동하기

- 환경까지 통합하기