Terraform/OpenTofu Fundamentals
No Type Declared, So the Error Landed on the Wrong Line
한국어 원문으로 표시합니다.
목표
기본형·컬렉션형·구조형을 하나씩 선언해 무엇이 변수 경계에서 막히고 무엇이 조용히 변환되는지 확인합니다. 선택 속성과 기본값, null 을 받지 않겠다는 선언, 그리고 형을 적지 않았을 때 오류가 어디서 나는지까지 봅니다.
왜 중요한가
형은 문서가 아니라 검문소입니다. 형을 적어 두면 잘못된 값이 변수 경계에서 tfvars 줄 번호와 함께 막히고, 적지 않으면 그 값이 저 안쪽까지 흘러 들어가 엉뚱한 메시지로 터집니다. 같은 실수인데 고치는 데 드는 시간이 열 배 차이 납니다. 그런데 형 검사는 막기만 하는 것이 아니라 바꾸기도 합니다. 문자열로 적은 숫자는 숫자가 되고, 원소 형을 지정한 맵에 숫자를 넣으면 문자열이 됩니다. 이 변환은 오류 없이 일어나므로, 나중에 비교나 산술을 하려는 값이라면 미리 알고 있어야 합니다. 반대로 구조형은 선언에 없는 속성을 아무 말 없이 버립니다 — 속성 이름에 오타를 내면 기본값이 적용된 것처럼 보입니다. 무엇이 막히고 무엇이 바뀌고 무엇이 사라지는지, 이 셋을 구분하는 것이 이 모듈의 전부입니다.
단계
/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에 저장하세요./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에 저장하세요./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에 저장하세요./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에 저장하세요./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에 저장하세요./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에 저장하세요./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:뒤의 문구만)./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 를 고쳐 통과시키는 것. 그 파일은 틀린 채로 두어야 오류가 확인됩니다.
- 입력 변수 · 형 제약 · 타입과 값 · Type Constraints (HashiCorp)
기본형은 변수 경계에서 걸린다
/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 에 저장하세요.
따옴표가 붙은 값이라도 형에 맞게 바꿀 수 있으면 도구가 바꿔 줍니다. 출력 JSON 에는 값뿐 아니라 형도 함께 나오니 무엇으로 들어갔는지 눈으로 확인하세요.
컬렉션 안에서는 변환이 조용히 일어난다
/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 에 저장하세요.
원소의 형을 지정한 컬렉션은 넣는 값을 그 형으로 바꿔서 담습니다. 숫자와 참거짓이 문자열이 되어도 오류가 나지 않으니, 나중에 비교나 산술을 하려는 값이라면 이 변환을 알고 있어야 합니다.
같은 입력을 목록·집합·튜플로 받으면 다르게 남는다
/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 에 저장하세요.
목록은 적은 순서와 중복을 그대로 지키고, 집합은 중복을 버리고 자기 규칙대로 정렬합니다. 튜플은 자리마다 형이 정해진 고정 길이라 개수가 다르면 그 자리에서 막힙니다.
오브젝트는 빠지면 막고 남으면 조용히 버린다
/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 에 저장하세요.
오브젝트 형은 선언한 속성만 받아들이고, 선언에 없는 속성은 오류가 아니라 버림입니다. 그래서 오타 난 속성 이름은 아무 말 없이 사라지고, 기본값이 적용된 것처럼 보이게 됩니다.
선택 속성과 기본값으로 짧은 입력을 받는다
/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 에 저장하세요.
선택 속성은 두 번째 인자로 기본값을 받습니다. 기본값을 주지 않으면 그 속성은 null 이 되어 하류에서 다시 확인해야 하므로, 기본값을 함께 적는 편이 쓰는 쪽을 편하게 합니다.
null 을 받지 않겠다는 선언은 두 갈래로 동작한다
/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 에 저장하세요.
null 을 받지 않겠다고 선언했을 때, 기본값이 있으면 null 은 기본값으로 대체되고 기본값이 없으면 오류가 됩니다. 값이 없을 때 무엇이 되는지를 한 곳에서 못 박아 두는 장치입니다.
any 로 받으면 오류가 저 안쪽에서 난다
/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: 뒤의 문구만).
형을 적어 두지 않으면 잘못된 값이 변수 경계를 그대로 통과합니다. 그러면 오류는 그 값을 쓰는 자리에서 나고, 메시지는 변수가 아니라 함수 이야기를 합니다. 형을 좁히면 같은 실수가 tfvars 줄 번호와 함께 앞에서 막힙니다.
중첩 형으로 입력 규격을 못 박는다
/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 하세요. 채점기가 이 설정의 사본에 잘못된 입력 두 가지를 넣어 거절되는지 확인합니다.
형을 제대로 적어 두면 잘못된 입력이 tfvars 줄 번호와 함께 그 자리에서 막힙니다. 문자열로 적은 포트가 숫자로 들어가는 것과 맵 안의 숫자가 문자열이 되는 것, 두 변환이 한 입력에서 함께 일어나니 결과를 눈으로 확인하세요.