読むだけのブロックが状態に残った
한국어 원문으로 표시합니다.
목표
data 블록이 resource 와 무엇이 다른지를 상태·계획·파괴 세 자리에서 직접 확인합니다. 읽기가 언제 일어나는지, 무엇을 소유하지 않는지, 원본이 없거나 바뀌면 어떻게 되는지를 OpenTofu 로 하나씩 일으켜 봅니다.
왜 중요한가
설정 파일에서 data 블록은 resource 만큼 자주 나오는데, 둘을 같은 것으로 읽으면 사고가 조용히 납니다. data 는 대상을 만들지도 지우지도 않습니다 — destroy 를 돌려도 원본은 그대로 남고, 그래서 남의 팀이 만든 것을 읽어 쓰는 설정이 안전해집니다. 대신 data 는 상태에 저장된 값을 믿지 않고 계획마다 다시 읽습니다. 원본이 바뀌면 그것은 드리프트가 아니라 입력이 바뀐 것이고, 하류가 통째로 교체될 수 있습니다. 읽을 대상의 이름이 아직 정해지지 않았거나 depends_on 이 걸려 있으면 읽기가 적용 시점으로 밀리는데, 이때 계획에는 값이 통째로 '알 수 없음' 으로 나와 리뷰가 어려워집니다. 이 네 가지를 손으로 겪어 두면 남의 설정을 읽을 때 data 블록에서 눈이 멈추게 됩니다.
단계
/root/tfb-data/base/seed.txt에alpha한 줄을 직접 만들고, 같은 디렉터리의main.tf에 그 파일을 읽는data "local_file" "seed"와 그 내용을copy.txt에 쓰는resource "local_file" "copy"를 두세요. init·apply 하고 계획이 깨끗해야 합니다./root/tfb-data/base/terraform.tfstate를 열어 mode 가 data 인 항목과 managed 인 항목의 주소를 각각 찾고,/root/tfb-data/shape.txt에data=<그 주소>와managed=<그 주소>두 줄을 적으세요. 주소는data.local_file.seed처럼 mode 접두어까지 포함한 형태입니다./root/tfb-data/own/에 같은 모양의 설정을 두되seed.txt는owned한 줄로 만드세요. init·apply 로copy.txt를 만든 뒤tofu destroy -auto-approve를 돌리고 그 출력을/root/tfb-data/own-destroy.txt에 저장하세요. 다시 apply 하지 않습니다./root/tfb-data/deferred/main.tf에random_pet.name(length 2), 그 이름이 들어간made-<이름>.txt를 쓰는local_file.made, 그 파일을 읽는data.local_file.back, 읽은 값을echo.txt에 쓰는local_file.echo를 두세요. init 한 뒤 plan 출력을/root/tfb-data/deferred-plan.txt에 저장하고 apply 하세요./root/tfb-data/gate/ready.txt를ready한 줄로 먼저 만들어 두세요. 같은 디렉터리main.tf에null_resource.prepare(triggers v = "1"),depends_on = [null_resource.prepare]를 붙인data.local_file.ready, 읽은 값을mirror.txt에 쓰는local_file.mirror를 두고 init 하세요. plan 출력을/root/tfb-data/gate-plan.txt에 저장한 뒤 apply 하세요./root/tfb-data/missing/main.tf에 없는 파일absent.txt를 읽는data.local_file.absent와 그 내용을 내보내는 출력absent를 두고 init 하세요. plan 을 돌려 오류 출력을/root/tfb-data/missing-plan.txt에 저장하세요. 명령이 실패해도 괜찮습니다.absent.txt는 만들지 마세요./root/tfb-data/tfdata/main.tf에terraform_data.note(input "v1")와 그 output 을 내보내는 출력note를 두고 init·apply 하세요. 그다음 input 을 "v2" 로 바꾸고 plan 출력을/root/tfb-data/tfdata-plan.txt에 저장한 뒤 apply 하세요. 마지막으로/root/tfb-data/mode-compare.txt에terraform_data=<tfdata 상태에서 읽은 mode>와local_file_seed=<base 상태에서 읽은 mode>두 줄을 적으세요./root/tfb-data/base/seed.txt를beta한 줄로 바꾸고/root/tfb-data/base에서 plan 을 돌려 출력을/root/tfb-data/data-change.txt에 저장한 뒤 apply 하세요. 계획이 왜 교체(replace)로 나오는지 확인하고, 마지막에 계획이 다시 깨끗해져야 합니다.
참고
- 파드에는 OpenTofu 1.9.0 과 local·random·null·tls 프로바이더 미러가 있어 인터넷 없이 돕니다. 인터넷이 필요한 데이터 소스는 이 파드에서 쓸 수 없어 전부 local 파일로 재현합니다.
- 계획 출력은
-no-color로 저장해야 채점기가 읽기 좋습니다. 색 코드가 섞이면 사람 눈에도 지저분합니다. - 흔한 실수: 6단계에서 오류를 없애려고 absent.txt 를 만들어 버리는 것. 이 단계는 실패하는 계획을 남기는 것이 과제입니다.
- 흔한 실수: 3단계에서 destroy 뒤에 다시 apply 하는 것. 지운 자리를 그대로 두고 원본이 남았는지 확인하는 단계입니다.
- Data Sources · depends_on · terraform_data · local_file 데이터 소스 · tofu plan
이미 있는 파일을 data 로 읽는다
/root/tfb-data/base/seed.txt 에 alpha 한 줄을 직접 만들고, 같은 디렉터리의 main.tf 에 그 파일을 읽는 data "local_file" "seed" 와 그 내용을 copy.txt 에 쓰는 resource "local_file" "copy" 를 두세요. init·apply 하고 계획이 깨끗해야 합니다.
data 블록은 만들지 않고 읽기만 합니다. 읽은 값은 data.<타입>.<이름>.<속성> 으로 참조합니다. local 프로바이더의 file 데이터 소스는 content 속성에 파일 내용을 담아 줍니다.
상태에서 읽는 것과 만드는 것을 가른다
/root/tfb-data/base/terraform.tfstate 를 열어 mode 가 data 인 항목과 managed 인 항목의 주소를 각각 찾고, /root/tfb-data/shape.txt 에 data=<그 주소> 와 managed=<그 주소> 두 줄을 적으세요. 주소는 data.local_file.seed 처럼 mode 접두어까지 포함한 형태입니다.
상태 JSON 의 각 항목에는 mode·type·name 이 있습니다. mode 가 data 면 주소 앞에 data. 가 붙고, managed 면 붙지 않습니다. tofu state list 출력과 견줘 보세요.
destroy 해도 읽기만 한 원본은 남는다
/root/tfb-data/own/ 에 같은 모양의 설정을 두되 seed.txt 는 owned 한 줄로 만드세요. init·apply 로 copy.txt 를 만든 뒤 tofu destroy -auto-approve 를 돌리고 그 출력을 /root/tfb-data/own-destroy.txt 에 저장하세요. 다시 apply 하지 않습니다.
destroy 는 상태가 소유한 것만 지웁니다. data 로 읽기만 한 파일은 상태에 기록은 남아도 소유물이 아닙니다. destroy 직전 상태는 terraform.tfstate.backup 으로 남습니다.
읽을 대상이 아직 없으면 읽기가 apply 로 밀린다
/root/tfb-data/deferred/main.tf 에 random_pet.name(length 2), 그 이름이 들어간 made-<이름>.txt 를 쓰는 local_file.made, 그 파일을 읽는 data.local_file.back, 읽은 값을 echo.txt 에 쓰는 local_file.echo 를 두세요. init 한 뒤 plan 출력을 /root/tfb-data/deferred-plan.txt 에 저장하고 apply 하세요.
데이터 소스의 인자가 plan 시점에 알 수 없는 값이면 읽기를 미룹니다. 계획 출력에서 그 데이터 소스 줄이 어떻게 적히는지 그대로 읽어 보세요.
depends_on 을 붙이면 있는 파일도 plan 때 못 읽는다
/root/tfb-data/gate/ready.txt 를 ready 한 줄로 먼저 만들어 두세요. 같은 디렉터리 main.tf 에 null_resource.prepare(triggers v = "1"), depends_on = [null_resource.prepare] 를 붙인 data.local_file.ready, 읽은 값을 mirror.txt 에 쓰는 local_file.mirror 를 두고 init 하세요. plan 출력을 /root/tfb-data/gate-plan.txt 에 저장한 뒤 apply 하세요.
원본이 이미 있어도 depends_on 이 있으면 도구는 그 의존이 끝나기 전에는 읽지 않습니다. 1단계의 계획 출력과 견줘 보면 차이가 한 줄로 드러납니다.
원본이 없으면 계획 자체가 실패한다
/root/tfb-data/missing/main.tf 에 없는 파일 absent.txt 를 읽는 data.local_file.absent 와 그 내용을 내보내는 출력 absent 를 두고 init 하세요. plan 을 돌려 오류 출력을 /root/tfb-data/missing-plan.txt 에 저장하세요. 명령이 실패해도 괜찮습니다. absent.txt 는 만들지 마세요.
데이터 소스의 읽기는 계획 단계에서 일어납니다. 그래서 읽을 수 없으면 적용까지 가지도 못하고 계획이 멈춥니다. 오류 메시지의 제목과 원인 줄을 그대로 저장하세요.
terraform_data 는 data 가 아니라 managed 다
/root/tfb-data/tfdata/main.tf 에 terraform_data.note(input "v1")와 그 output 을 내보내는 출력 note 를 두고 init·apply 하세요. 그다음 input 을 "v2" 로 바꾸고 plan 출력을 /root/tfb-data/tfdata-plan.txt 에 저장한 뒤 apply 하세요. 마지막으로 /root/tfb-data/mode-compare.txt 에 terraform_data=<tfdata 상태에서 읽은 mode> 와 local_file_seed=<base 상태에서 읽은 mode> 두 줄을 적으세요.
이름만 보면 데이터 소스 같지만 상태의 mode 를 보면 답이 나옵니다. 계획 출력의 동작 낱말도 데이터 소스와 다릅니다 — 데이터 소스는 read, 이쪽은 생명주기가 있는 리소스입니다.
원본이 바뀌면 드리프트가 아니라 입력이 바뀐 것이다
/root/tfb-data/base/seed.txt 를 beta 한 줄로 바꾸고 /root/tfb-data/base 에서 plan 을 돌려 출력을 /root/tfb-data/data-change.txt 에 저장한 뒤 apply 하세요. 계획이 왜 교체(replace)로 나오는지 확인하고, 마지막에 계획이 다시 깨끗해져야 합니다.
데이터 소스는 상태에 저장된 값을 믿지 않고 계획마다 다시 읽습니다. 그래서 원본이 바뀌면 상태가 어긋난 것이 아니라 하류 리소스의 입력이 바뀐 것으로 잡힙니다. local_file 의 content 는 제자리 수정이 안 되는 속성입니다.