- [이론] Terraform2024년 04월 26일
- yeongki0944
- 작성자
- 2024.04.26.:07
1. HCL (Hashicorp Configuration Language)
- https://github.com/hashicorp/hcl
- HCL native syntax는 libucl, nginx configuration 등에 영감을 받음.
- 인프라가 코드로 표현되고, 이 코드는 곧 인프라이기 때문에 선언적 특성
- 튜링 완전한 Turing-complete 언어적 특성
- 조건문 처리 같은 동작이 가능
https://www.slideshare.net/GyuSeokLee1/terraform-featureskr
- HCL 표현식
// 한줄 주석 방법1 # 한줄 주석 방법2 /* 라인 주석 */ locals { key1 = "value1" # = 를 기준으로 키와 값이 구분되며 myStr = "TF ♡ UTF-8" # UTF-8 문자를 지원한다. multiStr = <<EOF Multi Line String with anytext EOF boolean1 = true # boolean true boolean2 = false # boolean false를 지원한다. deciaml = 123 # 기본적으로 숫자는 10진수, octal = 0123 # 0으로 시작하는 숫자는 8진수, hexadecimal = "0xD5" # 0x 값을 포함하는 스트링은 16진수, scientific = 1e10 # 과학표기 법도 지원한다. # funtion 호출 예 myprojectname = format("%s is myproject name", var.project) # 3항 연산자 조건문을 지원한다. credentials = var.credentials == "" ? file(var.credentials_file) : var.credentials }
2. Version
테라폼 내에서 버전이 명시되는 terraform, module에서 사용 가능하며 버전에 대한 제약을 둠으로써 테라폼, 프로바이더, 모듈이 항상 의도한 정의대로 실행되는 것을 목적으로 한다.
버전 체계는 시맨틱 버전 관리 Semantic Versioning 방식을 따른다
# version = Major.Minor.Patch version = 1.3.4
- 시맨틱 버전 관리 방식
- Major 버전 : 내부 동작의 API가 변경 또는 삭제되거나 하위 호환이 되지 않는 버전
- Minor 버전 : 신규 기능이 추가되거나 개선되고 하위 호환이 가능한 버전
- Patch 버전 : 버그 및 일부 기능이 개선된 하위 호환이 가능한 버전
- 버전 제약 구문은 다른 프로그램 언어에서의 종속성 관리 시스템과 흡사하다.
- = 또는 연산자 없음 : 지정된 버전만을 허용하고 다른 조건과 병기할 수 없다.
- != : 지정된 버전을 제외한다.
- , >=, <, <= : 지정된 버전과 비교해 조건에 맞는 경우 허용한다.
- ~> : 지정된 버전에서 가장 자리수가 낮은 구성요소만 증가하는 것을 허용한다.
- ~> x.y 인 경우 y 버전에 대해서만, ~> x.y.z인 경우 z 버전에 대해서만 보다 큰 버전을 허용한다
- ~> : 지정된 버전에서 가장 자리수가 낮은 구성요소만 증가하는 것을 허용한다.
- 테라폼 버전 관리로 비유된 선언 방식의 의미
선언된 버전 의미 고려 사항 1.0.0 테라폼 v1.0.0만을 허용한다 테라폼을 업그레이드하기 위해서는 선언된 버전을 변경해야만 한다 >= 1.0.0 테라폼 v1.0.0 이상의 모든 버전을 허용한다 v1.0.0 버전을 포함해 그 이상의 모든 버전을 허용해 실행된다 ~> 1.0.0. 테라폼 v1.0.0을 포함한 v1.0.x 버전을 하용하고 v1.x는 허용하지 않는다 부버전에 대한 업데이트는 무중단으로 이루어진다 >= 1.0, < 2.0.0 테라폼 v1.0.0 이상 v2.0.0 미만인 버전을 허용한다 주버전에 대한 업데이트를 방지한다 프로바이더 버전
- 테라폼 0.13 버전 이전에는 provider 블록에 함께 버전을 명시했지만
해당 버전 이후 프로바이더 버전은 terraform 블록에서 required_providers에 정의
v0.13 이전 v0.13 부터 적용 provider "aws" {
version = "~> 4.2.0"
region = "ap-northeast-2"
}
provider "azurerm" {
version = ">= 2.99.0"
features {}
}terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 4.2.0"
}
azurerm = {
source = "hashicorp/azurerm"
version = ">= 2.99.0"
}
}
}- 각 프로바이더의 이름에 소스 경로와 버전을 명시하며, 테라폼 레지스트리 공식 페이지에서 원하는 프로바이더를 선택한 다음 화면에서 우측 상단의 [USE PROVIDER]를 클릭하면 테라폼 코드에 해당 버전을 사용하는 샘플 코드가 표기된다 - 링크
3. Block
- 블록의 단위 { }
Block 관련 이미지 출처 : [tistory] [Terraform] Block Type
- Block Type, Block Label
- Argument
- IDENTIFIER = EXPRESSION 형태로 정의
- key-value 형태
- resouce "<RESOURCE TYPE>" "<RESOURCE NAME>"
- "<RESOURCE TYPE>" : provider에 따라 사용할 수 있는 resource type이 다름
- "<RESOURCE NAME>" : 사용자 지정 값(EC2 Name Tag 등)
4. Variables
- 입력 변수는 인프라를 구성하는 데 필요한 속성 값을 정의해 코드의 변경 없이 여러 인프라를 생성하는 데 목적이 있다.
- 테라폼에서는 이것을 입력 변수 Input Variables 로 정의한다.
- 변수는 variable로 시작되는 블록으로 구성된다. 변수 블록 뒤의 이름 값은 동일 모듈 내 모든 변수 선언에서 고유해야 하며, 이 이름으로 다른 코드 내에서 참조된다.
# variable 블록 선언의 예 variable "<이름>" { <인수> = <값> } variable "image_id" { type = string }
- 테라폼 예약 변수 이름으로 사용 불가능 : source, version, providers, count, for_each, lifecycle, depends_on, locals
- 변수 정의 시 사용 가능한 메타인수
- default : 변수 값을 전달하는 여러 가지 방법을 지정하지 않으면 기본값이 전달됨, 기본값이 없으면 대화식으로 사용자에게 변수에 대한 정보를 물어봄
- type : 변수에 허용되는 값 유형 정의, string number bool list map set object tuple 와 유형을 지정하지 않으면 any 유형으로 간주
- description : 입력 변수의 설명
- validation : 변수 선언의 제약조건을 추가해 유효성 검사 규칙을 정의 - 링크
- sensitive : 민감한 변수 값임을 알리고 테라폼의 출력문에서 값 노출을 제한 (암호 등 민감 데이터의 경우) - 링크
- nullable : 변수에 값이 없어도 됨을 지정
- 기본 유형
- string : 글자 유형
- number : 숫자 유형
- bool : true 또는 false
- any : 명시적으로 모든 유형이 허용됨을 표시
- 집합 유형
- list (<유형>): 인덱스 기반 집합
- map (<유형>): 값 = 속성 기반 집합이며 키값 기준 정렬
- set (<유형>): 값 기반 집합이며 정렬 키값 기준 정렬
- object ({<인수 이름>=<유형>, …})
- tuple ([<유형>, …])
- list와 set은 선언하는 형태가 비슷하지만 참조 방식이 인덱스와 키로 각각 차이가 있고, map와 set의 경우 선언된 값이 정렬되는 특징을 가진다.
입력 변수 사용 예시
# 1. 전달할 값이 number 인지 확인하는 입력 변수의 예 variable "number_example" { description = "An example of a number variable in Terraform" type = number default = 42 }
# 2. 전달할 값이 list 인지 확인하는 입력 변수의 예 variable "list_example" { description = "An example of a list in Terraform" type = list default = ["a", "b", "c"] }
# 3. 조건 결합 사용 가능. 다음은 리스트의 모든 항목이 number 인 list 의 예 variable "list_numeric_example" { description = "An example of a numeric list in Terraform" type = list(number) default = [1, 2, 3] }
# 4. 다음은 모든 값이 string 인 map 의 예 variable "map_example" { description = "An example of a map in Terraform" type = map(string) default = { key1 = "value1" key2 = "value2" key3 = "value3" } }
# 5. 다음은 object 또는 tuple 제약 조건을 사용하여 보다 복잡한 구조적 유형(structural type) 작성 가능 variable "object_example" { description = "An example of a structural type in Terraform" type = object({ name = string age = number tags = list(string) enabled = bool }) default = { name = "value1" age = 42 tags = ["a", "b", "c"] enabled = true } }
변수 유형별 선언 방식의 예시 - main.tf 파일
variable "string" { type = string description = "var String" default = "myString" } variable "number" { type = number default = 123 } variable "boolean" { default = true } variable "list" { default = [ "google", "vmware", "amazon", "microsoft" ] } output "list_index_0" { value = var.list.0 } output "list_all" { value = [ for name in var.list : upper(name) ] } variable "map" { # Sorting default = { aws = "amazon", azure = "microsoft", gcp = "google" } } variable "set" { # Sorting type = set(string) default = [ "google", "vmware", "amazon", "microsoft" ] } variable "object" { type = object({ name = string, age = number }) default = { name = "abc" age = 12 } } variable "tuple" { type = tuple([string, number, bool]) default = ["abc", 123, true] } variable "ingress_rules" { # optional ( >= terraform 1.3.0) type = list(object({ port = number, description = optional(string), protocol = optional(string, "tcp"), })) default = [ { port = 80, description = "web" }, { port = 53, protocol = "udp" }] }
확인
# terraform init && terraform plan && terraform apply -auto-approve terraform state list # terraform output list_all = [ "GOOGLE", "VMWARE", "AMAZON", "MICROSOFT", ] list_index_0 = "google"
변수 참조 : variable은 코드 내에서 var.<이름>으로 참조된다.
variable "my_password" {} resource "local_file" "abc" { content = var.my_password filename = "${path.module}/abc.txt" }
# terraform init -upgrade terraform apply -auto-approve var.my_password Enter a value: qwe123 ... # 확인 terraform state list terraform state show local_file.abc cat abc.txt ; echo # 해당 파일에 다른 내용으로 변경해보기 terraform apply -auto-approve var.my_password Enter a value: t101mypss ... # 확인 cat abc.txt ; echo
민감한 변수 취급 : 입력 변수의 민감 여부 선언 가능
- main.tf 코드 파일 내용 수정
- 기본값 추가로 입력 항목은 발생하지 않지만, 출력에서 참조되는 변수 값이(sensitive)로 감춰지는 것을 확인 할 수 있다
variable "my_password" { default = "password" sensitive = true } resource "local_file" "abc" { content = var.my_password filename = "${path.module}/abc.txt" }
민감한 변수로 지정해도 terraform.tfstate 파일에는 결과물이 평문으로 기록되므로 State 파일의 보안에 유의해야 한다
# 출력부분에 내용 안보임! terraform apply -auto-approve terraform state show local_file.abc echo "local_file.abc.content" | terraform console (sensitive value) # 결과물 파일 확인 cat abc.txt ; echo # terraform.tfstate 파일 확인 cat terraform.tfstate | grep '"content":' "content": "password",
변수 입력 방식과 우선순위
- variable의 목적은 코드 내용을 수정하지 않고 테라폼의 모듈적 특성을 통해 입력되는 변수로 재사용성을 높이는 데 있다.
- 특히 입력 변수라는 명칭에 맞게 사용자는 프로비저닝 실행 시에 원하는 값으로 변수에 정의할 수 있다.
- 선언되는 방식에 따라 변수의 우선순위가 있으므로, 이를 적절히 사용해 로컬 환경과 빌드 서버 환경에서의 정의를 다르게 하거나, 프로비저닝 파이프라인을 구성하는 경우 외부 값을 변수에 지정할 수 있다.
- main.tf 코드 파일 내용 수정
variable "my_var" {} resource "local_file" "abc" { content = var.my_var filename = "${path.module}/abc.txt" }
[우선순위 수준]의 숫자가 작을수록 우선순위도 낮다.
[우선순위 수준 1] 실행 후 입력
# 실행 terraform apply -auto-approve var.my_var Enter a value: var1 ... # 확인 terraform state show local_file.abc cat abc.txt ; echo
[우선순위 수준 2] variable 블록의 default 값
- main.tf 코드 파일 내용 수정
variable "my_var" { default = "var2" } resource "local_file" "abc" { content = var.my_var filename = "${path.module}/abc.txt" }
- 확인
# 실행 terraform apply -auto-approve # 확인 terraform state show local_file.abc cat abc.txt ; echo
[우선순위 수준 3] 환경 변수 (TF_VAR 변수 이름)
- 시스템 환경 변수의 접두사에 TF_VAR_ 가 포함되면 그 뒤의 문자열을 변수 이름으로 인식한다.
- 앞서 default로 추가한 내용과 어떤 방식이 우선순위가 높은지 확인해보자
# Linux/macOS export TF_VAR_my_var=var3 terraform apply -auto-approve # 확인 cat abc.txt ; echo
[우선순위 수준 4] terraform.tfvars에 정의된 변수 선언
- 루트 모듈의 main.tf 파일과 같은 위치에 terraform.tfvars 파일을 생성해 변수에 대한 값을 추가하고 앞서 선언한 변수 선언과 비교해 우선순위를 확인
# echo 'my_var="var4"' > terraform.tfvars cat terraform.tfvars # terraform apply -auto-approve # 확인 cat abc.txt ; echo
[우선순위 수준 5] *.auto.tfvars에 정의된 변수 선언
- 파일명의 정렬에 따라 우선순위가 적용된다
# a.auto.tfvars 파일 생성 echo 'my_var="var5_a"' > a.auto.tfvars ls *.tfvars # terraform apply -auto-approve # 확인 cat abc.txt ; echo # b.auto.tfvars 파일 생성 echo 'my_var="var5_b"' > b.auto.tfvars ls *.tfvars # terraform apply -auto-approve # 확인 cat abc.txt ; echo
[우선순위 수준 6] *.auto.tfvars.json에 정의된 변수 선언
- *.auto.tfvars와 같이 파일명의 정렬에 따라 우선순위가 적용된다
# a.auto.tfvars.json 파일 생성 cat <<EOF > a.auto.tfvars.json { "my_var" : "var6_a" } EOF ls *.tfvars ; ls *.json # terraform apply -auto-approve # 확인 cat abc.txt ; echo # c.auto.tfvars.json 파일 생성 cat <<EOF > c.auto.tfvars.json { "my_var" : "var6_c" } EOF ls *.tfvars ; ls *.json # terraform apply -auto-approve # 확인 cat abc.txt ; echo
[우선순위 수준 7] CLI 실행 시 -var 인수에 지정 또는 -var-file로 파일 지정
- 여러 인수가 선언되는 경우 나중에 선언된 변수의 우선순위가 높다
# terraform apply -auto-approve -var=my_var=var7 cat abc.txt ; echo # terraform apply -auto-approve -var=my_var=var7 -var=my_var=var8 cat abc.txt ; echo
- *.tfvars와 같은 형식의 내용의 파일이라면 -var-file로 지정할 수 있다.
# var9.txt 파일 생성 echo 'my_var="var9"' > var9.txt # terraform apply -auto-approve -var=my_var=var7 -var-file="var9.txt" cat abc.txt ; echo
- .tfvars 확장자로 생성된 파일에 변수를 미리 기입하면 실행 시 입력해야 하는 변수 값을 하나의 파일에서 관리할 수 있다는 장점이 있다.
다음글이전글이전 글이 없습니다.댓글
스킨 업데이트 안내
현재 이용하고 계신 스킨의 버전보다 더 높은 최신 버전이 감지 되었습니다. 최신버전 스킨 파일을 다운로드 받을 수 있는 페이지로 이동하시겠습니까?
("아니오" 를 선택할 시 30일 동안 최신 버전이 감지되어도 모달 창이 표시되지 않습니다.)