본문 바로가기
IaC

[IaC] Terraform 작성 및 배포(1) - provider block, resource block, dynamic block, data block, depends_on

by cloudraw 2024. 3. 4.

안녕하세요, 클라우드로입니다!

 

이번 글에서는 테라폼을 구성하는 block(terraform, provider, resource, data, dynamic)들과 depends_on에 대해 알아보겠습니다. 위 개념들의 이해를 돕기 위해 네이버 클라우드에서 제공하는 테라폼 리소스(NaverCloudPlatform Terraform Registry)를 예시로 작성하였습니다. 

 

terraform & provider block

 먼저 terrafom 코드를 작성할 때, 가장 선행되어야 할 작업은 provider 지정입니다. 일반적으로 provider는 terraform이 리소스를 생성하고 관리하는데 사용하는 plugin으로 쉽게 설명할 수 있으며, 어떤 인프라에 반영할지 정하는 부분이라고 생각하면 됩니다. 

terraform block, provider block

 

 위 그림에서는 terraform block과 provider block을 보여주고 있습니다. terraform block에는 사용자가 사용할 csp 및 버전을 작성합니다. 이 block에 필요한 정보는 Terraform Registry 홈페이지에 명시되어 있습니다. provider block의 경우,해당 csp에 접근할 수 있는 크레덴셜 정보에 대해 작성을 필요로 합니다. 위 예시처럼 ncloud의 경우에는 access_key와 secret_key가 필요합니다. 예시에서 support_vpc는 ncloud classic 환경과 vpc 환경 중에서 어느 환경에서 인프라를 배포할지 정하는 것으로, true로 설정하면 vpc 환경에서 작업하겠다는 의미입니다.

 

간혹 aws, ncloud 처럼 provider block에서 region을 지정하는 csp가 있는데, 이는 어떤 region에 배포할지 결정할 때 사용합니다. 일반적으로 main.tf을 작성하는 경우에는, provider block을 하나만 만들어, 한 region에 리소스를 배포합니다. 다만 region을 구분하여 리소스를 배포해야하는 경우  provider block을 추가로 선언하고, 해당 provider block에 alias값을 지정합니다. 이는 provider를 구분하기 위한 것으로, 추가로 provider block을 생성한 경우에는 alias를 반드시 설정해야 하며, 기존 provider에는 alias를 지정하지 않습니다.

provider block이 2개일 경우

위의 코드를 보면 provider block이 각각 한국, 일본으로 하나씩 선언이 되어있는 것을 확인할 수 있습니다. 위처럼 provider가 2개일 경우, 밑에서 설명할 resource block에서 어떤 provider를 사용할 지 선언하는데, 아래와 같은 방식처럼 지정합니다. 

provider를 지정한 vpc의 resource block

 이렇게 되면 alias가 설정된 provider를 사용하면서 배포를 하게 됩니다. 만약 provider block이 하나만 존재한다면 어떤 provider를 사용할 것인지 resource block에 설정해주지 않아도 정상적으로 동작합니다. 

 

resource block

  다음은 resource block입니다. 실제로 작성자가 배포하고자 하는 리소스에 대한 코드를 작성하는 부분이며, 가장 큰 비중을 차지하는 block입니다. resource block은 아래처럼 배포할 리소스의 종류, 코드 내에서 지정한 해당 리소스의 이름, 그리고 그 리소스를 구성하는 값들로 구성됩니다. 배포할 리소스의 종류에 들어갈 값과 리소스를 구성하는 인자에 해당하는 값은 Terraform Registry 홈페이지 에서 확인할 수 있습니다. 해당 홈페이지에 terraform에서 지원하는 모든 resource block 코드의 설명과 간단한 예시가 csp 별로 작성되어 있습니다. 파일에서 지정하는 이름은 작성자의 편의에 따라 선택할 수 있으며, 동일 리소스를 같은 이름으로 설정할 수는 없습니다. 

resource "(배포할 resource block 리소스의 종류)" "(해당 리소스의 파일 내 이름)" {
  (리소스를 구성하는 인자1)           = "(인자1에 상응하는 값1)"
  (리소스를 구성하는 인자2)           = "(인자1에 상응하는 값2)"
  ...
}

 

resource block의 형태는 위 형태에서 벗어나지 않고 동일하며, 어떤 값이 들어가느냐에 따라 배포되는 리소스가 달라집니다. ncloud 리소스 중 vpc과 subnet을 예시로 확인해 보겠습니다.

 

먼저 vpc에 해당하는 코드입니다. 

resource block - vpc

