LabHub
배우기 러닝패스 코스

Infrastructure as Code

属性を一つ変えただけなのにファイルが作り直された

LabHub 에서 이어서 보기

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

목표

진짜 선언형 도구(OpenTofu)가 내는 계획을 읽고, 종료 코드·저장된 계획·계획 JSON 으로 자동 판정을 만들며, prevent_destroy 가 막는 것과 못 막는 것을 직접 확인합니다.

왜 중요한가

앞 실습에서 셸로 흉내 낸 plan 의 기호가 실제 도구에서는 프로바이더의 규칙을 따릅니다. 파일 내용 한 줄을 고쳤을 뿐인데 리소스가 교체되는 일은 흔하고, 그걸 계획에서 읽어 내지 못하면 적용 뒤에야 알게 됩니다. 자동화는 계획을 사람 대신 읽어야 하므로 종료 코드와 JSON 을 약속대로 다뤄야 하고, 리뷰한 것과 적용된 것이 같다는 보장은 저장된 계획에서 나옵니다. 삭제 보호 역시 설정 안에 있을 때만 효력이 있다는 한계를 알아야 리뷰에서 무엇을 볼지 정해집니다.

단계

  1. /root/iac-plan/main.tf 에 local·random 프로바이더를 요구하고 리소스 셋을 선언하세요. local_file.motd${path.module}/out/motd.txthello v1 한 줄(끝에 줄바꿈)을 쓰고, terraform_data.release 는 input 이 v1, random_pet.suffix 는 keepers 가 team = "blue" 입니다. tofu inittofu 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 -outtofu show -json), 그 요약을 /root/iac-plan/now-summary.txt 에 저장하세요.
  6. local_file.motdlifecycle { 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), 그리고 스스로 만든 임시 디렉터리들로 확인합니다.

참고

세 가지 리소스를 선언하고 한 번 적용한다

/root/iac-plan/main.tf 에 local·random 프로바이더를 요구하고 리소스 셋을 선언하세요. local_file.motd${path.module}/out/motd.txthello v1 한 줄(끝에 줄바꿈)을 쓰고, terraform_data.release 는 input 이 v1, random_pet.suffix 는 keepers 가 team = "blue" 입니다. tofu inittofu apply -auto-approve 로 적용하세요.

local·random 은 파드 안 미러에서 받아지므로 인터넷이 없어도 init 이 됩니다. terraform_data 는 프로바이더 없이 쓰는 내장 리소스입니다. 적용 뒤 tofu state list 로 상태가 아는 주소를 확인하세요.

종료 코드 세 가지를 낱말로 바꾸는 게이트

/root/iac-plan/gate.sh <작업디렉터리> 를 만드세요. 그 디렉터리에서 tofu plan -detailed-exitcode 를 돌려 변경이 없으면 clean 을 출력하고 0, 변경이 있으면 changes 와 2, 오류면 error 와 1 로 끝냅니다. 출력은 그 낱말 한 줄뿐입니다. 채점기는 변경 없음·변경 있음·설정 오류 세 가지 임시 디렉터리를 만들어 이 스크립트를 돌립니다.

-detailed-exitcode 는 0·1·2 세 값을 냅니다. set -e 를 걸면 2 에서 스크립트가 먼저 끝나 버립니다. 계획만 세우는 명령에는 -lock=false 를 붙여 남의 작업을 막지 않게 할 수 있습니다.

속성 하나 고쳤는데 새로 만들어진다

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 로 판단합니다.

~ 는 제자리 수정, -/+ 는 지우고 다시 만드는 교체입니다. JSON 에서는 actions 가 ["update"] 인지 ["delete","create"] 인지로 보입니다. 어떤 속성이 교체를 강제하는지는 프로바이더가 정합니다 — 계획 출력에서 # forces replacement 표시를 찾으세요.

리뷰한 계획만 적용되고, 낡은 계획은 거절된다

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

