fullmoon's bright IT blog

[T101]3주차 - 기본 사용 3/3 - 조건문과 함수, 프로비저너 본문

Cloud/AWS

[T101]3주차 - 기본 사용 3/3 - 조건문과 함수, 프로비저너

휘영청 2023. 9. 18. 09:26
728x90

테라폼으로 시작하는 IaC의 도서를 기반으로 작성하였습니다.

 


조건문과 함수에 대해서 알아봅니다.

테라폼에서의 조건식3항 연산자 형태를 갖습니다. 조건은 true 또는 false로 확인되는 모든 표현식입니다.

[참고링크]

https://developer.hashicorp.com/terraform/language/expressions/conditionals

 

Conditional Expressions - Configuration Language | Terraform | HashiCorp Developer

Conditional expressions select one of two values. You can use them to define defaults to replace invalid values.

developer.hashicorp.com

 

조건문

[실습]

#main.tf 만들기
mkdir 3.10 && cd 3.10

파일내용 변경해주기

variable "enable_file" {
  default = true
}

resource "local_file" "foo" {
  count    = var.enable_file ? 1 : 0
  content  = "foo!"
  filename = "${path.module}/foo.bar"
}

output "content" {
  value = var.enable_file ? local_file.foo[0].content : ""
}

실행하기

# 변수 우선순위3 : 환경 변수 (TF_VAR 변수 이름)
export TF_VAR_enable_file=false
export | grep TF_VAR_enable_file

# 
terraform init && terraform plan && terraform apply -auto-approve
terraform state list

# 환경 변수 삭제
unset TF_VAR_enable_file
export | grep TF_VAR_enable_file

# 재실행
terraform plan && terraform apply -auto-approve
terraform state list

#
echo "local_file.foo[0]" | terraform console
echo "local_file.foo[0].content" | terraform console
  • 일반적으로 비교, 논리 연산자를 사용해 조건을 확인한다.
  • 조건식은 ? 기호를 기준으로 왼쪽조건
  • 오른쪽: 기호를 기준으로 왼쪽이 조건에 대해 true가 반환되는 경우이고 오른쪽false가 반환되는 경우다.
  • 다음의 예에서 var.a가 빈 문자열이 아니라면 var.a를 나타내지만, 비어 있을 때는 “default-a”를 반환한다
# <조건 정의> ? <옳은 경우> : <틀린 경우>
var.a != "" ? var.a : "default-a"

조건식의 각 조건은 비교 대상의 형태가 다르면 테라폼 실행 시 조건 비교를 위해 형태를 추론하여 자동으로 변환하는데, 명시적인 형태 작성을 권장한다.

조건식은 단순히 특정 속성에 대한 정의, 로컬 변수에 대한 재정의, 출력 값에 대한 조건 정의 뿐만 아니라 리소스 생성 여부에 응용할 수 있다. count에 조건식을 결합한 경우 다음과 같이 특정 조건에 따라 리소스 생성 여부를 선택할 수 있다.

 

함수

[실습]

# main.tf 만들기

mkdir 3.11 && cd 3.11

resource "local_file" "foo" {
  content  = upper("foo! bar!")
  filename = "${path.module}/foo.bar"
}

실행하기

#실행하기
terraform init && terraform plan && terraform apply -auto-approve
cat foo.bar ; echo

# 내장 함수 간단 사용
terraform console
>
-----------------
upper("foo!")
max(5, 12, 9)
lower(local_file.foo.content)

cidrnetmask("172.16.0.0/12")

exit
-----------------

[도전과제] count + 함수 cidrhost 로 EC2의 ENI 에 10개의 ip를 장착

provider "aws" {
  region = "ap-northeast-2"
}

resource "aws_vpc" "hwi_vpc" {
  cidr_block = "172.16.0.0/16"
}

data "aws_availability_zones" "available" {
  state = "available"
}

locals {
  host_ip_count = 10
}

resource "aws_subnet" "hwi_subnet" {
  vpc_id            = aws_vpc.hwi_vpc.id
  cidr_block        = "172.16.10.0/24"
  availability_zone = data.aws_availability_zones.available.names[0]
}

resource "aws_network_interface" "foo" {
  count       = local.host_ip_count
  subnet_id   = aws_subnet.hwi_subnet.id
  private_ips = [cidrhost(aws_subnet.hwi_subnet.cidr_block, count.index + 100)]
}

resource "aws_instance" "foo" {
  count         = local.host_ip_count
  ami           = "ami-0365b82b9a892c59"
  instance_type = "t2.micro"

  network_interface {
    network_interface_id = aws_network_interface.foo[count.index].id
    device_index         = 0
  }
}

output "network_private_ips" {
  value = aws_network_interface.foo.*.private_ips
}

나온결과

#output
Outputs:

network_private_ips = [
  toset([
    "172.16.10.100",
  ]),
  toset([
    "172.16.10.101",
  ]),
  toset([
    "172.16.10.102",
  ]),
  toset([
    "172.16.10.103",
  ]),
  toset([
    "172.16.10.104",
  ]),
  toset([
    "172.16.10.105",
  ]),
  toset([
    "172.16.10.106",
  ]),
  toset([
    "172.16.10.107",
  ]),
  toset([
    "172.16.10.108",
  ]),
  toset([
    "172.16.10.109",
  ]),
]

테라폼은 프로그래밍 언어적인 특성을 가지고 있어서, 값의 유형을 변경하거나 조합할 수 있는 내장 함수를 사용 할 수 있다

[참고링크]

