Terraform/OpenTofu Fundamentals
Dissecting the Dependency Graph and the State File
한국어 원문으로 표시합니다.
목표
참조가 어떻게 의존성 그래프를 만드는지 상태 파일에서 직접 확인하고, 상태를 사람과 기계 두 가지 방식으로 읽어 메타데이터를 뽑아낼 수 있게 됩니다.
왜 중요한가
Terraform 을 며칠 쓰다 보면 "순서가 왜 이렇지"라는 질문이 반드시 옵니다. 답은 언제나 그래프입니다. 도구는 파일에 적힌 순서를 보지 않고, 어떤 리소스가 어떤 리소스의 값을 쓰는지만 봅니다. 그래서 값을 참조하면 순서가 생기고, 값을 베껴 적으면 순서가 사라집니다. depends_on 은 값으로 드러나지 않는 순서를 표현하는 탈출구지만, 습관이 되면 그래프가 굵어져 실행이 느려지고 재생성이 옆으로 번집니다. 한편 이 관계는 상태 파일에 dependencies 로 기록되는데, 이것이 코드에서 리소스를 지운 뒤에도 올바른 역순으로 삭제할 수 있는 근거입니다. 상태를 손으로 편집하는 일이 왜 위험한지도 여기서 이해할 수 있습니다.
단계
/root/tf/state에 설정을 만들어 초기화하세요. 이름이seed인random_pet과 이름이child인local_file을 선언하되,child의 내용이random_pet.seed의 값을 참조하게 하세요.child에는depends_on을 쓰지 마세요. 적용 뒤 상태의local_file.child의dependencies에random_pet.seed가 들어 있어야 합니다.- 이름이
marker인local_file을 추가하고,/root/tf/state/main.tf에depends_on = [local_file.child]를 적어 순서를 못 박으세요. 적용 뒤 상태의local_file.marker의dependencies에local_file.child가 보여야 합니다. - 상태에 등록된 리소스 주소 목록을
/root/tf/state/out/state-list.txt에 저장하세요.random_pet.seed,local_file.child,local_file.marker세 줄이 각각 정확히 그 문자열 그대로 들어가야 합니다. - 상태의 JSON 표현을
/root/tf/state/out/state.json에 저장하세요..values.root_module.resources아래에 리소스가 3개 이상 있고, 그중address가local_file.child인 항목이 있어야 합니다. /root/tf/state/out/meta.json을 만드세요.serial,lineage,version,resource_count네 키를 가지며, 앞의 셋은/root/tf/state/terraform.tfstate의 값과 같아야 하고resource_count는 상태의resources배열 길이와 같아야 합니다.child가 만든 파일을 Terraform 을 거치지 않고 셸에서 직접 지운 뒤, 그 상태로 계획을 뽑아/root/tf/state/out/drift-plan.txt에 저장하세요. 출력에local_file.child를 다시 만들겠다는 내용이 있어야 하고 "변경 없음" 이면 안 됩니다./root/tf/state/.terraform.lock.hcl을 읽고 거기에 고정된 프로바이더 이름과 버전을 한 줄로 정리해/root/tf/state/out/lock-note.txt에 저장하세요.local이라는 이름과2.5.3같은 세 자리 버전 번호가 모두 들어가야 합니다.- 이름이
stage_a,stage_b,stage_c인local_file세 개를 추가하되stage_b는stage_a의 값을,stage_c는stage_b의 값을 참조하게 하세요. 적용한 뒤/root/tf/state/out/chain.txt에 만들어지는 순서대로local_file.stage_a,local_file.stage_b,local_file.stage_c를 한 줄에 하나씩, 총 3줄로 적으세요.
참고
terraform state list는 주소만,terraform show -json은 상태 전체를 기계가 읽는 형식으로 보여 줍니다. 후자는jq와 짝을 이룹니다.- 5번은
jq로.serial,.lineage,.version,(.resources|length)를 뽑아 새 JSON 을 조립하면 손으로 베끼는 실수를 피할 수 있습니다. - 6번의 계획 출력은 표준 출력으로 나옵니다. 다시 적용하기 전에 파일로 남기세요.
- 흔한 실수 1: 순서를 맞추려고 모든 리소스에
depends_on을 다는 것. 참조가 있으면 의존성은 이미 생겨 있고, 중복된depends_on은 그래프만 굵게 만듭니다. - 흔한 실수 2: 3번과 8번에서 주소 앞뒤에 공백이나 따옴표를 남기는 것. 채점은 줄 전체가 정확히 일치하는지를 봅니다.
참조만으로 의존성 만들기
/root/tf/state 에 설정을 만들어 초기화하세요. 이름이 seed 인 random_pet 과 이름이 child 인 local_file 을 선언하되, child 의 내용이 random_pet.seed 의 값을 참조하게 하세요. child 에는 depends_on 을 쓰지 마세요. 적용 뒤 상태의 local_file.child 의 dependencies 에 random_pet.seed 가 들어 있어야 합니다.
다른 리소스의 속성을 식으로 쓰면 그것이 곧 순서 선언입니다. 이 단계에서는 depends_on 을 쓰지 말고, 상태의 dependencies 배열이 채워지는지로 확인하세요.
depends_on 으로 순서 못 박기
이름이 marker 인 local_file 을 추가하고, /root/tf/state/main.tf 에 depends_on = [local_file.child] 를 적어 순서를 못 박으세요. 적용 뒤 상태의 local_file.marker 의 dependencies 에 local_file.child 가 보여야 합니다.
값을 쓰지 않는데 순서만 필요할 때 쓰는 인자가 있습니다. 값은 리소스 주소의 목록이며 따옴표로 감싸지 않습니다.
상태 주소 목록 뽑기
상태에 등록된 리소스 주소 목록을 /root/tf/state/out/state-list.txt 에 저장하세요. random_pet.seed, local_file.child, local_file.marker 세 줄이 각각 정확히 그 문자열 그대로 들어가야 합니다.
상태에 등록된 주소만 한 줄씩 보여 주는 하위 명령이 있습니다. 파일에는 주소 외의 장식이 들어가면 안 됩니다.
상태를 JSON 으로 뽑기
상태의 JSON 표현을 /root/tf/state/out/state.json 에 저장하세요. .values.root_module.resources 아래에 리소스가 3개 이상 있고, 그중 address 가 local_file.child 인 항목이 있어야 합니다.
사람이 읽는 출력과 기계가 읽는 출력은 다른 옵션입니다. JSON 안에서 리소스 목록이 어느 경로에 있는지 jq 로 더듬어 보세요.
상태 메타데이터 기록하기
/root/tf/state/out/meta.json 을 만드세요. serial, lineage, version, resource_count 네 키를 가지며, 앞의 셋은 /root/tf/state/terraform.tfstate 의 값과 같아야 하고 resource_count 는 상태의 resources 배열 길이와 같아야 합니다.
네 개의 키가 필요합니다. 값을 눈으로 베끼지 말고 상태 파일에서 직접 뽑아 조립하면 틀릴 일이 없습니다. 리소스 개수는 배열의 길이입니다.
손으로 지운 파일이 계획에 잡히는지 보기
child 가 만든 파일을 Terraform 을 거치지 않고 셸에서 직접 지운 뒤, 그 상태로 계획을 뽑아 /root/tf/state/out/drift-plan.txt 에 저장하세요. 출력에 local_file.child 를 다시 만들겠다는 내용이 있어야 하고 "변경 없음" 이면 안 됩니다.
코드는 그대로 두고 결과물만 없애면 조회 단계에서 차이가 드러납니다. 다시 적용하기 전에 계획 출력을 먼저 저장하세요.
잠금 파일에서 프로바이더 버전 읽기
/root/tf/state/.terraform.lock.hcl 을 읽고 거기에 고정된 프로바이더 이름과 버전을 한 줄로 정리해 /root/tf/state/out/lock-note.txt 에 저장하세요. local 이라는 이름과 2.5.3 같은 세 자리 버전 번호가 모두 들어가야 합니다.
잠금 파일에는 프로바이더 블록과 확정된 버전, 그리고 해시가 있습니다. 해시가 무엇을 보증하는지 생각하며 한 줄로 정리하세요.
3단계 의존 사슬 만들고 순서 기록하기
이름이 stage_a, stage_b, stage_c 인 local_file 세 개를 추가하되 stage_b 는 stage_a 의 값을, stage_c 는 stage_b 의 값을 참조하게 하세요. 적용한 뒤 /root/tf/state/out/chain.txt 에 만들어지는 순서대로 local_file.stage_a, local_file.stage_b, local_file.stage_c 를 한 줄에 하나씩, 총 3줄로 적으세요.
앞 단계의 결과를 다음 단계가 참조하게 이으면 사슬이 됩니다. 기록할 순서는 코드에 적은 순서가 아니라 만들어지는 순서입니다.