본 시리즈는 가시다님의 T101(테라폼으로 시작하는 IaC) 3기 진행 내용입니다. (가시다님 노션)
도서 정보
https://www.yes24.com/Product/Goods/119179333
실습 코드
https://github.com/terraform101
목차
1. 데이터 소스 및 반복문 - (링크)
2. 입력 변수(Variable) 및 지역값(local)
3. 출력(output)
1. 입력 변수(Variable)
입력 변수는 인프라를 구성하는 데 필요한 속성 값을 정의해 코드의 변경 없이 여러 인프라를 생성하는 데 목적이 있다.
테라폼에서는 이것을 입력 변수 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"
유효성 검사 : 입력되는 변수 타입 지정 이외, 사용자 지정 유효성 검사가 가능
- 변수 블록 내에 validation 블록에서 조건인 condition에 지정되는 규칙이 true 또는 false를 반환해야 하며, error_message는 condition 값의 결과가 false 인 경우 출력되는 메시지를 정의한다.
- regex 함수는 대상의 문자열에 정규식을 적용하고 일치하는 문자열을 반환하는데, 여기에 can 함수를 함께 사용하면 정규식에 일치하지 않는 경우의 오류를 검출한다.
- validation 블록은 중복으로 선언할 수 있다.
- variable 유효성 검사의 예 - main.tf 코드 파일 내용 수정
variable "image_id" {
type = string
description = "The id of the machine image (AMI) to use for the server."
validation {
condition = length(var.image_id) > 4
error_message = "The image_id value must exceed 4."
}
validation {
# regex(...) fails if it cannot find a match
condition = can(regex("^ami-", var.image_id))
error_message = "The image_id value must starting with \"ami-\"."
}
}
- 확인
#
terraform apply -auto-approve
var.image_id
The id of the machine image (AMI) to use for the server.
Enter a value: ami
...
#
terraform apply -auto-approve
var.image_id
The id of the machine image (AMI) to use for the server.
Enter a value: ami-
...
#
terraform apply -auto-approve
var.image_id
The id of the machine image (AMI) to use for the server.
Enter a value: ami-12345678
...
첫 ami 를 입력하면 첫 번째 validation과 두 번째 validation 둘 다 에러가 발생한다.
string의 길이가 4가 넘지 않았고, 정규표현식에 부합하지 않아서이다.
두 번째로 ami- 를 입력하면 첫 번째 validation만 에러가 발생한다.
이는 정규표현식 규칙에는 부합하기 때문에 첫 번째 validation만 에러가 발생했다.
마지막 ami-12345678 를 입력하면 두개 validation 모두 충족하기 때문에 넘어가게 된다.
변수 참조 : variable은 코드 내에서 var.<이름>으로 참조된다.
- main.tf 코드 파일 내용 수정
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
# 결과물 파일 확인
cat abc.txt ; echo
# terraform.tfstate 파일 확인
cat terraform.tfstate | grep '"content":'
"content": "password",
변경하게 되면 기본적으로 내용이 출력되지 않는다.
abc.txt 파일을 열어보면 당연히 보이게 된다.
terraform.tfstate 를 조회해도 content의 내용이 평문으로 보인다.
그렇기에 terraform.tfstate 파일의 보안에 주의해야 한다.
(이것 또한 TFC에서 제공한다고 한다.)
변수 입력 방식과 우선순위
- 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 값
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 확장자로 생성된 파일에 변수를 미리 기입하면 실행 시 입력해야 하는 변수 값을 하나의 파일에서 관리할 수 있다는 장점이 있다.
이걸 직접 해보기 전까지는 너무 길고 힘들어보였는데, 막상 해보니 규칙이 있었다.
마지막에 적용되는 변수가 반영된다는 점.
- *.auto.tfvars , *.auto.tfvars.json , 그리고 apply 시 -var=my_var=var7 or 파일로 -var-file="var9.txt" 입력 하는 것들 모두
- *.auto.tfvars , *.auto.tfvars.json 의 경우 마지막의 기준은 알파벳 순 정렬했을 때 더 뒤에 있는 파일 기준 a -> z
그리고 *.auto.tfvars , *.auto.tfvars.json 는 서로 같은 tfvars로 처리되기 때문에 z.auto.tfvars와 a.auto.tfvars.json 에 동일하게 my_var를 z와 a로 지정했다면 z로 변수가 입력된다.
2. 지역값(local)
코드 내에서 사용자가 지정한 값 또는 속성 값을 가공해 참조 가능한 local (지역 값)은 외부에서 입력되지 않고, 코드 내에서만 가공되어 동작하는 값을 선언한다.
‘local’은 입력 변수와 달리 선언된 모듈 내에서만 접근 가능하고, 변수처럼 실행 시에 입력받을 수 없다.
로컬은 사용자가 테라폼 코드를 구현할 때 값이나 표현식을 반복적으로 사용할 수 있는 편의를 제공한다. 하지만 빈번하게 여러 곳에서 사용되는 경우 실제 값에 대한 추적이 어려워져 유지 관리 측면에서 부담이 발생할 수 있으므로 주의해야 한다.
local 선언
- 로컬이 선언되는 블록은 locals로 시작한다. 선언되는 인수에 표현되는 값은 상수만이 아닌 리소스의 속성, 변수의 값들도 조합해 정의할 수 있다.
- 동일한 tf 파일 내에서 여러 번 선언하는 것도 가능하고 여러 파일에 걸쳐 만드는 것도 가능하다.
- 다만 lcoals에 선언한 로컬 변수 이름은 전체 루트 모듈 내에서 유일해야 한다.
- 정의되는 속성 값은 지정된 값의 형태에 따라 다양한 유형으로 정의할 수 있다.
- main.tf 파일 : local 값 선언 방식의 예
variable "prefix" {
default = "hello"
}
locals {
name = "terraform"
content = "${var.prefix} ${local.name}"
my_info = {
age = 20
region = "KR"
}
my_nums = [1, 2, 3, 4, 5]
}
locals {
content = "content2" # 중복 선언되었으므로 오류가 발생한다.
}
- 실행
#
terraform init
terraform apply -auto-approve
locals를 두번 쓰는건 문제가 안되지만 지역 변수를 중복해서 선언하게 되면 에러가 발생한다.
- main.tf 파일 수정
variable "prefix" {
default = "hello"
}
locals {
name = "terraform"
content = "${var.prefix} ${local.name}"
my_info = {
age = 20
region = "KR"
}
my_nums = [1, 2, 3, 4, 5]
}
#
terraform init
terraform apply -auto-approve
terraform state list
local 참조
- 선언된 local 값은 local.<이름>으로 참조할 수 있다.
- 테라폼 구성 파일을 여러 개 생성해 작업하는 경우 서로 다른 파일에 선언되어 있더라도 다른 파일에서 참조할 수 있다.
- main.tf 파일 내용 수정
variable "prefix" {
default = "hello"
}
locals {
name = "terraform"
}
resource "local_file" "abc" {
content = local.content
filename = "${path.module}/abc.txt"
}
- sub.tf 파일 생성
locals {
content = "${var.prefix} ${local.name}"
}
- 실행 : main.tf의 content 내용 값으로 local.content를 참조하며, 해당 값은 다른 테라폼 구성 파일에 있지만 실행 시점에는 마치 하나의 구성 파일 처럼 올바로 표기되는 것을 확인할 수 있다.
#
ls *.tf
terraform init -upgrade
terraform apply -auto-approve
terraform state list
terraform state show local_file.abc
# graph 확인 > graph.dot 파일 선택 후 오른쪽 상단 DOT 클릭
terraform graph > graph.dot
#
cat abc.txt ; echo
- 이 예제에서는 서로 다른 테라폼 구성 파일에서도 로컬 값을 참조할 수 있다는 가능성을 확인할 수 있지만, 관리 측면에서는 서로 참조하는 로컬값이 파편화되어 유지 보수가 어려워질 수 있으므로 주의가 필요하다.
(추가) terraform.tfvars에 정의된 변수 선언
#
echo 'prefix="t101-study"' > terraform.tfvars
cat terraform.tfvars
#
terraform apply -auto-approve
cat abc.txt ; echo
아까 실습했던 terraform.tfvars 에 prefix 변수값을 넣게 되면 기존 prefix 변수 값인 “hello” 에서 “t101-study”로 변경된다.
결론
입력 변수와 로컬 변수에 대해서 몰랐던 부분들을 세세하게 알게 되었다. 분산해서 관리할 수 있다는 장점이 있지만 파편화를 주의하자.
'Tech > Terraform' 카테고리의 다른 글
[T101_3기] 3주차 - 기본 사용 및 프로바이더 (1/3) - 기본 사용(1/2) (0) | 2023.09.10 |
---|---|
[T101_3기] 2주차 - 기본 사용 (3/3) - 출력(output) (0) | 2023.09.09 |
[T101_3기] 2주차 - 기본 사용 (1/3) - 데이터 소스 및 반복문 (0) | 2023.09.09 |
[T101_3기] 1주차 - Terraform 설명 및 환경 구성 (2/2) - 도전 과제 (0) | 2023.09.01 |
[T101_3기] 1주차 - Terraform 설명 및 환경 구성 (1/2) - 설명 및 구성 (0) | 2023.09.01 |
댓글