네트워크 인프라 자동화를 위한 호환 Terraform 모듈
네트워크 인프라 자동화를 위한 호환 Terraform 모듈 (Compatible Terraform Modules for Network Infrastructure Automation)
Consul-Terraform-Sync(CTS)는 태스크를 통해 Terraform 모듈의 실행을 자동화해요. 태스크는 CTS에서 Terraform과 모듈의 자동화를 정의하는 구성 요소예요.
출처: 문서
본문
Consul-Terraform-Sync(CTS)는 태스크를 통해 Terraform 모듈 실행을 자동화해요. 태스크는 CTS에서 Terraform과 모듈의 자동화를 정의하는 구성 요소(construct)예요.
모듈 사양 (Module Specifications)
CTS와 호환되는 모듈은 표준 모듈 구조를 따르며, Terraform 버전 0.13 이상이 지원하는 구문을 사용할 수 있어요.
호환성 요구 사항 (Compatibility Requirements)
다음은 CTS와의 모듈 호환성을 위한 두 가지 필수 요소예요.
- 루트 모듈 (Root module) — Terraform에는 리포지토리 루트 디렉터리의 파일이 모듈의 기본 진입점으로 기능해야 한다는 요구 사항이 하나 있어요. 이 파일은 CTS가 태스크 자동화에 사용할 핵심 로직을 캡슐화해야 해요. 리소스가 생성되는 기본 파일의 권장 파일명은
main.tf예요. services입력 변수 — CTS는 모든 모듈이 루트 모듈 내에서 다음 입력 변수를 선언하도록 요구해요.services변수 선언은 다른 입력 변수가 일반적으로 선언되는 권장variables.tf파일의 맨 위에 포함할 수 있어요. 이 변수는 Consul 카탈로그 API의 응답 객체 역할을 하며 모듈이 사용할 네트워크 정보를 표면화해요. 객체의 맵 구조로 되어 있어요.
선택적 입력 변수 (Optional Input Variables)
필수 services 입력 변수 외에도 CTS는 모듈 내에서 사용할 추가적인 선택적 입력 변수를 제공해요. 선택적 입력 변수 지원에는 두 가지 변경이 필요해요:
- Terraform 모듈을 업데이트해 권장
variables.tf에 입력 변수를 선언 - 입력 변수에 제공해야 하는 모듈 입력 값(module input values)을 정의하는 CTS 태스크 블록에 구성을 추가
모듈 입력 정의 및 Terraform 모듈에서 선택적 입력 변수 선언에 대한 자세한 내용은 아래 섹션을 참고해요.
모듈 입력 (Module Input)
태스크는 태스크 구성으로 정의된 Consul 객체를 모니터링해요. Consul 객체는 태스크의 Terraform 모듈 입력 변수가 정의한 요구 사항을 충족하는 모듈 입력으로 사용될 수 있어요.
태스크의 모듈 입력은 둘 다 정의된 객체를 모니터링하지만 태스크의 조건(condition)과는 약간 달라요. 태스크의 조건은 구성된 기준(criteria)으로 정의된 객체를 모니터링해요. 이 기준이 충족되면 태스크가 트리거돼요.
반면 모듈 입력은 이러한 객체에 대한 값이나 메타데이터를 Terraform 모듈에 제공할 목적으로 정의된 객체를 모니터링해요. 모니터링되는 모듈 입력과 조건 객체는 동일한 객체일 수 있어요. 예를 들어 condition "services" 블록과 use_as_module_input이 true로 설정된 태스크가 그렇죠. 모듈 입력과 조건은 다른 객체일 수도 있고 별도로 구성될 수도 있어요. 예를 들어 condition "catalog-services와 module_input "consul-kv" 블록으로 구성된 태스크가 그렇죠. 그 결과, 모니터링되는 모듈 입력은 Terraform 모듈을 충족시키기 위해 제공된 조건과 분리(de-coupled)돼요.
CTS가 모니터링하는 각 객체 유형은 태스크 정의 내의 하나의 구성으로만 정의할 수 있어요. 예를 들어 태스크가 서비스를 모니터링하면 condition "services"와 module_input "services"를 모두 구성할 수 없어요. 자세한 내용은 Task Module Input 구성을 참고해요.
모듈 입력을 정의하는 몇 가지 방법이 있어요:
services목록 (더 이상 사용되지 않음) — 모듈 입력으로 사용할 서비스 목록.condition블록의use_as_module_input필드 — true로 설정하면 조건의 객체가 모듈 입력으로 사용돼요.- 이 필드는 이전에
source_includes_var(deprecated)로 불렸어요.
- 이 필드는 이전에
module_input블록 — 이 블록은 모듈 입력으로 사용할 객체를 정의하기 위해 여러 번 구성할 수 있어요.- 이 블록은 이전에
source_input(deprecated)으로 불렸어요.
- 이 블록은 이전에
모듈 입력을 정의하는 여러 방법은 구성 유연성을 추가하며 services 입력 변수와 함께 CTS가 지원하는 선택적 추가 입력 변수를 허용해요.
추가적인 선택적 입력 변수 유형:
Services 모듈 입력 (Services Module Input)
services 모듈 입력으로 구성된 태스크는 서비스의 변경 사항을 모니터링해요. 모니터링은 구성된 서비스 목록이나 제공된 regex와 일치하는 모든 서비스 중 하나로 수행돼요.
렌더링된 services 입력 예시:
terraform.tfvars:
services = {
"web.test-server.dc1" = {
id = "web"
name = "web"
kind = ""
address = "127.0.0.1"
port = 80
meta = {}
tags = ["example"]
namespace = ""
status = "passing"
node = "pm8902"
node_id = "307625d3-a1cf-9e85-ff81-12017ca4d848"
node_address = "127.0.0.1"
node_datacenter = "dc1"
node_tagged_addresses = {
lan = "127.0.0.1"
lan_ipv4 = "127.0.0.1"
wan = "127.0.0.1"
wan_ipv4 = "127.0.0.1"
}
node_meta = {
consul-network-segment = ""
}
},
}
services 모듈 입력으로 태스크를 구성하려면 입력에 사용될 서비스 목록을 다음 중 한 가지 방법으로 구성해야 해요:
- 태스크의
services(더 이상 사용되지 않음) use_as_module_input필드를 true로 설정해 구성한condition "services"블록- 필드는 이전에
source_includes_var(deprecated)로 불렸어요.
- 필드는 이전에
module_input "services"블록- 블록은 이전에
source_input "services"(deprecated)로 불렸어요.
- 블록은 이전에
services 모듈 입력은 Health List Nodes For Service API를 모니터링해 동작하며 최신 서비스 정보를 입력 변수에 제공해요. 모듈에 제공될 서비스 정보의 전체 목록은 다음과 같아요:
| 속성 | 설명 |
|---|---|
id |
이 서비스에 대한 고유한 Consul ID. 서비스 ID는 Consul 에이전트별로 고유해요. |
name |
서비스의 논리적 이름. 많은 서비스 인스턴스가 동일한 논리적 서비스 이름을 공유할 수 있어요. |
address |
서비스 호스트의 IP 주소 — 비어 있으면 노드 주소를 사용해야 해요. |
port |
서비스의 포트 번호 |
meta |
서비스에 대한 사용자 정의 메타데이터 키/값 쌍 목록 |
tags |
서비스에 대한 태그 목록 |
namespace |
서비스 인스턴스의 Consul Enterprise 네임스페이스 |
status |
헬스 체크 목록의 집계를 기반으로 한 서비스 인스턴스의 대표 상태 |
node |
서비스가 등록된 Consul 노드의 이름 |
node_id |
서비스가 등록된 노드의 ID. |
node_address |
서비스가 등록된 Consul 노드의 IP 주소. |
node_datacenter |
서비스가 등록된 Consul 노드의 데이터 센터. |
node_tagged_addresses |
에이전트에 대한 명시적 LAN 및 WAN IP 주소 목록 |
node_meta |
노드에 대한 사용자 정의 메타데이터 키/값 쌍 목록 |
다음은 일정에 따라 실행되고 regexp 매개변수와 일치하는 서비스에 대한 정보를 태스크의 모듈에 제공하는 태스크 구성 예시예요.
task {
name = "services_condition_task"
description = "execute on changes to services whose name starts with web"
providers = ["my-provider"]
module = "path/to/services-condition-module"
condition "schedule" {
cron = "* * * * Mon"
}
module_input "services" {
regexp = "^web.*"
}
}
Consul KV 모듈 입력 (Consul KV Module Input)
Consul KV 모듈 입력으로 구성된 태스크는 제공된 구성을 충족하는 KV 쌍의 변경 사항에 대해 Consul KV를 모니터링해요. Consul KV 모듈 입력은 Consul KV API를 모니터링해 동작하며 이러한 키 값을 태스크의 모듈에 제공해요.
렌더링된 consul KV 입력 예시:
terraform.tfvars:
consul_kv = {
"my-key" = "some value"
}
Consul KV 모듈 입력으로 태스크를 구성하려면 입력에 사용될 KV를 다음 중 한 가지 방법으로 구성해야 해요:
use_as_module_input필드를 true로 설정해 구성한condition "consul-kv"블록.- 필드는 이전에
source_includes_var(deprecated)로 불렸어요.
- 필드는 이전에
module_input "consul-kv"블록.- 블록은 이전에
source_input "consul-kv"(deprecated)로 불렸어요.
- 블록은 이전에
다음은 Consul KV 조건 섹션에서 제공된 예시와 유사한 예시예요. 그러나 이 예시의 차이는 Consul KV 변경에 따라 트리거되는 대신 이 태스크가 일정에 따라 실행된다는 것이에요. 실행이 트리거되면 Consul KV 정보가 태스크의 모듈에 제공돼요.
task {
name = "consul_kv_schedule_task"
description = "executes on Monday monitoring Consul KV"
module = "path/to/consul-kv-module"
condition "schedule" {
cron = "* * * * Mon"
}
module_input "consul-kv" {
path = "my-key"
recurse = true
datacenter = "dc1"
namespace = "default"
}
}
Catalog Services 모듈 입력 (Catalog Services Module Input)
Catalog Services 모듈 입력으로 구성된 태스크는 Catalog List Services API가 제공하는 서비스 및 태그 정보를 모니터링해요. 모듈 입력은 서비스 이름을 태그 목록에 매핑하는 맵이에요.
렌더링된 catalog-services 입력 예시:
terraform.tfvars:
catalog_services = {
"api" = ["prod", "staging"]
"consul" = []
"web" = ["blue", "green"]
}
Catalog Services 모듈 입력으로 태스크를 구성하려면 입력에 사용될 카탈로그 서비스를 다음 중 한 가지 방법으로 구성해야 해요:
use_as_module_input필드로 구성한condition "catalog-services"블록.- 필드는 이전에
source_includes_var(deprecated)로 불렸어요.
- 필드는 이전에
참고 (Note): 현재
module_input "catalog-services"블록에 대한 지원은 없어요.
use_as_module_input을 통해 모듈 입력을 지원하는 catalog-services 조건 예시:
task {
name = "catalog_services_condition_task"
description = "execute on registration/deregistration of services"
providers = ["my-provider"]
module = "path/to/catalog-services-module"
condition "catalog-services" {
datacenter = "dc1"
namespace = "default"
regexp = "web.*"
use_as_module_input = true
node_meta {
key = "value"
}
}
}
호환 Terraform 모듈 생성 방법 (How to Create a Compatible Terraform Module)
모듈을 만드는 방법에 대해 더 읽거나 모듈을 구축하는 튜토리얼을 진행할 수 있어요. CTS는 다음 섹션의 사양을 충족하는 모든 모듈과 통합되도록 설계됐어요.
리포지토리 hashicorp/consul-terraform-sync-template-module을 복제해 호환 Terraform 모듈을 구성하기 위한 시작점으로 사용할 수 있어요. 템플릿 리포지토리에는 다음 단계에서 설명하는 파일들이 준비되어 있어요.
먼저 모듈을 구성하는 Terraform 구성 파일을 정리할 디렉터리를 만들어요. main.tf와 variables.tf 두 파일을 만드는 것부터 시작해 모듈과 네트워크 인프라 자동화 요구에 따라 확장할 수 있어요.
main.tf는 모듈의 진입점이며 여기서 모듈 작성을 시작할 수 있어요. Consul 서비스 디스커버리 정보, 특히 필수 services 입력 변수를 사용하는 자동화 태스크와 관련된 여러 Terraform 리소스를 포함할 수 있어요. 아래 코드 예시는 services 변수를 사용하는 리소스를 보여줘요. 이 예시를 CTS와 함께 자동화에서 사용하면 Consul 서비스 디스커버리 정보가 변경됨에 따라 로컬 파일의 내용이 동적으로 업데이트돼요.
main.tf:
# Create a file with service names and their node addresses
resource "local_file" "consul_services" {
content = join("\n", [
for _, service in var.services : "${service.name} ${service.id} ${service.node_address}"
])
filename = "consul_services.txt"
}
모듈을 작성하기 전에 고려해야 할 중요한 점은 모듈이 실행될 조건을 결정하는 것이에요. 이렇게 하면 모듈에서 다른 유형의 CTS 제공 입력 변수도 사용할 수 있어요. 또한 문서와 사용자가 모듈에 대해 태스크를 구성하는 방법을 알리는 데 도움이 돼요.
Services 변수 (Services Variable)
호환 모듈의 사양 요구 사항을 충족하려면 services 변수 선언을 variables.tf 파일에 복사해요. 모듈은 var.services 외에도 다른 변수 선언과 CTS 제공 입력 변수를 선택적으로 가질 수 있어요.
variables.tf:
variable "services" {
description = "Consul services monitored by Consul-Terraform-Sync"
type = map(
object({
id = string
name = string
kind = string
address = string
port = number
meta = map(string)
tags = list(string)
namespace = string
status = string
node = string
node_id = string
node_address = string
node_datacenter = string
node_tagged_addresses = map(string)
node_meta = map(string)
cts_user_defined_meta = map(string)
})
)
}
services 맵의 키는 Consul 에이전트 및 데이터 센터 전반에 걸친 서비스의 고유 식별자예요. 키는 service-id.node.datacenter 형식(Consul Enterprise의 경우 service-id.node.namespace.datacenter)을 따르며, services 변수에 사용할 수 있는 속성의 전체 목록은 CTS 태스크 문서에 포함되어 있어요.
Terraform 변수는 모듈 인수로 전달될 때 객체 유형에 대해 손실(lossy)될 수 있어요. 이를 통해 CTS는 생성된 루트 모듈에서 모든 객체 속성으로 전체 변수를 선언하고, 변수 선언을 위해 이러한 속성 중 일부만 포함하는 하위 모듈에 변수를 전달할 수 있어요. CTS와 호환되는 모듈은 사용하지 않는 속성을 생략해 모듈 내의 var.services 선언을 단순화할 수 있어요. 예를 들어 다음 services 변수는 4개의 속성을 가지며 나머지는 생략됐어요.
variables.tf:
variable "services" {
description = "Consul services monitored by Consul-Terraform-Sync"
type = map(
object({
id = string
name = string
node_address = string
port = number
status = string
})
)
}
Catalog Services 변수 (Catalog Services Variable)
catalog-services 조건용 모듈을 만드는 경우 서비스 등록 및 태그 정보를 포함하는 catalog_services 변수를 추가할 수 있어요. 모듈이 이 정보를 사용하는 데 유용하다면 다른 변수와 함께 catalog_services 변수 선언을 variables.tf 파일에 복사할 수 있어요.
variables.tf:
variable "catalog_services" {
description = "Consul catalog service names and tags monitored by Consul-Terraform-Sync"
type = map(list(string))
}
catalog_services 맵의 키는 지정된 데이터 센터에서 Consul에 등록된 서비스의 이름이에요. 각 서비스 이름에 대한 값은 해당 서비스에 대해 알려진 모든 태그 목록이에요.
catalog-services 조건으로 모듈을 만드는 경우 이를 README에 문서화할 것을 권장해요. 이렇게 하면 모듈로 태스크를 구성하려는 사용자가 catalog-services 조건 블록을 구성해야 한다는 것을 알게 돼요.
마찬가지로 모듈에서 catalog_services 변수를 사용하는 경우 이 사용을 README에 문서화할 것도 권장해요. 모듈 사용자는 catalog-services 조건 use_as_module_input 구성을 true로 설정해야 한다는 것을 알게 될 거예요. 이 필드가 true로 설정되면 CTS는 생성된 루트 모듈에서 catalog_services 변수를 선언하고 변수를 하위 모듈에 전달해요. 따라서 이 필드가 일관되지 않게 구성되면 CTS는 오류를 내고 종료해요.
Consul KV 변수 (Consul KV Variable)
consul-kv 조건용 모듈을 만드는 경우 Consul KV 쌍의 키와 값을 포함하는 consul_kv 변수를 추가할 수 있어요. 모듈이 이 정보를 사용하는 데 유용하다면 다른 변수와 함께 consul_kv 변수 선언을 variables.tf 파일에 복사할 수 있어요.
variables.tf:
variable "consul_kv" {
description = "Keys and values of the Consul KV pairs monitored by Consul-Terraform-Sync"
type = map(string)
}
모듈에 consul_kv 변수가 포함된 경우 README 파일에 사용을 문서화해 사용자가 consul-kv 조건에서 use_as_module_input 구성을 true로 설정하도록 하는 것을 권장해요. 필드를 true로 설정하면 CTS가 생성된 루트 모듈에서 consul_kv 변수를 선언하고 변수를 하위 모듈에 전달하도록 지시해요. 따라서 이 필드가 일관되지 않게 구성되면 CTS는 오류를 내고 종료해요.
모듈 입력 변수 (Module Input Variables)
네트워크 인프라는 팀과 조직마다 크게 다르며, 실무자의 자동화 요구는 기존 설정에 따라 고유해요. 입력 변수는 실무자를 위한 모듈의 사용자 지정 매개변수 역할을 할 수 있어요.
- 모듈에서 실무자가 자동화를 자신의 인프라에 맞게 조정할 수 있는 영역을 식별해요.
- 입력 변수를 선언하고 모듈 리소스 전반에 걸쳐 변수 사용을 삽입해 이러한 옵션을 실무자에게 노출해요.
- 변수가 무엇이고 어떻게 사용되는지 설명하는 설명을 포함하고 변수에 대한 사용자 지정 검증 규칙을 지정해 사용자에게 변수의 예상 형식과 조건에 대한 컨텍스트를 제공해요.
- 선택적인 변수에 대해 합리적인 기본값을 설정하거나 필수 모듈 인수인 변수에 대해 기본값을 생략해요.
- 비밀 또는 민감한 값을 포함하는 변수에 대해 sensitive 인수를 설정해요. 설정하면 Terraform 명령 실행 시 Terraform이 출력에서 값을 삭제(redact)해요.
Terraform은 명시적 구성 언어이며 변수가 선언되고 유형이 지정되며 모듈 인수로 명시적으로 전달되어야 해요. CTS는 모듈 입력에서 루트 수준의 중간 변수(intermediate variables)를 만들어 이를 추상화해요. 이러한 값은 실무자가 task 블록 내에서 구성해요. 값 할당은 구문 분석되어 해당 변수 선언을 보간하며 적절한 Terraform 파일에 기록돼요. 중간 변수에 대해 몇 가지 가정이 이루어져요: 사용자가 CTS에 제공하는 변수는 이름과 유형이 일치하는 모듈에 의해 선언되고 지원된다는 것이에요.
모듈 지침 (Module Guidelines)
이 섹션은 호환 CTS 모듈 작성에 대한 지침을 다뤄요.
범위 (Scope)
모듈을 공급자의 몇 가지 관련 리소스로 범위를 한정할 것을 권장해요. 작은 모듈은 최종 사용자가 CTS를 위해 채택하기 더 쉽고 유연해요. 이를 통해 사용자는 서로 다른 모듈을 반복적으로 결합하고 이를 구성 요소로 사용해 고유한 네트워크 인프라 요구를 충족할 수 있어요.
복잡성 (Complexity)
Terraform 실행 시간을 줄이기 위해 복잡성이 낮은 모듈 작성을 고려해요. 의존성이 많은 복잡한 모듈은 실행 시간이 길어질 수 있으며, 이는 거의 실시간에 가까운(near real time) 네트워크 업데이트에 지연을 추가해요.
제공자 (Providers)
Terraform 모듈은 terraform.required_providers 블록 내에서 필요한 공급자를 선언해야 해요. 또한 모듈이 호환되는 버전을 지정하기 위해 공급자에 대한 버전 제약 조건을 포함할 것을 권장해요.
required_providers 블록을 제외하고 네트워크 통합용 공유 모듈에는 공급자 구성을 포함해서는 안 돼요. 최종 사용자는 CTS를 통해 공급자를 구성하며 CTS는 공급자 구성을 생성된 루트 모듈에 적절히 변환해요.
문서 (Documentation)
CTS용 모듈은 Terraform 모듈이며 consul-terraform-sync 데몬과 Consul 환경에서 독립적으로 효과적으로 실행될 수 있어요. Terraform 모범 사례에 따라 작성되고 설계되어야 하며 Terraform 사용자에게 모듈이 무엇을 하고 어떻게 사용하는지 명확해야 해요. 모듈 문서는 README 또는 README.md로 이름을 지정해야 해요. 설명에는 모듈이 무엇에 사용되어야 하는지와 CTS와 함께 자동화에서 실행할 때의 영향(implications)을 담아야 해요.