๐Ÿ“‚ IaC/Terraform

TF 101 Study 2์ฃผ์ฐจ ์ •๋ฆฌ - data source, variable, local, output, for_each, for, dynamic

dhyuck 2023. 7. 14. 23:51
๋ฐ˜์‘ํ˜•
  • ๊ฐ€์‹œ๋‹ค๋‹˜์ด ์ง„ํ–‰ํ•˜์‹œ๋Š” CloudNeta์˜ Terraform 101 Study์— ์ฐธ๊ฐ€ํ•˜๋ฉฐ ์ž‘์„ฑํ•œ ๋‚ด์šฉ์ž…๋‹ˆ๋‹ค.
  • ์Šคํ„ฐ๋”” ๊ต์žฌ โ†’ ํ…Œ๋ผํผ์œผ๋กœ ์‹œ์ž‘ํ•˜๋Š” IaC

CH3. ๊ธฐ๋ณธ ์‚ฌ์šฉ๋ฒ• - 2


3-5. ๋ฐ์ดํ„ฐ ์†Œ์Šค


  • ๋ฐ์ดํ„ฐ ์†Œ์Šค โ†’ ํ…Œ๋ผํผ์œผ๋กœ ์ •์˜๋˜์ง€ ์•Š์€ ์™ธ๋ถ€ ๋ฆฌ์†Œ์Šค ๋˜๋Š” ์ €์žฅ๋œ ์ •๋ณด๋ฅผ ํ…Œ๋ผํผ ๋‚ด์—์„œ ์ฐธ์กฐํ•  ๋•Œ ์‚ฌ์šฉ
  • ์™ธ๋ถ€์—์„œ ๋ฐ์ดํ„ฐ ์†Œ์Šค๋ฅผ ๊ฐ€์ ธ์˜ค๊ธฐ ์œ„ํ•œ ์กฐ๊ฑด โ†’ ์ธ์ˆ˜(Arguments)
  • ๊ฐ€์ ธ์˜จ ๋ฐ์ด์„œ ์†Œ์Šค์˜ ๋‚ด์šฉ โ†’ ์†์„ฑ(Attributes)
# ํ…Œ๋ผํผ ์ฝ”๋“œ
data "<๋ฆฌ์†Œ์Šค ์œ ํ˜•>" "<์ด๋ฆ„>" {
    <์ธ์ˆ˜> = <๊ฐ’>
}

# ๋ฐ์ดํ„ฐ ์†Œ์Šค ์ฐธ์กฐ
data.<๋ฆฌ์†Œ์Šค ์œ ํ˜•>.<์ด๋ฆ„>.<์†์„ฑ>

3-6. ์ž…๋ ฅ ๋ณ€์ˆ˜(variable)


  • Input Variables โ†’ ํ•„์š”ํ•œ ์†์„ฑ ๊ฐ’์„ ์ •์˜ํ•ด ์ฝ”๋“œ์˜ ๋ณ€๊ฒฝ ์—†์ด ์ธํ”„๋ผ๋ฅผ ์ƒ์„ฑํ•˜๊ธฐ ์œ„ํ•ด ์‚ฌ์šฉ
  • ์ž…๋ ฅ ๋ณ€์ˆ˜๋Š” ํ…Œ๋ผํผ Plan์‹œ์— ์ž…๋ ฅํ•˜๊ณ  ์ฐธ์กฐ๋Š” var.<์ด๋ฆ„>์œผ๋กœ ํ•œ๋‹ค
variable "<์ด๋ฆ„>" {
    <์ธ์ˆ˜> = <๊ฐ’>
}

๋ณ€์ˆ˜ ์œ ํ˜•

  • ๊ธฐ๋ณธ ์œ ํ˜•
    • string, number, bool, any
  • ์ปฌ๋ ‰์…˜ ์œ ํ˜•
    • list โ†’ ์ธ๋ฑ์Šค๋กœ ์ฐธ์กฐ
    • set โ†’ ํ‚ค๋กœ ์ฐธ์กฐ
    • map, set โ†’ ์„ ์–ธ๋œ ๊ฐ’์ด ์ •๋ ฌ

