Terraform 정리

dongdorrong·2024년 6월 18일
0

DevOps

목록 보기
4/5

1. if-else-elseif

https://stackoverflow.com/a/69586941/17858112

개발을 할 때 조건문을 활용하는 경우가 많은데 Terraform에서는 if-else의 경우만 쓸 수 있도록 제공해 주는 것 같습니다.

elseif처럼, 그밖에 다른 조건을 추가하고 싶으면 아래와 같이 구현해서 활용하시면 됩니다.

conditioning_a != "condition_a" ? "value1" : (conditioning_b == "condition_b" ? "value_b" : (conditioning_c == "condition_c" ? "value_c" : (conditioning_d == "condition_d" ? "value_d" : "value2")))

2. concat(), lookup()

develop, staging 환경은 review없이 즉시 배포하고, production 환경은 review 이후 배포하도록 파이프라인을 구성하는 경우가 많은데, 저는 concat 함수를 활용해서 CodePipeline의 stage를 구성하도록 구현했습니다.

locals {
  common_stages = [
    {
      name             = "Source"
      category         = "Source"
      ...
      ...
      }
    },
    {
      name             = "Build"
      category         = "Build"
      ...
      ...
    }
  ]

  production_only_stage = [
    {
      name             = "Review"
      category         = "Approval"
      ...
      ...
    }
  ]

  deploy_stage = [
    {
      name             = "Deploy"
      category         = "Deploy"
      ...
      ...
    }
  ]

  stages = concat(
    local.common_stages,
    (var.is_production ? local.production_only_stage : []),
    local.deploy_stage
  )
}

local에서 파이프라인의 stage를 적절하게 구성해 주고, 이후로 리소스를 선언할 때 dynamic으로 stage를 구성해 주면 됩니다. 그리고 CodePipeline에서 Review 단계를 추가할 때 namespace 속성이 null이기 때문에, lookup 함수로 null 처리를 해준 부분이 있습니다.

resource "aws_codepipeline" "pipeline" {
  name     = var.pipeline_name
  role_arn = var.pipeline_role_arn

  dynamic "stage" {
    for_each = local.stages

    content {
      name = "${stage.value["name"]}"

      action {
        name             = stage.value["name"]
        category         = stage.value["category"]
        owner            = stage.value["owner"]
        provider         = stage.value["provider"]
        version          = stage.value["version"]
        input_artifacts  = stage.value["input_artifacts"]
        output_artifacts = stage.value["output_artifacts"]
        namespace        = lookup(stage.value, "namespace", null)
        configuration    = stage.value["configuration"] 
      }
    }
  }
}

3. flatten()

AWS Batch를 사용하기 위한 컴퓨팅 리소스, 대기열 등을 만들고, EventBridge 규칙으로 작업을 트리거할 수 있는 IAM 정책을 공통으로 사용하고 있습니다.

배치를 생성할 때마다 정책을 번거롭게 수정하는 것이 번거로워서 저는 아래와 같이 구현하였습니다.

module "batch_develop_dongdorrong" {
...
}

module "batch_staging_dongdorrong" {
...
}

module "batch_production_dongdorrong" {
...
}

locals {
    modules = {
        develop    = module.batch_develop_dongdorrong
        staging    = module.batch_staging_dongdorrong
        production = module.batch_production_dongdorrong
    }

    job_definitions = {
        for name, mod in local.modules : name => regex("^(.+):[^:]+$", mod.job_definition_arn)[0]
    }
}

resource "aws_iam_policy" "batch_trigger" {
    name = "batch_dongdorrong_trigger"

    policy = jsonencode({
        Version = "2012-10-17"
        Statement = [
          {
            Sid    = "BatchSubmitJobStatement"
            Action = [
              "batch:SubmitJob",
            ]
            Effect   = "Allow"
            Resource = flatten([
              for name, mod in local.modules : [
                mod.job_queue_arn,
                local.job_definitions[name],
                format("%s:*", local.job_definitions[name])
              ]
            ])
          },
        ]
      })
}

EventBridge에서 Batch의 작업 정의에 접근할 수 있어야 하기 때문에 local에서 정규식으로 처리하였고, job_definitions, job_queue_arn은 모듈의 outputs으로 참조하도록 구성했습니다.

위와 같이 구성하시면 새로운 Batch를 만들었을 때 local의 modules 블록만 수정해 주면 Batch 작업을 유연하게 구동할 수 있습니다.

profile
DevOps 엔지니어 / 열심히 해서 잘하자

0개의 댓글