위 코드는 ncloud에서 vpc를 배포하는 간단 형태의 resource block에 대한 코드입니다. ncloud_vpc를 배포할 것이며, 해당 리소스의 파일 내 이름을 "TEST"로 지정했다는 것을 알 수 있습니다. 리소스를 구성하는 인자 값을 통해 배포될 vpc의 이름은 "test-vpc"가 될 것이며, ipv4_cidr_block은 "10.0.0.0/16"으로 설정했다는 것을 알 수 있습니다.

 

다음은 subnet에 해당하는 resource block입니다. 

resource block - subnet

 위 코드를 보면, ncloud_subnet을 배포할 것이며, 파일 내 이름은 "TEST"으로 설정하겠다는 것을 알 수 있습니다. 기본적으로 사용하는 인자와 달리 vpc_no와 network_acl_no을 보면 변수형태로 값이 할당되어있습니다. 이는 다른 리소스의 값을 참조하고 있음을 의미합니다. subnet은 자신이 어떤 vpc 내부에 위치하는지 vpc의 고유 id를 필요로 하는데, 이럴 경우에 위 코드처럼 참조하도록 작성합니다.(코드를 작성하는 시점에서 vpc가 배포되어 있어 vpc의 id를 알고 있다면 직접 작성해도 되나 참조 값을 통해 배포의 순서를 정할 수 있습니다.) 

 

 

 

data block

 다음은 data block입니다. data block은 이미 존재하는 값을 불러올 때 사용합니다. 값만 가져오는 것이지, 실제로 리소스를 불러와 형상 관리를 하는 것은 아닙니다. data block은 기존에 배포되어 있는 리소스의 특정 값을 가져올 때테라폼에서 기본적으로 제공하는 값 중 사용할 수 있는 값을 확인할 때 사용합니다. data block의 기본적인 형태는 아래와 같습니다. 

data "(배포할 data block 리소스의 종류)" "(파일에서 해당 리소스를 부를 이름)" {
	"(불러올 리소스에 대한 조건1)" = "(조건1에 해당하는 값1)"
}

 

만약 해당 리소스가 배포되지 않은 상황에서 data block을 사용하면 아래와 같은 에러가 발생합니다. 

data block - error message(1)

또 만약 같은 유형의 리소스가 2개 이상 배포된 상황에서 name처럼 리소스를 특정할 수 있는 조건이 명시되지 않았다면, 어떤 리소스를 불러올 지 특정할 수 없기 때문에, 아래와 같은 에러를 마주하게 됩니다.

data block - error message(2)

이제, ncloud의 vpc를 예시로 설명해보겠습니다. "test-vpc"라는 이름의 vpc가 배포되어 있다고 가정하면, data block의 코드는 아래처럼 작성할 수 있습니다. 

data block - vpc

data block 작성 후, apply 명령어를 사용하면, terraform.tfstate 파일에 다음과 같이 불러온 내용이 있는 것을 알 수 있습니다. 

terraform.tfstate - data block을 사용하여 불러온 vpc

 

이렇게 불러온 정보를 다른 resource block에서 참조하여 사용할 수 있습니다. 위에서 언급했던 subnet으로 예를 들어보겠습니다. subnet에서는 vpc_no와 network_acl_no라는 인자로 vpc의 특정값이 필요합니다.

resource block - data block을 적용하지 않은 subnet

선행하여 배포된 vpc 정보를 data block을 사용하면, 아래와 같이 수정할 수 있습니다. 

resource block - data block을 적용한 subnet

 

이번에는 테라폼에서 제공하는 값 중 사용할 수 있는 값을 확인하는 상황에 대해 이야기해 보겠습니다.  

data "(배포할 data block 리소스의 종류)" "(파일에서 해당 리소스를 부를 이름)" {
  filter {
    name = "(필터로 사용할 인자1)"
    values = "(인자1에 해당하는 값1)"
  }
  ...
}

 

data block 내부에 바로 filter를 사용하여 찾는 값에 대한 조건을 작성합니다. 이 역시 terraform registry 홈페이지에 어떤 식으로 작성해야 하는지 나와있습니다. 그렇다면 실제로 사용하는 예시를 살펴보겠습니다. 우선, 다음은 ncloud server를 배포하는 resource block 코드입니다. 

resource block - server

위 코드를 보면, ncloud_server를 배포할 때, server_image_product_code와 server_product_code를 필요로 하고 있는 것을 확인할 수 있습니다. 해당 인자에 잘못된 값이 들어가면 에러가 발생하기 때문에, 올바른 값을 찾아 입력해야 합니다. 이때, data block을 사용하여 들어갈 수 있는 값을 찾을 수 있습니다. terraform registry 홈페이지 중, ncloud_server_images data block 페이지에서 해당 filter로 "platform_type"을 사용할 수 있고, 그 값으로 가능한 값들도 작성되어 있습니다. 이를 참조하여 아래와 같은 data block을 작성할 수 있습니다. 