์œ ํšจ์„ฑ ๊ฒ€์‚ฌ

  • ํ…Œ๋ผํผ 0.13.0 ์ดํ›„๋กœ ์‚ฌ์šฉ์ž ์ง€์ • ์œ ํšจ์„ฑ ๊ฒ€์‚ฌ๊ฐ€ ๊ฐ€๋Šฅ โ†’ ๋ณ€์ˆ˜ ๋ธ”๋ก ๋‚ด์— validation๊ณผ condition, error_message
  • ๋ณ€์ˆ˜ ์ฝ”๋“œ ๋‚ด์—์„œ validation์€ ์—ฌ๋Ÿฌ๋ฒˆ ๊ฐ€๋Šฅ
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 {
    condition     = can(regex("^ami-", var.image_id))
    error_message = "The image_id value mus starting with 'ami-i'."
  }
}

๋ฏผ๊ฐํ•œ ๋ณ€์ˆ˜ ์ทจ๊ธ‰

  • sensitive๊ฐ€ ์ ์šฉ๋œ ๋ณ€์ˆ˜๋Š” Plan, Apply์‹œ์— (sensitive value)๋กœ ํ‘œ์‹œ๊ฐ€ ๋œ๋‹ค.
  • sensitive๋ฅผ ์ ์šฉํ•ด๋„ terraform.tfstate ํŒŒ์ผ์—๋Š” ํ‰๋ฌธ์œผ๋กœ ์ €์žฅ
variable "my_password" {
   default   = "password"
   sensitive = true
 }

๋ณ€์ˆ˜ ์ž…๋ ฅ ๋ฐฉ์‹๊ณผ ์šฐ์„ ์ˆœ์œ„

  • ๋ณ€์ˆ˜๊ฐ€ ์„ ์–ธ๋˜๋Š” ๋ฐฉ์‹์— ๋”ฐ๋ผ ์šฐ์„ ์ˆœ์œ„๊ฐ€ ์กด์žฌ
  • CLI์—์„œ ์ž…๋ ฅ < default ๊ฐ’ < ํ™˜๊ฒฝ๋ณ€์ˆ˜ < terraform.tfvars < *.auto.tfvars < *auto.tfvars.json < -var ๋˜๋Š” -var-file๋กœ ๋ณ€์ˆ˜ ์ง€์ •
  • ํ™˜๊ฒฝ๋ณ€์ˆ˜๋Š” โ€˜TF_VAR_๋ณ€์ˆ˜์ด๋ฆ„โ€™์œผ๋กœ ์„ ์–ธ
  • *.atuo.tfvars๊ณผ *.auto.tfvars.json โ†’ ํŒŒ์ผ๋ช…์— ๋”ฐ๋ผ ์šฐ์„ ์ˆœ์œ„ ์ ์šฉ(a.auto.tfvars๋ณด๋‹ค b.auto.tfvars์˜ ์šฐ์„ ์ˆœ์œ„๊ฐ€ ๋†’๋‹ค, *.auto.tfvars.json๋„ ๋™์ผ)
  • ๋ณ€์ˆ˜ ์„ ์–ธ ๋ฐฉ์‹์ด ๋‹ค์–‘ํ•œ ์ด์œ  โ†’ ํ…Œ๋ผํผ ์‹คํ–‰ ํ™˜๊ฒฝ, ์‹คํ–‰ ๋ฐฉ์‹์— ๋”ฐ๋ผ ๋™์ผํ•œ ์ฝ”๋“œ๋กœ ๋‹ค์ˆ˜์˜ ํ”„๋กœ๋น„์ €๋‹์„ ์ˆ˜ํ–‰ํ•˜๋„๋ก ๋””์ž์ธ

