Infrastructure as Code · 선언형 사고 · 실습
속성 하나 고쳤는데 파일이 새로 만들어졌다
목표
진짜 선언형 도구(OpenTofu)가 내는 계획을 읽고, 종료 코드·저장된 계획·계획 JSON 으로 자동 판정을 만들며, prevent_destroy 가 막는 것과 못 막는 것을 직접 확인합니다.
왜 중요한가
앞 실습에서 셸로 흉내 낸 plan 의 기호가 실제 도구에서는 프로바이더의 규칙을 따릅니다. 파일 내용 한 줄을 고쳤을 뿐인데 리소스가 교체되는 일은 흔하고, 그걸 계획에서 읽어 내지 못하면 적용 뒤에야 알게 됩니다. 자동화는 계획을 사람 대신 읽어야 하므로 종료 코드와 JSON 을 약속대로 다뤄야 하고, 리뷰한 것과 적용된 것이 같다는 보장은 저장된 계획에서 나옵니다. 삭제 보호 역시 설정 안에 있을 때만 효력이 있다는 한계를 알아야 리뷰에서 무엇을 볼지 정해집니다.
단계
1. /root/iac-plan/main.tf 에 local·random 프로바이더를 요구하고 리소스 셋을 선언하세요. local_file.motd 는 ${path.module}/out/motd.txt 에 hello v1 한 줄(끝에 줄바꿈)을 쓰고, terraform_data.release 는 input 이 v1, random_pet.suffix 는 keepers 가 team = "blue" 입니다. tofu init 과 tofu apply -auto-approve 로 적용하세요.
2. /root/iac-plan/gate.sh <작업디렉터리> 를 만드세요. 그 디렉터리에서 tofu plan -detailed-exitcode 를 돌려 변경이 없으면 clean 을 출력하고 0, 변경이 있으면 changes 와 2, 오류면 error 와 1 로 끝냅니다. 출력은 그 낱말 한 줄뿐입니다. 채점기는 변경 없음·변경 있음·설정 오류 세 가지 임시 디렉터리를 만들어 이 스크립트를 돌립니다.
3. main.tf 에서 세 값을 바꾸세요: motd 내용은 hello v2, release 의 input 은 v2, suffix 의 keepers team 은 green. 적용하지 말고 tofu plan -out=/root/iac-plan/change.tfplan 으로 계획을 저장한 뒤, /root/iac-plan/actions.txt 에 바뀌는 리소스마다 <주소> <create|update|replace|delete> 한 줄씩 적으세요. 무엇이 제자리 수정이고 무엇이 교체인지는 계획 출력의 기호와 tofu show -json 의 actions 로 판단합니다.
4. 먼저 tofu apply change.tfplan 으로 저장한 계획을 그대로 적용하세요. 그다음 motd 내용을 hello v3 로 바꾸고 tofu plan -out=/root/iac-plan/late.tfplan 으로 저장합니다. 이 계획을 적용하기 전에 다른 사람이 끼어든 상황을 만듭니다: tofu apply -auto-approve -replace=random_pet.suffix -target=random_pet.suffix 를 먼저 실행하세요(suffix 하나만 교체하고 motd 는 건드리지 않습니다). 이제 tofu apply late.tfplan 을 실행해 표준 출력과 오류를 함께 /root/iac-plan/stale.txt 에 저장하세요.
5. /root/iac-plan/summary.sh <계획JSON> 을 만드세요. tofu show -json 결과 파일을 받아 create=<수> update=<수> replace=<수> delete=<수> 한 줄을 출력합니다. 교체(삭제와 생성이 한 리소스에 함께 있는 것)는 replace 한 건으로만 셉니다. 그리고 지금 작업 디렉터리의 계획을 /root/iac-plan/now.json 으로 저장하고(tofu plan -out 후 tofu show -json), 그 요약을 /root/iac-plan/now-summary.txt 에 저장하세요.
6. local_file.motd 에 lifecycle { prevent_destroy = true } 를 더하세요. 내용이 hello v3 인 채로 tofu plan 을 돌려 출력(오류 포함)을 /root/iac-plan/guard.txt 에 저장합니다. 그다음 motd 내용을 hello v2 로 되돌려 계획이 다시 깨끗해지게 하세요(작업 디렉터리의 계획이 변경 없음이어야 합니다). 채점기는 사본에서 motd 의 내용을 바꾼 계획을 세워 보호가 실제로 막는지 확인합니다.
7. /root/iac-plan 를 상태 파일까지 통째로 /root/iac-plan-bypass 로 복사하세요(cp -a). 사본의 main.tf 에서 local_file.motd 리소스 블록을 lifecycle 까지 통째로 지우고, 사본에서 tofu plan -out=/root/iac-plan-bypass/bypass.tfplan 을 저장합니다. 적용하지는 않습니다. 원본은 그대로 둡니다.
8. /root/iac-plan/review.sh <작업디렉터리> 를 만드세요. 그 디렉터리의 계획을 임시 파일로 저장해 summary.sh 로 세고, 변경이 없으면 CLEAN 과 0, 추가·수정만 있으면 AUTO 로 시작하는 한 줄과 2, 교체나 삭제가 하나라도 있으면 REVIEW 로 시작하는 한 줄과 3, 계획이 실패하면 ERROR 와 1 로 끝냅니다. 작업 디렉터리에 계획 파일을 남기지 않습니다. 채점기는 원본(CLEAN), 우회 사본(REVIEW), 그리고 스스로 만든 임시 디렉터리들로 확인합니다.
참고
- 파드에는 OpenTofu 1.9.0 이
tofu(같은 바이너리를terraform으로도 부를 수 있음)로 들어 있고, local·random·null·tls 프로바이더는 파드 안 미러에서 받습니다. 인터넷은 필요 없습니다. - 계획 JSON:
tofu show -json <계획파일>— 계획 파일은 그것을 만든 작업 디렉터리에서 읽어야 프로바이더 스키마를 찾습니다. - 흔한 실수: 스크립트에
set -e를 걸어 -detailed-exitcode 의 2 에서 스크립트가 먼저 죽는 것. - 흔한 실수: 교체를 추가 하나와 삭제 하나로 두 번 세는 것.
- [tofu plan (-detailed-exitcode)](https://opentofu.org/docs/cli/commands/plan/) · [tofu apply (Saved Plan Mode)](https://opentofu.org/docs/cli/commands/apply/) · [JSON Output Format](https://opentofu.org/docs/internals/json-format/) · [lifecycle](https://opentofu.org/docs/language/meta-arguments/lifecycle/) · [Terraform plan](https://developer.hashicorp.com/terraform/cli/commands/plan)
단계 8개
- 세 가지 리소스를 선언하고 한 번 적용한다
- 종료 코드 세 가지를 낱말로 바꾸는 게이트
- 속성 하나 고쳤는데 새로 만들어진다
- 리뷰한 계획만 적용되고, 낡은 계획은 거절된다
- 계획 JSON 에서 동작을 센다
- 보호를 걸었더니 교체도 막혔다
- 블록을 지우면 보호도 함께 사라진다
- 파괴가 섞인 계획은 사람에게 넘긴다