data block - server images

위 방식으로 filter를 작성하면, 해당 platform_type을 가진 모든 server image들을 확인할 수 있고, apply 명령어를 실행하면 tfstate 파일에 가능한 값들이 나옵니다.

terraform.tfstate - server image 관련 tfstate 중 일부

 

 

 

dynamic block

dynamic block은 resource block 내부에 block 인자를 생성하는 개념으로, 내부 block의 동적 생성이 필요(Optional 인자)하거나 동일한 이름으로 여러 번 생성될 수 있을 경우 사용합니다. 일반적으로 중첩된 block은 block이름을 바로 작성하며 시작하는 것과 달리 dynamic block은 "dynamic"을 붙여서 사용합니다. 아래 코드를 보면서 비교해 보겠습니다. 

일반 nested block과 dynamic block

 위 내용은 ncloud의 리소스 중 하나인, source build 중 project를 배포하는 코드의 일부입니다. 위 그림을 보면, resource block 내부에 source, env, compute, platform block들은 각각 한 개씩 중첩되어 존재하는데, 그 이유는 해당 block들이 여러 번 생성될 수 없으며, 필수로 생성되어야 하기 때문입니다. 반면 dynamic block 인 os block은 dynamic이 선언되어 있으며, 그 내부에는 다음과 같이 작성되어 있습니다.  

dynamic "os" {
	for_each = var.os_settings
	content {
   		id = os.value.id
	}
}

 

dynamic block은 동일한 block을 여러 번 생성하는 것이기 때문에 반복할 대상이 필요합니다. 이때 반복할 대상을 for_each를 통해 지정하게 됩니다. for_each에 대해서는 다음 테라폼 글에서 더 자세히 다루도록 하겠습니다. 반복해서 생성되는 실제 인자들은 content라는 block 내부에 작성합니다. content 내부에서는 dynamic block으로 지정한 이름을 참조한 후, 그 값 중 필요한 값을 사용한다는 의미에서 "~.value.~" 형식으로 작성합니다. 

dynamic "(생성할 block 이름)" {
	for_each = (반복해서 block을 생성할 때 사용할 전체 값)
	content {
    	    (block 내부에 사용할 인자1) = (생성할 block 이름).value.(인자1에 해당하는 값)
            (block 내부에 사용할 인자2) = (생성할 block 이름).value.(인자2에 해당하는 값)
	}
}

 

그렇다면, 조건에 따라서 dynamic block을 생성하고 싶을 때는 어떻게 할까요? 그럴때는 for_each 문에 조건을 부여하고, 조건에 부합할 경우에만 block을 사용하겠다고 설정합니다. 

dynamic "os" {
	for_each = var.os_settings.enable_os == true ? [1] : []
	content {
   		id = os.value.id
	}
}

 

위 코드의 for_each 문장을 보면, "var.os_settings.enable_os == true ? " 라는 조건 부분이 있습니다. 해당 조건을 만족하면 [1] 즉, os block을 사용하겠다는 의미이고, 조건을 불만족하면, block을 생성하지 않겠다는 의미입니다. 

 

 

 

depends_on

위에서 사용했던 ncloud server의 resource block 코드를 다시 보겠습니다.

resource block - server

 ncloud server를 배포할 때, subnet과 login_key의 특정 값을 참조하여 사용한다는 것을 알 수 있습니다. 여기서 리소스의 배포 순서에 대해 생각해보아야 합니다. 위의 코드에서는 server 배포 전, subnet과 login_key가 먼저 배포되었다는 것을 전제하고 작성되어 있는 코드입니다. 따라서 만약 login_key가 배포되지 않았는데, server를 먼저 배포하려하면, 에러가 발생할 것입니다. 이러한 문제를 방지하기 위해 작성하는 부분이 바로 depends_on 입니다. 

depends_on 적용한 server resource block

depends_on은 list 형식으로 작성하며, 선행 배포할 리소스 종류와 내부 이름을 같이 기입합니다.

 

 

 

이렇게 테라폼의 provider block, resource block, data block, dynamic block depends_on을 알아봤습니다. 해당 내용은 테라폼 코드 작성 시, 많이 사용되는 방식이기 때문에 잘 숙지하고 여러 번 반복해서 이해할 필요가 있습니다. 

 

다음 테라폼 글에서는 for_each, flatten, local values를 활용하여 테라폼 코드를 작성하는 방법에 대해 알아보도록 하겠습니다. 

 

감사합니다. 


 

    

 

Cloudraw는 쉽게 클라우드 인프라를 그리고 사용할 수 있는 서비스를 제공하기 위해 노력하고 있습니다.

 

클라우드가 있는 곳 어디든 Cloudraw가 함께합니다.

 

📨 help@cloudraw.kr