3-7. local(์ง€์—ญ ๊ฐ’)


  • local โ†’ ์ฝ”๋“œ ๋‚ด์—์„œ ๊ฐ€๊ณต๋˜์–ด ๋™์ž‘ํ•˜๋Š” ๊ฐ’์„ ์„ ์–ธ(locals ๋ธ”๋Ÿญ์œผ๋กœ ์„ ์–ธ)
  • ๋ณ€์ˆ˜์ฒ˜๋Ÿผ ์‹คํ–‰ ์‹œ์— ์ž…๋ ฅ๋ฐ›์„ ์ˆ˜ ์—†๋‹ค.
  • ๊ฐ’์ด๋‚˜ ํ‘œํ˜„์‹์„ ๋ฐ˜๋ณต์ ์œผ๋กœ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ๋Š” ํŽธ์˜์„ฑ์„ ์ œ๊ณต
    โ†’ ๋นˆ๋ฒˆํ•˜๊ฒŒ ์—ฌ๋Ÿฌ ๊ณณ์—์„œ ์‚ฌ์šฉํ•˜๋Š” ๊ฒฝ์šฐ ์‹ค์ œ ๊ฐ’์— ๋Œ€ํ•œ ์ถ”์ ์ด ์–ด๋ ค์›Œ์ ธ ๊ด€๋ฆฌ์˜ ์ธก๋ฉด์—์„œ ๋ถ€๋‹ด์ด ๋ฐœ์ƒํ•  ์ˆ˜ ์žˆ๋‹ค.
  • ๋™์ผํ•œ tfํŒŒ์ผ ๋‚ด์—์„œ ์—ฌ๋Ÿฌ๋ฒˆ ์„ ์–ธ ๊ฐ€๋Šฅํ•˜๊ณ  ์—ฌ๋Ÿฌ ํŒŒ์ผ์— ๊ฑธ์ณ ๋งŒ๋“œ๋Š” ๊ฒƒ๋„ ๊ฐ€๋Šฅ
    โ†’ locals์— ์„ ์–ธํ•œ ์ด๋ฆ„์€ ์ „์ฒด ๋ฃจํŠธ ๋ชจ๋“ˆ ๋‚ด์—์„œ ์œ ์ผํ•ด์•ผ ํ•ฉ๋‹ˆ๋‹ค.
locals {
    name = "tf101"
    my_info = {
        name = "hyuckang"
        region = "KR"
    }
}
# local.name -> tf101
# local.my_info.name -> hyuckang

3-8. ์ถœ๋ ฅ(output)


  • output โ†’ ํ”„๋กœ๋น„์ €๋‹ ์ˆ˜ํ–‰ ํ›„์˜ ๊ฒฐ๊ณผ ๊ฐ’์„ ํ™•์ธํ•˜๋Š” ์šฉ๋„
  • ํ…Œ๋ผํผ ๋ชจ๋“ˆ ๊ฐ„ ๋˜๋Š” ์›Œํฌ์ŠคํŽ˜์ด์Šค ๊ฐ„ ๋ฐ์ดํ„ฐ ์ ‘๊ทผ ์šฉ๋„
  • output ๊ฒฐ๊ณผ์—์„œ ๋ฆฌ์†Œ์Šค ์ƒ์„ฑ ํ›„ ๊ฒฐ์ •๋˜๋Š” ์†์„ฑ ๊ฐ’์€ ํ”„๋กœ๋น„์ €๋‹์ด ์™„๋ฃŒ๋˜์–ด์•ผ ์ตœ์ข…์ ์œผ๋กœ ๊ฒฐ๊ณผ๋ฅผ ํ™•์ธ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    โ†’ ์ด๋Ÿฐ ๊ฒฝ์šฐ terraform plan์—์„œ ๊ฐ’์„ ์ถœ๋ ฅํ•  ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค.

3-9. ๋ฐ˜๋ณต๋ฌธ


count

  • ์„ ์–ธ๋œ ์ •์ˆ˜(count)๋งŒํผ ๋ฆฌ์†Œ์Šค๋‚˜ ๋ชจ๋“ˆ์„ ์ƒ์„ฑ
  • count์—์„œ ์ƒ์„ฑ๋˜๋Š” ์ฐธ์กฐ๊ฐ’์€ count.index์ด๋ฉฐ ์ธ๋ฑ์Šค๋Š” 0๋ถ€ํ„ฐ ์‹œ์ž‘ํ•ด 1์”ฉ ์ฆ๊ฐ€
