Terraform/OpenTofu 기초 · 변수의 형 · 실습
형을 안 적었더니 오류가 엉뚱한 줄에서 났다
목표
기본형·컬렉션형·구조형을 하나씩 선언해 무엇이 변수 경계에서 막히고 무엇이 조용히 변환되는지 확인합니다. 선택 속성과 기본값, null 을 받지 않겠다는 선언, 그리고 형을 적지 않았을 때 오류가 어디서 나는지까지 봅니다.
왜 중요한가
형은 문서가 아니라 검문소입니다. 형을 적어 두면 잘못된 값이 변수 경계에서 tfvars 줄 번호와 함께 막히고, 적지 않으면 그 값이 저 안쪽까지 흘러 들어가 엉뚱한 메시지로 터집니다. 같은 실수인데 고치는 데 드는 시간이 열 배 차이 납니다. 그런데 형 검사는 막기만 하는 것이 아니라 바꾸기도 합니다. 문자열로 적은 숫자는 숫자가 되고, 원소 형을 지정한 맵에 숫자를 넣으면 문자열이 됩니다. 이 변환은 오류 없이 일어나므로, 나중에 비교나 산술을 하려는 값이라면 미리 알고 있어야 합니다. 반대로 구조형은 선언에 없는 속성을 아무 말 없이 버립니다 — 속성 이름에 오타를 내면 기본값이 적용된 것처럼 보입니다. 무엇이 막히고 무엇이 바뀌고 무엇이 사라지는지, 이 셋을 구분하는 것이 이 모듈의 전부입니다.
단계
1. /root/tfb-types/prim/main.tf 에 string 변수 name, number 변수 replicas, bool 변수 debug 와 세 개의 출력을 두세요. ok.tfvars 에는 name = "api", replicas = "3", debug = "true" 를 적어 apply 하고 tofu output -json 을 /root/tfb-types/prim.json 에 저장하세요. bad.tfvars 에는 replicas 에 목록을 넣어 plan 을 돌리고 오류 출력을 /root/tfb-types/prim-bad.txt 에 저장하세요.
2. /root/tfb-types/quiet/main.tf 에 map(string) 변수 tags 와 list(string) 변수 ids, 두 개의 출력을 두세요. v.tfvars 에서 tags 에는 team = "core", rev = 3, tls = true 를, ids 에는 [1, 2, 10] 을 주고 apply 한 뒤 tofu output -json 을 /root/tfb-types/quiet.json 에 저장하세요.
3. /root/tfb-types/coll/main.tf 에 list(string) 변수 as_list, set(string) 변수 as_set, tuple([string, number, bool]) 변수 as_tuple 과 다섯 개의 출력(세 값과 목록·집합의 길이)을 두세요. v.tfvars 에서 앞의 두 변수에 똑같이 ["b", "a", "b"] 를, 튜플에 ["web", 3, true] 를 주고 apply 한 뒤 tofu output -json 을 /root/tfb-types/coll.json 에 저장하세요. 이어서 튜플 원소를 두 개만 준 bad.tfvars 로 plan 을 돌려 오류를 /root/tfb-types/tuple-bad.txt 에 저장하세요.
4. /root/tfb-types/obj/main.tf 에 object({ name = string, port = number }) 변수 svc 와 출력 하나를 두세요. ok.tfvars 에는 name·port 에 더해 선언에 없는 owner = "team-a" 까지 적어 apply 하고 tofu output -json 을 /root/tfb-types/obj.json 에 저장하세요. bad.tfvars 에는 name 을 빼고 plan 을 돌려 오류를 /root/tfb-types/obj-bad.txt 에 저장하세요.
5. /root/tfb-types/opt/main.tf 에 svc 변수를 오브젝트로 두되 name 만 필수로 하고 port(기본 8080), tls(기본 false), tags(기본 빈 맵), aliases(기본 빈 목록)는 선택으로 선언하세요. v.tfvars 에는 name 만 주고 apply 한 뒤 tofu output -json 을 /root/tfb-types/opt.json 에 저장하세요.
6. /root/tfb-types/nul/main.tf 에 nullable = false 인 변수 두 개를 두세요 — 기본값 "a" 가 있는 zone 과 기본값이 없는 must. 출력도 둘 두세요. ok.tfvars 에 zone = null, must = "x" 를 주고 apply 한 뒤 tofu output -json 을 /root/tfb-types/nul.json 에 저장하세요. bad.tfvars 에는 must = null 만 주고 plan 을 돌려 오류를 /root/tfb-types/nul-bad.txt 에 저장하세요.
7. /root/tfb-types/late/ 에 any 형 변수 loose 와 그 길이를 내보내는 출력을 두고, /root/tfb-types/tight/ 에는 같은 모양이되 list(string) 형 변수 tight 를 두세요. 두 곳 모두 v.tfvars 에 값 7 을 주고 plan 을 돌려 출력을 각각 /root/tfb-types/late.txt 와 /root/tfb-types/tight.txt 에 저장하세요. 그다음 두 오류의 첫 줄만 뽑아 /root/tfb-types/blame.txt 에 late=<첫 오류 줄> 과 tight=<첫 오류 줄> 두 줄로 적으세요(Error: 뒤의 문구만).
8. /root/tfb-types/schema/main.tf 에 service 변수를 5단계와 같은 모양(필수 name, 선택 port·tls·tags·aliases)으로 두고, 그 값으로 service.conf 를 만드세요. 다섯 줄은 name=, port=, tls=, tags=(JSON 으로 인코딩), aliases=(콤마로 이어 붙임) 입니다. v.tfvars 에는 name = "api", port = "9090", tags = { team = "core", rev = 3 }, aliases = ["api-1", "api-2"] 를 주고 apply 하세요. 채점기가 이 설정의 사본에 잘못된 입력 두 가지를 넣어 거절되는지 확인합니다.
참고
- 형은 '모양' 을 보고 validation 블록은 '값의 범위' 를 봅니다. 두 가지는 서로를 대신하지 못합니다.
- 출력 JSON 에는 값과 함께 형도 들어 있어, 무엇으로 들어갔는지 눈으로 확인하기 좋습니다.
- 명령줄로 값을 줄 때 기본형 변수는 따옴표까지 값의 일부로 받습니다. 이 실습에서는 헷갈리지 않게 tfvars 파일만 씁니다.
- 흔한 실수: 3단계의 bad.tfvars 를 고쳐 통과시키는 것. 그 파일은 틀린 채로 두어야 오류가 확인됩니다.
- [입력 변수](https://opentofu.org/docs/language/values/variables/) · [형 제약](https://opentofu.org/docs/language/expressions/type-constraints/) · [타입과 값](https://opentofu.org/docs/language/expressions/types/) · [Type Constraints (HashiCorp)](https://developer.hashicorp.com/terraform/language/expressions/type-constraints)
단계 8개
- 기본형은 변수 경계에서 걸린다
- 컬렉션 안에서는 변환이 조용히 일어난다
- 같은 입력을 목록·집합·튜플로 받으면 다르게 남는다
- 오브젝트는 빠지면 막고 남으면 조용히 버린다
- 선택 속성과 기본값으로 짧은 입력을 받는다
- null 을 받지 않겠다는 선언은 두 갈래로 동작한다
- any 로 받으면 오류가 저 안쪽에서 난다
- 중첩 형으로 입력 규격을 못 박는다