Infrastructure as Code · 멱등성 · 실습
apply 할 때마다 서비스가 재시작됐다
목표
선언형 도구 안에 붙인 부작용(재시작·일회성 작업)이 언제 일어나는지를 트리거로 통제하고, 실패한 작업이 남기는 tainted 상태와 교체 순서를 확인한 뒤, 두 번 적용 시험으로 멱등성을 증명합니다.
왜 중요한가
파일을 쓰는 것은 몇 번 해도 결과가 같지만, 서비스 재시작이나 데이터 마이그레이션은 돌 때마다 흔적이 남습니다. 그래서 '무엇이 바뀌었을 때만 돌린다' 는 조건이 멱등성의 핵심이고, 선언형 도구에서는 그 조건이 트리거 값으로 표현됩니다. 트리거에 매번 바뀌는 값을 넣으면 계획이 절대 비지 않아 CI 의 두 번 적용 시험이 깨지고, 실패한 작업은 tainted 로 표시돼 다음 적용에서 다시 돌기 때문에 그 작업 자체가 재시도에 안전해야 합니다. 교체가 정지와 시작의 순서로 일어난다는 것도 무중단 설계의 출발점입니다.
단계
1. /root/iac-prov/noisy/main.tf 에 port 변수(기본 8080), out/app.conf 에 port=<값> 을 쓰는 local_file.conf, 그리고 triggers_replace = timestamp() 인 terraform_data.restart 를 두세요. restart 는 생성될 때 local-exec 로 out/restarts.log 에 restart 한 줄을 덧붙입니다. init 한 뒤 apply 를 두 번 하세요. 채점기는 이 디렉터리에서 계획을 새로 세워 매번 변경이 나오는지 봅니다.
2. /root/iac-prov/app/main.tf 를 1단계와 같게 두되 restart 의 트리거를 설정 파일 내용의 해시(local_file.conf 의 content_sha256)로 바꾸세요. init 한 뒤 apply 를 두 번 하고 계획이 깨끗한지 확인합니다. 채점기는 사본에서 port 를 다른 값으로 준 계획을 세워 restart 가 교체되는지, 같은 값이면 아무것도 바뀌지 않는지 봅니다.
3. /root/iac-prov/app/out/restarts.log 의 줄 수를 센 뒤 apply 를 두 번 더 하고 다시 세어, /root/iac-prov/app/proof.txt 에 before=<수> after=<수> 한 줄로 적으세요. 채점기는 사본에서 apply 를 두 번 돌려 기록이 실제로 늘지 않는지도 확인합니다.
4. /root/iac-prov/app/terraform.tfvars 에 port = 8081 을 두고 apply 하세요. out/app.conf 가 port=8081 이 되고, restarts.log 가 proof.txt 의 after 보다 정확히 한 줄 늘어야 합니다.
5. app/main.tf 에 terraform_data.migrate 를 더하세요. 생성될 때 local-exec 로 ${path.module}/ready.flag 가 있는지 검사하고, 있으면 out/migrate.log 에 migrated 한 줄을 덧붙입니다(없으면 명령이 실패). ready.flag 가 없는 채로 apply 해 출력을 /root/iac-prov/app/taint.txt 에 저장하고, 이어서 tofu plan 출력을 /root/iac-prov/app/taint-plan.txt 에 저장하세요. 채점기는 사본에서 ready.flag 없이 migrate 를 다시 만들어 tainted 가 되는지도 봅니다.
6. /root/iac-prov/app/ready.flag 를 만들고 apply 하세요. migrate 가 교체되며 이번에는 성공해야 하고, 그 뒤 계획은 깨끗해야 합니다. restart 는 이 과정에서 다시 돌지 않아야 합니다(restarts.log 줄 수가 4단계 뒤와 같음).
7. app/main.tf 에 worker_version 변수(기본 v1)와 terraform_data.worker 를 더하세요. input 과 triggers_replace 는 둘 다 그 변수이고, 생성 시 out/worker.log 에 start <버전>, when = destroy 프로비저너로 stop <버전> 을 덧붙입니다. v1 로 적용한 뒤 terraform.tfvars 에 worker_version = "v2" 를 더해 다시 적용하세요. worker.log 가 start v1, stop v1, start v2 순서여야 합니다.
8. /root/iac-prov/twice.sh <작업디렉터리> 를 만드세요. apply 한 뒤 plan -detailed-exitcode 로 두 번째 계획을 확인해, 비었으면 idempotent 와 0, 변경이 남았으면 not-idempotent 로 시작하는 줄과 2, apply 나 plan 이 실패하면 error 로 시작하는 줄과 1 로 끝냅니다. 채점기는 /root/iac-prov/app 과 /root/iac-prov/noisy 의 사본, 그리고 설정이 깨진 임시 디렉터리로 확인합니다.
참고
- 파드에는 OpenTofu 1.9.0 과 local 프로바이더 미러가 있어 인터넷 없이 돕니다. terraform_data 는 내장 리소스라 프로바이더가 필요 없습니다.
- 프로비저너는 생성 시점(기본)과
when = destroy두 가지이고, destroy 프로비저너는self만 참조할 수 있습니다. - 흔한 실수: 상태를 지우거나 사본을 원본과 섞어 restarts.log 줄 수 비교가 어긋나는 것. 채점용 사본은 채점기가 따로 만듭니다.
- 공식 문서도 프로비저너를 최후의 수단으로 권합니다. 여기서는 부작용이 언제 도는지를 눈으로 보기 위해 씁니다.
- [Provisioners](https://opentofu.org/docs/language/resources/provisioners/syntax/) · [lifecycle](https://opentofu.org/docs/language/meta-arguments/lifecycle/) · [tofu plan](https://opentofu.org/docs/cli/commands/plan/) · [Resource Behavior](https://opentofu.org/docs/language/resources/behavior/)
단계 8개
- 적용할 때마다 재시작이 돈다
- 설정이 바뀔 때만 재시작하도록 트리거를 잡는다
- 두 번 더 적용해도 재시작 기록이 늘지 않음을 남긴다
- 설정이 정말 바뀌면 딱 한 번 재시작한다
- 실패한 프로비저너는 리소스를 tainted 로 남긴다
- 원인을 고치고 다시 적용하면 한 번만 교체된다
- 교체는 옛것의 정지 뒤에 새것의 시작이다
- CI 에 넣을 두 번 적용 시험