https://developer.hashicorp.com/terraform/language/functions

 

Functions - Configuration Language | Terraform | HashiCorp Developer

An introduction to the built-in functions that you can use to transform and combine values in expressions.

developer.hashicorp.com

  • 단, 내장된 함수 외에 사용자가 구현하는 별도의 사용자 정의 함수를 지원하지는 않는다.
  • 함수 종류에는 숫자, 문자열, 컬렉션, 인코딩, 파일 시스템, 날짜/시간, 해시/암호화, IP 네트워크, 유형 변환이 있다.
  • 테라폼 코드에 함수를 적용하면 변수, 리소스 속성, 데이터 소스 속성, 출력 값 표현 시 작업을 동적이고 효과적으로 수행할 수 있다.

프로비저너

 

[실습]

#main.tf 생성하기
mkdir 3.12 && cd 3.12

#main.tf
variable "sensitive_content" {
  default   = "secret"
  #sensitive = true
}

resource "local_file" "foo" {
  content  = upper(var.sensitive_content)
  filename = "${path.module}/foo.bar"

  provisioner "local-exec" {
    command = "echo The content is ${self.content}"
  }

  provisioner "local-exec" {
    command    = "abc"
    on_failure = continue
  }

  provisioner "local-exec" {
    when    = destroy
    command = "echo The deleting filename is ${self.filename}"
  }
}

실행하기

terraform init
 
# 실행 계획에서는 결과 유추가 불가능!
terraform plan

...
Plan: 1 to add, 0 to change, 0 to destroy.
local_file.foo: Creating...
local_file.foo: Provisioning with 'local-exec'...
local_file.foo (local-exec): Executing: ["/bin/sh" "-c" "echo The content is SECRET"]
local_file.foo (local-exec): The content is SECRET
local_file.foo: Provisioning with 'local-exec'...
local_file.foo (local-exec): Executing: ["/bin/sh" "-c" "abc"]
local_file.foo (local-exec): /bin/sh: abc: command not found
local_file.foo: Creation complete after 0s [id=3c3b274d119ff5a5ec6c1e215c1cb794d9973ac1]

terraform apply -auto-approve

# 테라폼 상태에 프로비저너 정보(실행 및 결과)가 없다
terraform state list
terraform state show local_file.foo
cat foo.bar ; echo
cat terraform.tfstate | jq

# graph 확인 : 프로비저너 정보(의존성)이 없다
terraform graph > graph.dot

# 삭제
terraform destroy -auto-approve
...
Plan: 0 to add, 0 to change, 1 to destroy.
local_file.foo: Destroying... [id=3c3b274d119ff5a5ec6c1e215c1cb794d9973ac1]
local_file.foo: Provisioning with 'local-exec'...
local_file.foo (local-exec): Executing: ["/bin/sh" "-c" "echo The deleting filename is ./foo.bar"]
local_file.foo (local-exec): The deleting filename is ./foo.bar
local_file.foo: Destruction complete after 0s

main.tf 수정한다면?

variable "sensitive_content" {
  default   = "secret"
  sensitive = true
}

resource "local_file" "foo" {
  content  = upper(var.sensitive_content)
  filename = "${path.module}/foo.bar"

  provisioner "local-exec" {
    command = "echo The content is ${self.content}"
  }

  provisioner "local-exec" {
    command    = "abc"
    #on_failure = continue
  }

  provisioner "local-exec" {
    when    = destroy
    command = "echo The deleting filename is ${self.filename}"
  }
}

실행을 다시한번 해보자

#에러발생시 중지됨

# 민감 정보 참조 부분의 실행 및 결과 내용은 출력 안됨
# 실행 실패 시 에러 발생되면 중지
terraform apply -auto-approve
...
Plan: 1 to add, 0 to change, 0 to destroy.
local_file.foo: Creating...
local_file.foo: Provisioning with 'local-exec'...
local_file.foo (local-exec): (output suppressed due to sensitive value in config)
local_file.foo (local-exec): (output suppressed due to sensitive value in config)
local_file.foo: Provisioning with 'local-exec'...
local_file.foo (local-exec): Executing: ["/bin/sh" "-c" "abc"]
local_file.foo (local-exec): /bin/sh: abc: command not found
╷
│ Error: local-exec provisioner error
│ 
│   with local_file.foo,
│   on main.tf line 14, in resource "local_file" "foo":
│   14:   provisioner "local-exec" {
│ 
│ Error running command 'abc': exit status 127. Output: /bin/sh: abc: command not found
│

프로바이더로 실행되지 않는 커맨드와 파일 복사 같은 역할을 수행하는 프로비저너는 AWS EC2 생성 후 특정 패키지를 설치해야 하거나 파일을 생성해야 하는 경우, 이것들은 테라폼의 구성과 별개로 동작해야 한다.

프로비저너로 실행된 결과는 테라폼의 상태 파일과 동기화되지 않으므로 프로비저닝에 대한 결과가 항상 같다고 보장할 수 없다 ⇒ 선언적 보장 안됨

따라서 프로비저너 사용을 최소화하는 것이 좋다. 프로비저너의 종류에는 파일 복사와 명령어 실행을 위한 file, local-exec, remote-exec가 있다.

프로비저너의 경우 리소스 프로비저닝 이후 동작하도록 구성할 수 있다. 예를 들어 AWS EC2 생성 후 CLI를 통해 별도 작업 수행 상황을 가정한다.

 

[프로비저너에 대한 내용은 추가 보충할 예쩡..]

728x90