Terraform

[ Terraform101 Study - 2w ] 입력변수 variable

su''@ 2024. 6. 23. 06:27
Terrafrom T101 4기 실습 스터디 게시글입니다.
"테라폼으로 시작하는 IaC" 도서를 참고하여 정리했습니다. 

 

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

테라폼에서는 이것을 입력 변수 Input Variables 로 정의한다. (코드의 재사용성 향상)

  • 변수 선언 방식
    • 3.6 디렉터리 신규 생성 후 열기 → main.tf 파일 생성
    cd .. && rm -rf 3.5
    mkdir 3.6 && cd 3.6
    touch main.tf
    
    • 변수는 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의 경우 선언된 값이 정렬되는 특징을 가진다.
    • 입력 변수 사용 예시
      • 전달할 값이 number 인지 확인하는 입력 변수의 예
        variable "number_example" {
          description = "An example of a number variable in Terraform"
          type        = number
          default     = 42
        }
      • 전달할 값이 list 인지 확인하는 입력 변수의 예
        variable "list_example" {
          description = "An example of a list in Terraform"
          type        = list
          default     = ["a", "b", "c"]
        }
      • 조건 결합 사용 가능. 다음은 리스트의 모든 항목이 number 인 list 의 예
        variable "list_numeric_example" {
          description = "An example of a numeric list in Terraform"
          type        = list(number)
          default     = [1, 2, 3]
        }
      • 다음은 모든 값이 string 인 map 의 예
        variable "map_example" {
          description = "An example of a map in Terraform"
          type        = map(string)
        
          default = {
            key1 = "value1"
            key2 = "value2"
            key3 = "value3"
          }
        }
      • 다음은 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
      ...
      
      terraform apply -auto-approve
      코드에서 validation의 ami를 지정해주지 않았기 때문에 ami값을 입력받는다.

      실습을 위해 입력한ami 값으로 ami- 뒤의 수는 '4자리 이상'이어야 함을확인하기 위해 ami-12345678을 입력했고, apply가 실행됨을 확인했다.


  • 변수 참조 : variable은 코드 내에서 var.<이름>으로 참조된다.
    • main.tf 코드 파일 내용 수정
    variable "my_password" {}
    
    resource "local_file" "abc" {
      content  = var.my_password #선언된 변수를 참조하기 위해서는 var. 으로 값을 참조한다.
      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
    valiable의 값을 지정해주지 않아 interactive 하게 값을 입력받고, 값이 입력된 후 정상적으로 apply 된 것을 확인할 수 있다.


  • 민감한 변수 취급 : 입력 변수의 민감 여부 선언 가능
    • 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.tfstate 파일을 보안적으로 안전하게 관리하는 방안은?
  •  
  • 변수 입력 방식과 우선순위 
    • variable의 목적은 코드 내용을 수정하지 않고 테라폼의 모듈적 특성을 통해 입력되는 변수로 재사용성을 높이는 데 있다.
    • 특히 입력 변수라는 명칭에 맞게 사용자는 프로비저닝 실행 시에 원하는 값으로 변수에 정의할 수 있다.
    • 선언되는 방식에 따라 변수의 우선순위가 있으므로, 이를 적절히 사용해 로컬 환경과 빌드 서버 환경에서의 정의를 다르게 하거나, 프로비저닝 파이프라인을 구성하는 경우 외부 값을 변수에 지정할 수 있다.
  • [우선순위 수준]의 숫자가 작을수록 우선순위도 낮다.
    • main.tf 코드 파일 내용 수정
    • variable "my_var" {} resource "local_file" "abc" { content = var.my_var filename = "${path.module}/abc.txt" }
  • [ 우선순위 수준 1] 실행 후 입력
    # (옵션) 신규 터미널
    watch -d 'ls -l;echo;cat 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_ 가 포함되면 그 뒤의 문자열을 변수 이름으로 인식한다.
    • 앞서 default로 추가한 내용과 어떤 방식이 우선순위가 높은지 확인해보자
    # Linux/macOS
    export TF_VAR_my_var=var3
    echo $TF_VAR_my_var
    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 확장자로 생성된 파일에 변수를 미리 기입하면 실행 시 입력해야 하는 변수 값을 하나의 파일에서 관리할 수 있다는 장점이 있다.