Terraform/OpenTofu Fundamentals
Almost Rebuilt a Resource When Only the State Was Wrong
한국어 원문으로 표시합니다.
목표
새로고침 전용 계획과 적용, 실물을 읽지 않는 계획의 착시, 저장한 파괴 계획, 파괴의 역순, 대상을 좁힌 파괴의 경고, 그리고 다 지운 뒤 상태에 남는 것까지를 OpenTofu 로 하나씩 확인합니다.
왜 중요한가
계획은 두 가지를 견줍니다 — 코드와 상태, 그리고 상태와 실물입니다. 이 둘을 따로 다룰 수 있다는 것이 새로고침 계열 명령의 핵심입니다. 상태가 실물과 어긋났을 뿐이라면 코드를 건드리지 않고 상태만 맞출 수 있고, 그러면 자원을 다시 만들지 않아도 됩니다. 반대로 실물을 읽지 않고 계획을 뽑으면 도구는 상태에 적힌 값을 사실로 믿습니다. 큰 저장소에서 속도를 얻는 대신 정확도를 내주는 선택인데, 그렇게 뽑은 계획으로 승인을 받으면 어긋난 채로 적용이 들어갑니다. 파괴 쪽도 순서가 전부입니다. 만드는 순서의 역순으로 지워야 아직 남은 것이 이미 사라진 것을 가리키지 않습니다. 대상을 좁혀 지우면 그 보장이 깨지므로 도구가 경고를 붙입니다. 마지막으로 다 지운 뒤에도 상태 파일 자체는 남는다는 것을 알아야 '상태를 지우는 것' 과 '자원을 지우는 것' 을 헷갈리지 않습니다.
단계
/root/tfb-refresh/base/main.tf에app.conf에mode=managed한 줄을 쓰는local_file.conf와, 그 리소스의 id 를conf=<id>한 줄로audit.txt에 쓰는local_file.audit를 두세요. init·apply 하고 계획이 깨끗한지 확인하세요.- 도구를 거치지 않고
/root/tfb-refresh/base/app.conf를HANDEDIT한 줄로 바꾸세요. 그다음tofu plan -refresh-only출력을/root/tfb-refresh/refresh-plan.txt에 저장하세요. 아직 아무것도 적용하지 마세요. - 같은 디렉터리에서
tofu plan -refresh=false출력을/root/tfb-refresh/norefresh.txt에, 그냥tofu plan출력을/root/tfb-refresh/withrefresh.txt에 저장하세요. 두 출력이 어떻게 다른지 확인하세요. 여전히 적용하지 않습니다. tofu apply -refresh-only -auto-approve를 돌리세요. 그다음/root/tfb-refresh/refresh-report.txt에 네 줄을 적으세요 —serial_before=<새로고침 직전 상태의 serial>,serial_after=<지금 serial>,resources_after=<지금 상태의 리소스 수>,conf_first_line=<지금 디스크의 app.conf 첫 줄>. 직전 상태는 백업 파일에 남아 있습니다./root/tfb-refresh/chain/main.tf에terraform_data세 개를 사슬로 두세요 —net, 그 output 을 참조하는db, 그 output 을 참조하는app. 셋 모두 파괴 시점에 자기 이름을/root/tfb-refresh/chain/order.log에 덧붙이는 프로비저너를 갖고,app.output을 내보내는 출력chain도 두세요. init·apply 한 뒤tofu plan -destroy -out=destroy.tfplan으로 계획을 저장하고,tofu show -json으로 삭제 대상 주소를 사전순으로/root/tfb-refresh/destroy-targets.txt에 한 줄씩 적으세요.- 저장한
destroy.tfplan을 그대로 적용해 사슬을 지우세요./root/tfb-refresh/chain/order.log에 남은 순서를 확인하고, 같은 순서를/root/tfb-refresh/order.txt에 한 줄씩 적으세요. /root/tfb-refresh/tgt/main.tf에 같은 모양의 사슬(net·db·app)을 프로비저너 없이 두고 init·apply 하세요. 그다음tofu destroy -target=terraform_data.app -auto-approve로 맨 끝 하나만 지우고 출력을/root/tfb-refresh/target-destroy.txt에 저장하세요. 남은 상태의 주소를 사전순으로/root/tfb-refresh/target-left.txt에 적으세요./root/tfb-refresh/chain의 파괴 뒤 상태를 백업 파일과 견줘/root/tfb-refresh/leftover.txt에 네 줄을 적으세요 —resources=<지금 상태의 리소스 수>,outputs=<지금 상태의 출력 수>,lineage_changed=<yes 또는 no>,serial_up=<yes 또는 no>. 그리고tofu plan을 한 번 더 돌려 출력을/root/tfb-refresh/after-destroy-plan.txt에 저장하세요.
참고
- 파괴 순서는 terraform_data 의 파괴 시점 프로비저너가 로그 파일에 이름을 덧붙여 눈으로 확인합니다.
- 저장한 계획 파일은 적용한 뒤에도 읽을 수 있습니다. 파괴처럼 되돌릴 수 없는 작업은 계획을 저장해 리뷰한 뒤 그 파일만 적용합니다.
- 흔한 실수: 2·3단계에서 확인만 하라는데 적용해 버리는 것. 그러면 4단계가 견줄 직전 상태가 사라집니다.
- 흔한 실수: 6단계에서 저장한 계획 대신 destroy 명령을 새로 돌리는 것. 저장한 계획을 적용하는 것이 과제입니다.
- tofu refresh · tofu plan · tofu destroy · terraform_data · State
기준선을 만든다
/root/tfb-refresh/base/main.tf 에 app.conf 에 mode=managed 한 줄을 쓰는 local_file.conf 와, 그 리소스의 id 를 conf=<id> 한 줄로 audit.txt 에 쓰는 local_file.audit 를 두세요. init·apply 하고 계획이 깨끗한지 확인하세요.
local 프로바이더의 파일 리소스는 내용의 해시를 id 로 씁니다. 그래서 내용이 바뀌면 id 가 바뀌고, 그 id 를 참조하는 리소스도 함께 흔들립니다.
밖에서 바뀐 것을 새로고침 전용 계획으로 본다
도구를 거치지 않고 /root/tfb-refresh/base/app.conf 를 HANDEDIT 한 줄로 바꾸세요. 그다음 tofu plan -refresh-only 출력을 /root/tfb-refresh/refresh-plan.txt 에 저장하세요. 아직 아무것도 적용하지 마세요.
새로고침 전용 계획은 '코드를 실물에 맞추는' 계획이 아니라 '상태를 실물에 맞추는' 계획입니다. 그래서 출력에 create 나 destroy 가 아니라 상태에서 무엇이 사라졌는지가 나옵니다.
실물을 읽지 않은 계획은 아무 일도 없다고 말한다
같은 디렉터리에서 tofu plan -refresh=false 출력을 /root/tfb-refresh/norefresh.txt 에, 그냥 tofu plan 출력을 /root/tfb-refresh/withrefresh.txt 에 저장하세요. 두 출력이 어떻게 다른지 확인하세요. 여전히 적용하지 않습니다.
실물을 읽지 않으면 도구는 상태에 적힌 값을 사실로 믿습니다. 큰 저장소에서 계획을 빨리 뽑으려고 쓰는 옵션인데, 그 계획으로 승인을 받으면 실물과 어긋난 채 적용이 들어갑니다.
상태만 고치고 실물은 건드리지 않는다
tofu apply -refresh-only -auto-approve 를 돌리세요. 그다음 /root/tfb-refresh/refresh-report.txt 에 네 줄을 적으세요 — serial_before=<새로고침 직전 상태의 serial>, serial_after=<지금 serial>, resources_after=<지금 상태의 리소스 수>, conf_first_line=<지금 디스크의 app.conf 첫 줄>. 직전 상태는 백업 파일에 남아 있습니다.
이 명령은 실물을 하나도 바꾸지 않습니다. 바뀌는 것은 상태뿐이고, 도구는 그 직전 상태를 백업 파일로 남깁니다. 손으로 고친 파일은 그대로 있어야 합니다.
파괴 계획을 파일로 저장해 리뷰한다
/root/tfb-refresh/chain/main.tf 에 terraform_data 세 개를 사슬로 두세요 — net, 그 output 을 참조하는 db, 그 output 을 참조하는 app. 셋 모두 파괴 시점에 자기 이름을 /root/tfb-refresh/chain/order.log 에 덧붙이는 프로비저너를 갖고, app.output 을 내보내는 출력 chain 도 두세요. init·apply 한 뒤 tofu plan -destroy -out=destroy.tfplan 으로 계획을 저장하고, tofu show -json 으로 삭제 대상 주소를 사전순으로 /root/tfb-refresh/destroy-targets.txt 에 한 줄씩 적으세요.
파괴 계획도 보통 계획처럼 파일로 저장할 수 있고, 저장한 파일은 사람이 읽을 형식과 기계가 읽을 형식 둘 다로 볼 수 있습니다. 파괴처럼 되돌릴 수 없는 작업일수록 계획을 저장해 리뷰한 뒤 그 파일만 적용하는 편이 안전합니다.
지우는 순서는 만드는 순서의 역순이다
저장한 destroy.tfplan 을 그대로 적용해 사슬을 지우세요. /root/tfb-refresh/chain/order.log 에 남은 순서를 확인하고, 같은 순서를 /root/tfb-refresh/order.txt 에 한 줄씩 적으세요.
만들 때는 의존 대상이 먼저 만들어져야 하고, 지울 때는 그 반대여야 합니다. 그렇지 않으면 아직 남아 있는 것이 이미 사라진 것을 가리키게 됩니다. 새로 계획을 세우지 말고 저장한 파일을 적용하세요.
대상을 좁힌 파괴는 경고를 달고 나온다
/root/tfb-refresh/tgt/main.tf 에 같은 모양의 사슬(net·db·app)을 프로비저너 없이 두고 init·apply 하세요. 그다음 tofu destroy -target=terraform_data.app -auto-approve 로 맨 끝 하나만 지우고 출력을 /root/tfb-refresh/target-destroy.txt 에 저장하세요. 남은 상태의 주소를 사전순으로 /root/tfb-refresh/target-left.txt 에 적으세요.
대상을 좁히는 옵션은 도구가 평소에 지켜 주던 전체 그래프의 일관성을 사람이 책임지겠다는 선언입니다. 그래서 출력에 경고가 붙습니다. 응급 상황에서만 쓰고, 쓴 뒤에는 대상을 좁히지 않은 계획을 한 번 돌려 확인합니다.
다 지운 뒤 상태에 남는 것
/root/tfb-refresh/chain 의 파괴 뒤 상태를 백업 파일과 견줘 /root/tfb-refresh/leftover.txt 에 네 줄을 적으세요 — resources=<지금 상태의 리소스 수>, outputs=<지금 상태의 출력 수>, lineage_changed=<yes 또는 no>, serial_up=<yes 또는 no>. 그리고 tofu plan 을 한 번 더 돌려 출력을 /root/tfb-refresh/after-destroy-plan.txt 에 저장하세요.
다 지워도 상태 파일 자체는 남습니다. 무엇이 비고 무엇이 남는지를 알아야 '상태를 지우는 것' 과 '자원을 지우는 것' 을 헷갈리지 않습니다. 파괴 직전 상태는 백업 파일에 있습니다.