resource "local_file" "count_files" {
    count = 5
    content = "abc"
    filename = "abc${count.index}.txt"
}

# count๋กœ ์ƒ์„ฑํ•œ ๋ฆฌ์†Œ์Šค ์ฐธ์กฐ
<๋ฆฌ์†Œ์Šค ํƒ€์ž…>.<์ด๋ฆ„>[<์ธ๋ฑ์Šค ๋ฒˆํ˜ธ>]
local_file.count_files[0].filename # abc0.txt
  • count์™€ list๋ฅผ ํ™œ์šฉํ•˜์—ฌ ๋ฆฌ์†Œ์Šค๋ฅผ ์ƒ์„ฑํ•œ ๊ฒฝ์šฐ
    โ†’ list ์ค‘๊ฐ„์— ๊ฐ’์ด ์‚ญ์ œ๋˜๋ฉด ์˜๋„ํ•˜์ง€ ์•Š์€ ์‚ญ์ œ ๋ฐ ์žฌ์ƒ์„ฑ์ด ์ผ์–ด๋‚  ์ˆ˜ ์žˆ๋‹ค.

for_each

  • map ๋˜๋Š” set์„ ์ด์šฉํ•˜์—ฌ ์„ ์–ธ๋œ key์˜ ๊ฐœ์ˆ˜๋งŒํผ ๋ฆฌ์†Œ์Šค๋ฅผ ์ƒ์„ฑ
  • key ๊ฐ’์€ count์˜ index์™€๋Š” ๋‹ฌ๋ฆฌ ๊ณ ์œ ํ•˜๋ฏ€๋กœ ์ค‘๊ฐ„์— ๊ฐ’์„ ์‚ญ์ œํ•œ ํ›„ ๋‹ค์‹œ ์ ์šฉํ•ด๋„ ์‚ญ์ œํ•œ ๊ฐ’์— ๋Œ€ํ•ด์„œ๋งŒ ๋ฆฌ์†Œ์Šค๋ฅผ ์‚ญ์ œ
  • each.key์™€ each.value๋ฅผ ํ†ตํ•ด ์ฝ”๋“œ๋‚ด์—์„œ ์ฐธ์กฐ ๊ฐ€๋Šฅ
# AAA๋ผ๋Š” ๋‚ด์šฉ์„ ๊ฐ€์ง„ key_a.txt์™€ BBB๋ผ๋Š” ๋‚ด์šฉ์„ ๊ฐ€์ง„ key_b.txt๊ฐ€ ์ƒ์„ฑ๋˜๋Š” ์ฝ”๋“œ
resource "local_file" "for_each_test" {
    for_each = {
        key_a = "AAA"
        key_b = "BBB"
    }
    content = each.value
    filename = "${each.key}.txt"
}

