LabHub
배우기 러닝패스 코스

Terraform/OpenTofu基礎

値を手でつなげて引用符に負けた

LabHub 에서 이어서 보기

한국어 원문으로 표시합니다.

목표

문자열·컬렉션·조건·변환·템플릿·직렬화 함수를 콘솔에서 한 줄씩 확인한 뒤, 그대로 설정에 옮겨 실제 파일을 만듭니다. 마지막에는 값을 하나도 직접 적지 않고 변수에서만 끌어 쓰는 설정을 만들어 다른 입력에도 버티는지 확인합니다.

왜 중요한가

설정 파일이 길어지는 이유는 대개 같은 값을 여러 곳에 적기 때문입니다. 이름을 조합하는 규칙, 환경마다 다른 값, 맵을 합칠 때의 우선순위 같은 것을 함수로 적어 두면 값 하나를 바꿀 때 고칠 자리가 한 곳으로 줄어듭니다. 그리고 함수는 콘솔에서 한 줄로 확인할 수 있어, 표현식이 헷갈릴 때 적용을 반복하는 비용이 사라집니다. 실패를 다루는 함수도 중요합니다. 바깥에서 들어온 데이터는 언제든 깨질 수 있는데, 그때마다 적용 전체가 멈추면 운영이 남의 실수에 묶입니다. 실패를 값으로 바꾸는 함수를 알면 기본값으로 내려앉는 설계를 할 수 있습니다. 마지막으로 직렬화 함수는 따옴표와 이스케이프를 사람이 책임지지 않게 해 줍니다 — 손으로 이어 붙인 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.tfmap(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(nameapi, 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 에서 templatefilename = "api", ports = [80, 443], tls = true 를 넘겨 site.conf 를 만드세요. 결과는 server { 로 시작해 name = api, listen 80;, listen 443;, tls on;, } 여섯 줄이어야 합니다.
  6. /root/tfb-func/enc/main.tflocal.data(name = api, ports = [80, 443], tls = true)를 두고 jsonencodedata.json, yamlencodedata.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.tflist(string) 변수 names(기본 api, web, db)와 list(number) 변수 ports(기본 8080, 80, 5432)를 두고, formatlist이름=포트 줄 목록을 만들고 join 으로 이어 붙이고 formatlength# <개수> services 머리글을 만들어 services.conf 를 만드세요. 첫 줄은 머리글, 그 뒤가 서비스 줄입니다. 값을 직접 적지 말고 변수에서만 끌어 쓰세요 — 채점기가 다른 입력으로 같은 설정을 적용해 봅니다.

참고

문자열 함수를 콘솔에서 확인한다

/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 에 저장하세요.

콘솔은 파일을 흘려 넣으면 한 줄씩 평가해 결과만 찍습니다. format 의 자리 표시자는 서식 문자열 규칙을 그대로 따르고, substr 의 두 번째 인자는 길이가 아니라 시작 위치입니다.

맵과 목록을 합치고 뽑는다

/root/tfb-func/coll/main.tfmap(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 에 저장하세요.

merge 는 뒤에 온 맵이 이깁니다. lookup 의 세 번째 인자는 키가 없을 때의 기본값이고, 이것을 빠뜨리면 없는 키에서 오류가 납니다. keys 는 정렬을 보장하지 않으니 sort 로 감쌉니다.

조건 표현식으로 환경별 값을 고른다

/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 에 저장하세요.

조건 표현식은 참일 때와 거짓일 때의 타입이 같아야 합니다. 콘솔에 변수 값을 주면 설정을 고치지 않고 다른 분기의 결과를 볼 수 있어, 적용을 반복하지 않고도 확인이 끝납니다.

깨진 입력을 값으로 흡수한다

/root/tfb-func/guard/ 에 올바른 JSON good.json(nameapi, 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 에 저장하세요.

try 는 앞 인자의 평가가 실패하면 다음 인자를 내놓고, can 은 성공 여부를 참거짓으로 바꿔 줍니다. 둘 다 실행 중에 생기는 오류만 잡습니다 — 선언조차 없는 참조 같은 정적 오류는 잡지 못합니다.

템플릿으로 설정 파일을 찍어 낸다

/root/tfb-func/tpl/site.tftpl 에 이름 한 줄, 포트 목록을 도는 반복, TLS 여부에 따른 조건을 담은 템플릿을 쓰고, main.tf 에서 templatefilename = "api", ports = [80, 443], tls = true 를 넘겨 site.conf 를 만드세요. 결과는 server { 로 시작해 name = api, listen 80;, listen 443;, tls on;, } 여섯 줄이어야 합니다.

템플릿의 반복과 조건은 백분율 기호로 시작하는 지시문입니다. 지시문 줄이 결과에 빈 줄로 남지 않게 하려면 닫는 중괄호 앞에 공백 제거 표시를 붙입니다. 템플릿 파일 확장자는 자유지만 관례가 있습니다.

같은 데이터를 두 형식으로 내보낸다

/root/tfb-func/enc/main.tflocal.data(name = api, ports = [80, 443], tls = true)를 두고 jsonencodedata.json, yamlencodedata.yaml 을 만드세요. apply 한 뒤 jq -c . 로 읽은 결과를 /root/tfb-func/enc-json.txt 에, yq -o=json -I=0 . 로 읽은 결과를 /root/tfb-func/enc-yaml.txt 에 저장하세요. 두 파일의 내용은 같아야 합니다.

두 함수는 같은 값을 다른 표기로 옮길 뿐이라 되읽으면 같은 데이터가 나옵니다. 설정 파일을 손으로 이어 붙이는 대신 이 함수들을 쓰면 따옴표와 이스케이프를 도구가 책임집니다.

변환 함수와 그 실패를 확인한다

/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 에 저장하세요.

변환 함수는 바꿀 수 없는 값을 만나면 오류를 냅니다. 그 오류를 값으로 바꾸는 것이 try 이고, 참거짓으로 바꾸는 것이 can 입니다. 진법이 10 이 아닌 문자열에는 전용 함수가 따로 있습니다.

함수를 엮어 설정 파일 하나로 모은다

/root/tfb-func/compose/main.tflist(string) 변수 names(기본 api, web, db)와 list(number) 변수 ports(기본 8080, 80, 5432)를 두고, formatlist이름=포트 줄 목록을 만들고 join 으로 이어 붙이고 formatlength# <개수> services 머리글을 만들어 services.conf 를 만드세요. 첫 줄은 머리글, 그 뒤가 서비스 줄입니다. 값을 직접 적지 말고 변수에서만 끌어 쓰세요 — 채점기가 다른 입력으로 같은 설정을 적용해 봅니다.

formatlist 는 여러 목록을 나란히 돌며 같은 서식을 적용합니다. 머리글의 개수는 세어서 넣어야 입력이 바뀌어도 맞습니다. 여기까지 오면 값 하나를 바꾸려고 파일을 여러 곳 고칠 일이 없어집니다.