공부하면서/Terraform

[T1012] 2주차 - 테라폼 기본 사용 2/3 (입력변수)

omelette master 2023. 7. 15. 19:52
해당 내용은 T1012 스터디에 나온 내용과 '테라폼으로 시작하는 IaC' 책을 기준으로 정리 했습니다

실습 환경

mkdir 3.5 && cd 3.5

3.6 입력 변수 Variable

입력변수는 인프라를 구성하는데 필요한 속성 값을 정의해 코드 변경없이 여러 인프라를 생성하는 데 목적이 있다.

변수선언 방식

# 3.6장 실습을 위한 사전 준비

mkdir 3.6 && cd 3.6
  • 변수는 variable로 시작되는 블록으로 구성
  • 변수 블록 뒤의 이름 값은 동일 모듈 내 모든 변수 선언에서 고유해야함
# variable 블록 선언의 예
variable "<이름>" {
 <인수> = <값>
}

variable "image_id" {
 type = string
}
  • 참고할 점으로 terraform에서 사용중인 메타 인수를 이름으로 사용할수 없다!
    source, version, providers, count, for_each, lifecycle, depends_on, locals
[사용할수 없는 변수이름]
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은 선언하는 형태가 비슷하지만 참조 방식이 index와 key로 각각 차이가 있고
map과 set의 경우 선언된 값이 정렬되는 특징을 가진다
  • 변수 유형별 선언 방식의 예시
# 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" }]
}
  • apply 하여 확인 해보면 다음과 같이 출력이 된다

유효성 검사

입력되는 변수 타입 외, 사용자 지정 유효성 검사 가능
  • 변수 블록 내에 validation 블록에서 조건인 condition에 지정되는 규칙이 true 또는 false를 반환해야 하며, error_message는 condition 값의 결과가 false 인 경우 출력되는 메시지를 정의한다.
  • regex 함수는 대상의 문자열에 정규식을 적용하고 일치하는 문자열을 반환하는데, 여기에 can 함수를 함께 사용하면 정규식에 일치하지 않는 경우의 오류를 검출한다.
  • validation 블록은 중복으로 선언할 수 있다.
  • variable 유효성 검사의 예
variable "image_id" {
  type        = string
  description = "The id of the machine image (AMI) to use for the server."

  validation { # 이미지 ID가 4자 이상인지
    condition     = length(var.image_id) > 4
    error_message = "The image_id value must exceed 4."
  }

  validation { # 이미지 ID가 ami- 이 있는지
    # 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-\"."
  }
}
kkyoung@DESKTOP-26MI22N:/mnt/d/study/workspaces/3.6$ terraform init -upgrade && terraform apply -auto-approve

Initializing the backend...

Initializing provider plugins...

Terraform has been successfully initialized!

You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.

If you ever set or change modules or backend configuration for Terraform,
rerun this command to reinitialize your working directory. If you forget, other
commands will detect it and remind you to do so if necessary.
var.image_id
  The id of the machine image (AMI) to use for the server.

  Enter a value: ami


Changes to Outputs:
  - list_all     = [
      - "GOOGLE",
      - "VMWARE",
      - "AMAZON",
      - "MICROSOFT",
    ] -> null
  - list_index_0 = "google" -> null

You can apply this plan to save these new output values to the Terraform state, without changing any real infrastructure.
╷
│ Error: Invalid value for variable
│
│   on main.tf line 1:
│    1: variable "image_id" {
│     ├────────────────
│     │ var.image_id is "ami"
│
│ The image_id value must exceed 4.
│
│ This was checked by the validation rule at main.tf:5,3-13.
╵
╷
│ Error: Invalid value for variable
│
│   on main.tf line 1:
│    1: variable "image_id" {
│     ├────────────────
│     │ var.image_id is "ami"
│
│ The image_id value must starting with "ami-".
│
│ This was checked by the validation rule at main.tf:10,3-13.

(왼쪽) ami 만 입력 했을때, (오른쪽) ami- 만 입력했을때
마지막으로 조건에 맞게 ami-1 를 입력 했을때

변수 참조

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

Enter a value: qwe123 입력
그러면 abc.txt 에 qwe123 이라는 정보가 들어간다

민감한 변수참조

입력한 변수에 대해 민감 여부 선언 가능
# main.tf 파일 수정
variable "my_password" {
  default   = "password"
  sensitive = true
}

resource "local_file" "abc" {
  content  = var.my_password
  filename = "${path.module}/abc.txt"
}
  • 실행시 content 값이 sensitive value 로 되어있는것을 확인할수 있다!

  • 하지만 terraform.tfstate 파일에는 결과물이 평문으로 저장되어 stste 파일이 노출되어 있을경우 보안 문제가 발생할수도 있다.

변수 입력 방식과 우선순위

선언되는 방식에 따라 변수의 우선순위가 있으므로, 적절히 사용해 로컬환경과 빌드서버 환경에서의 정의를 다르게 하거나, 프로비저닝 파잎프라인을 구성하는 경우 외부 값을 변수에 지정할수 있다.

출처:&nbsp;https://spacelift.io/blog/terraform-tfvars

우선순위 수준

  • 우선순위 수준의 숫자가 작을수록 우선순위도 낮다
[우선순위 수준 1] 실행 후 입력

# main.tf 수정
variable "my_var" {}

resource "local_file" "abc" {
  content  = var.my_var
  filename = "${path.module}/abc.txt"
}

# 실행
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_ 가 포함되면 그 뒤의 문자열을 변수 이름으로 인식한다.
** main.tf 를 수정하지 않았음으로 default=var2 와 TF_VAR_my_var=var3 가 같이 실행된다.
   그에 대한 결과는?? -> var3가 출력될것이다
# Linux/macOS
export TF_VAR_my_var=var3
terraform apply -auto-approve

# 확인
cat abc.txt ; echo
---

[우선순위 수준 4] terraform.tfvars에 정의된 변수 선언
* 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 확장자로 생성된 파일에 변수를 미리 기입하면 실행 시 입력해야 하는 변수 값을 하나의 파일에서 관리할 수 있다는 장점이 있다.