저장된 계획에는 계획을 세울 때의 상태가 함께 들어 있습니다. 그 사이에 상태가 바뀌었으면 OpenTofu 는 계획을 적용하지 않습니다. -replace 는 설정을 바꾸지 않고 그 리소스를 교체하게 하는 옵션이고, -target 은 계획의 범위를 그 리소스로 좁힙니다(-target 이 없으면 main.tf 의 v3 변경까지 함께 적용됩니다). -no-color 를 붙이면 저장한 파일이 읽기 쉽습니다.

계획 JSON 에서 동작을 센다

/root/iac-plan/summary.sh <계획JSON> 을 만드세요. tofu show -json 결과 파일을 받아 create=<수> update=<수> replace=<수> delete=<수> 한 줄을 출력합니다. 교체(삭제와 생성이 한 리소스에 함께 있는 것)는 replace 한 건으로만 셉니다. 그리고 지금 작업 디렉터리의 계획을 /root/iac-plan/now.json 으로 저장하고(tofu plan -outtofu show -json), 그 요약을 /root/iac-plan/now-summary.txt 에 저장하세요.

resource_changes 의 각 원소에 change.actions 배열이 있습니다. 변경 없는 리소스는 ["no-op"] 이라 어느 칸에도 세지 않습니다. jq 에서 배열끼리 == 로 비교할 수 있습니다.

보호를 걸었더니 교체도 막혔다

local_file.motdlifecycle { prevent_destroy = true } 를 더하세요. 내용이 hello v3 인 채로 tofu plan 을 돌려 출력(오류 포함)을 /root/iac-plan/guard.txt 에 저장합니다. 그다음 motd 내용을 hello v2 로 되돌려 계획이 다시 깨끗해지게 하세요(작업 디렉터리의 계획이 변경 없음이어야 합니다). 채점기는 사본에서 motd 의 내용을 바꾼 계획을 세워 보호가 실제로 막는지 확인합니다.

local_file 의 content 는 바뀌면 교체입니다. 교체에는 삭제가 들어 있으므로 prevent_destroy 가 걸린 리소스에서는 계획 자체가 오류로 끝납니다. 오류 메시지에서 리소스 주소와 이유를 읽으세요.

블록을 지우면 보호도 함께 사라진다

/root/iac-plan 를 상태 파일까지 통째로 /root/iac-plan-bypass 로 복사하세요(cp -a). 사본의 main.tf 에서 local_file.motd 리소스 블록을 lifecycle 까지 통째로 지우고, 사본에서 tofu plan -out=/root/iac-plan-bypass/bypass.tfplan 을 저장합니다. 적용하지는 않습니다. 원본은 그대로 둡니다.

prevent_destroy 는 설정 안에 있는 동안만 효력이 있습니다. 블록을 지우면 그 설정도 사라지므로 계획은 오류 없이 삭제를 제안합니다. 이 차이가 코드 리뷰에서 무엇을 봐야 하는지를 알려 줍니다.

파괴가 섞인 계획은 사람에게 넘긴다

/root/iac-plan/review.sh <작업디렉터리> 를 만드세요. 그 디렉터리의 계획을 임시 파일로 저장해 summary.sh 로 세고, 변경이 없으면 CLEAN 과 0, 추가·수정만 있으면 AUTO 로 시작하는 한 줄과 2, 교체나 삭제가 하나라도 있으면 REVIEW 로 시작하는 한 줄과 3, 계획이 실패하면 ERROR 와 1 로 끝냅니다. 작업 디렉터리에 계획 파일을 남기지 않습니다. 채점기는 원본(CLEAN), 우회 사본(REVIEW), 그리고 스스로 만든 임시 디렉터리들로 확인합니다.

앞 단계의 gate.sh 와 summary.sh 를 이어 붙이는 문제입니다. 임시 파일은 mktemp 로 만들고 trap 으로 지웁니다. 계획 파일 없이 JSON 을 얻을 수는 없습니다 — -out 으로 저장한 뒤 show 합니다.