Terraform/OpenTofu 기초 · 표현식과 내장 함수 · 실습
값을 손으로 이어 붙이다 따옴표에 졌다
목표
문자열·컬렉션·조건·변환·템플릿·직렬화 함수를 콘솔에서 한 줄씩 확인한 뒤, 그대로 설정에 옮겨 실제 파일을 만듭니다. 마지막에는 값을 하나도 직접 적지 않고 변수에서만 끌어 쓰는 설정을 만들어 다른 입력에도 버티는지 확인합니다.
왜 중요한가
설정 파일이 길어지는 이유는 대개 같은 값을 여러 곳에 적기 때문입니다. 이름을 조합하는 규칙, 환경마다 다른 값, 맵을 합칠 때의 우선순위 같은 것을 함수로 적어 두면 값 하나를 바꿀 때 고칠 자리가 한 곳으로 줄어듭니다. 그리고 함수는 콘솔에서 한 줄로 확인할 수 있어, 표현식이 헷갈릴 때 적용을 반복하는 비용이 사라집니다. 실패를 다루는 함수도 중요합니다. 바깥에서 들어온 데이터는 언제든 깨질 수 있는데, 그때마다 적용 전체가 멈추면 운영이 남의 실수에 묶입니다. 실패를 값으로 바꾸는 함수를 알면 기본값으로 내려앉는 설계를 할 수 있습니다. 마지막으로 직렬화 함수는 따옴표와 이스케이프를 사람이 책임지지 않게 해 줍니다 — 손으로 이어 붙인 JSON 은 언젠가 반드시 깨집니다.
단계
1. /root/tfb-func/play 를 만들고 local 프로바이더만 선언한 main.tf 로 init 하세요. /root/tfb-func/strings-in.txt 에 여섯 줄을 적으세요 — join("-", ["web", "prod", "01"]), format("%s-%03d", "node", 7), replace("db-prod-01", "prod", "stage"), trimspace(" padded "), substr("abcdefgh", 2, 3), upper(join("_", sort(["b", "a"]))). 그 파일을 tofu console 에 흘려 넣어 결과를 /root/tfb-func/strings-out.txt 에 저장하세요.
2. /root/tfb-func/coll/main.tf 에 map(number) 변수 ports(web 80, api 8080)와, merge 로 두 태그 맵을 합친 local.tags, sort(keys(...)) 로 만든 local.names, lookup 으로 읽은 local.api(있는 키)와 local.db(없는 키, 기본값 5432), distinct 로 중복을 없앤 local.unique 를 두고 다섯 개의 출력으로 내보내세요. init·apply 한 뒤 tofu output -json 을 /root/tfb-func/collections.json 에 저장하세요.
3. /root/tfb-func/cond/main.tf 에 기본값이 prod 인 변수 env 와, var.env == "prod" 를 담은 local.is_prod, 그것으로 고르는 local.replicas(3 또는 1), local.log_level(warn 또는 debug), local.backup(daily 또는 none), format 으로 만든 local.endpoint(포트는 443 또는 8080)를 두고, 네 값을 키=값 네 줄로 쓰는 app.conf 를 만드세요. init·apply 한 뒤, tofu console -var env=dev 로 같은 네 값을 평가해 /root/tfb-func/cond-dev.txt 에 저장하세요.
4. /root/tfb-func/guard/ 에 올바른 JSON good.json(name 이 api, port 가 8080)과 깨진 JSON bad.json 을 만드세요. main.tf 에서 두 파일을 try(jsondecode(...), {}) 로 읽고, 있는 키와 없는 키를 각각 try(..., "unknown") 으로 꺼내고, can(jsondecode(...)) 로 두 파일의 성공 여부를 담아 다섯 개의 출력(name·miss·bad_keys·ok_good·ok_bad)으로 내보내세요. apply 한 뒤 tofu output -json 을 /root/tfb-func/guard.json 에 저장하세요.
5. /root/tfb-func/tpl/site.tftpl 에 이름 한 줄, 포트 목록을 도는 반복, TLS 여부에 따른 조건을 담은 템플릿을 쓰고, main.tf 에서 templatefile 로 name = "api", ports = [80, 443], tls = true 를 넘겨 site.conf 를 만드세요. 결과는 server { 로 시작해 name = api, listen 80;, listen 443;, tls on;, } 여섯 줄이어야 합니다.
6. /root/tfb-func/enc/main.tf 에 local.data(name = api, ports = [80, 443], tls = true)를 두고 jsonencode 로 data.json, yamlencode 로 data.yaml 을 만드세요. apply 한 뒤 jq -c . 로 읽은 결과를 /root/tfb-func/enc-json.txt 에, yq -o=json -I=0 . 로 읽은 결과를 /root/tfb-func/enc-yaml.txt 에 저장하세요. 두 파일의 내용은 같아야 합니다.
7. /root/tfb-func/convert-in.txt 에 여섯 줄을 적으세요 — parseint("ff", 16), tonumber("007"), tostring(true), try(tonumber("abc"), -1), can(tonumber("abc")), format("%s has %d ports", "api", length([80, 443])). /root/tfb-func/play 에서 콘솔에 흘려 넣어 결과를 /root/tfb-func/convert-out.txt 에 저장하세요.
8. /root/tfb-func/compose/main.tf 에 list(string) 변수 names(기본 api, web, db)와 list(number) 변수 ports(기본 8080, 80, 5432)를 두고, formatlist 로 이름=포트 줄 목록을 만들고 join 으로 이어 붙이고 format 과 length 로 # <개수> services 머리글을 만들어 services.conf 를 만드세요. 첫 줄은 머리글, 그 뒤가 서비스 줄입니다. 값을 직접 적지 말고 변수에서만 끌어 쓰세요 — 채점기가 다른 입력으로 같은 설정을 적용해 봅니다.
참고
- 콘솔은 지금 디렉터리의 변수와 locals 를 읽으므로 init 이 끝난 디렉터리에서 돌려야 합니다.
- 콘솔은 첫 오류에서 멈추고 0 이 아닌 코드로 끝납니다. 여러 줄을 흘려 넣을 때는 앞줄이 성공해야 뒷줄이 평가됩니다.
- 흔한 실수: 4단계의 깨진 JSON 을 고쳐 버리는 것. 그 파일은 깨진 채로 두어야 흡수가 확인됩니다.
- 흔한 실수: 8단계에서 서비스 개수를 3 으로 적어 두는 것. 입력이 바뀌면 머리글만 틀리게 됩니다.
- [함수 목록](https://opentofu.org/docs/language/functions/) · [templatefile](https://opentofu.org/docs/language/functions/templatefile/) · [try](https://opentofu.org/docs/language/functions/try/) · [can](https://opentofu.org/docs/language/functions/can/) · [jsonencode](https://opentofu.org/docs/language/functions/jsonencode/) · [yamlencode](https://opentofu.org/docs/language/functions/yamlencode/) · [조건 표현식](https://opentofu.org/docs/language/expressions/conditionals/)
단계 8개
- 문자열 함수를 콘솔에서 확인한다
- 맵과 목록을 합치고 뽑는다
- 조건 표현식으로 환경별 값을 고른다
- 깨진 입력을 값으로 흡수한다
- 템플릿으로 설정 파일을 찍어 낸다
- 같은 데이터를 두 형식으로 내보낸다
- 변환 함수와 그 실패를 확인한다
- 함수를 엮어 설정 파일 하나로 모은다