for

  • ๋ณตํ•ฉ ํ˜•์‹ ๊ฐ’์˜ ๋ฐ˜๋ณตํ•˜๋Š”๋ฐ ์‚ฌ์šฉ

  • for๋ฌธ์„ [ ]๋กœ ๋ฌถ์œผ๋ฉด tuple์ด ๋ฐ˜ํ™˜๋˜๊ณ , { }๋กœ ๋ฌถ์œผ๋ฉด object๊ฐ€ ๋ฐ˜ํ™˜๋œ๋‹ค.

  • object์˜ ๊ฒฝ์šฐ์— ํ‚ค์™€ ๊ฐ’์— ๋Œ€ํ•œ ์Œ์€ => ๊ธฐํ˜ธ๋กœ ๊ตฌ๋ถ„ํ•œ๋‹ค.

  • list์™€ for

      # ๊ฐ’ ๋˜๋Š” ์ธ๋ฑ์Šค๋ฅผ ๋ฐ˜๋ณต -> ์ธ์ˆ˜๊ฐ€ 1๊ฐœ์ธ ๊ฒฝ์šฐ "๊ฐ’"๋งŒ ๋ฐ˜๋ณต, ์ธ์ˆ˜๊ฐ€ 2๊ฐœ์ธ ๊ฒฝ์šฐ "์ธ๋ฑ์Šค์™€ ๊ฐ’"์„ ๋ฐ˜๋ณต
      # ๊ด€์šฉ์ ์œผ๋กœ ๊ฐ’์€ v, ์ธ๋ฑ์Šค๋Š” i๋กœ ํ‘œํ˜„
    
      output "list_one_argument" {
        value = [for v in [1, 2, 3] : "value : ${v}"]
      }
      # list_one_argument์˜ ์ถœ๋ ฅ ๊ฒฐ๊ณผ
      list_one_argument = [
        "value : 1",
        "value : 2",
        "value : 3",
      ]
    
      output "list_two_argument" {
        value = [for i, v in [1, 2, 3] : "index : ${i} / value : ${v}"] # ์ถœ๋ ฅ index : 0 / value : 1
      }
      # list_two_argument์˜ ์ถœ๋ ฅ ๊ฒฐ๊ณผ
      list_two_argument = [
        "index : 0 / value : 1",
        "index : 1 / value : 2",
        "index : 2 / value : 3",
      ]
  • map๊ณผ for

      # ํ‚ค ๋˜๋Š” ์ธ๋ฑ์Šค๋ฅผ ๋ฐ˜๋ณต -> ์ธ์ˆ˜๊ฐ€ 1๊ฐœ์ธ ๊ฒฝ์šฐ "ํ‚ค"๋งŒ ๋ฐ˜๋ณต, ์ธ์ˆ˜๊ฐ€ 2๊ฐœ์ธ ๊ฒฝ์šฐ "ํ‚ค์™€ ๊ฐ’"์„ ๋ฐ˜๋ณต
      # ๊ด€์šฉ์ ์œผ๋กœ ํ‚ค๋Š” k, ๊ฐ’์€ v๋กœ ํ‘œํ˜„
      variable "members" {
        default = {
          name_a = { role = "guest", group = "infra" },
          name_b = { role = "member", group = "dev" },
          name_c = { role = "admin", group = "infra" },
        }
      }
    
      output "print_role" {
        value = [for k, v in var.members : "${k} has ${v.role}"]
      }
    
      # print_role์˜ ์ถœ๋ ฅ ๊ฒฐ๊ณผ
      print_role = [
        "name_a has guest",
        "name_b has member",
        "name_c has admin",
      ]

dynamic

  • ๋ฆฌ์†Œ์Šค ์ž์ฒด์˜ ๋ฐ˜๋ณต์ด ์•„๋‹Œ ๋ฆฌ์†Œ์Šค ๋‚ด์˜ ๋ธ”๋ก ์†์„ฑ(Attribute as Blocks)์„ ๋ฐ˜๋ณตํ•˜๋Š” ๊ฒฝ์šฐ โ†’ dynamic
  • ๊ธฐ์กด ๋ธ”๋ก์˜ ์†์„ฑ ์ด๋ฆ„์„ dynamic ๋ธ”๋ก์˜ ์ด๋ฆ„ ์„ ์–ธํ•˜๊ณ , ๊ธฐ์กด ๋ธ”๋ก์˜ ์†์„ฑ์„ content ๋ธ”๋ก์— ์ž‘์„ฑํ•œ๋‹ค.
# ๊ธฐ์กด์˜ ๋ฆฌ์†Œ์Šค ๋‚ด์˜ ๋ฐ˜๋ณต
resource "provider_resource" "name" {
  some_setting {
    key = a_value
  }
  some_setting {
    key = b_value
  }
  some_setting {
    key = c_value
  }
}

# ๋ฆฌ์†Œ์Šค ๋‚ด์˜ ๋ฐ˜๋ณต์„ dynamic์œผ๋กœ ๋ณ€๊ฒฝ
resource "provider_resource" "name" {
  dynamic "some_setting" {
    for_each = {
      a_key = a_value
      b_key = b_value
      c_key = c_value
    }
  }
  content {
    key = some_setting.value
  }
}
๋ฐ˜์‘ํ˜•