Infrastructure as Code · 상태 관리 · 실습
상태 파일을 옮겼더니 같은 서버가 둘이 됐다
목표
상태 파일의 구조를 열어 보고, 상태를 잃었을 때의 중복 생성·lineage 안전장치·import 복구·동시 적용 잠금·상태 분할·커밋 규칙을 OpenTofu 로 하나씩 일으켜 확인합니다.
왜 중요한가
상태는 코드와 실제 인프라를 잇는 유일한 기록이라, 사고는 대개 코드가 아니라 상태에서 납니다. 상태가 사라지면 도구는 이미 있는 것을 모르고 또 만들고, 엉뚱한 상태로 덮어쓰면 남의 기록을 지웁니다. 복구는 import 로 하나씩 되돌리는 길뿐이라 버전 관리된 백엔드가 기본이 됩니다. 잠금이 있어야 두 적용이 겹치지 않고, 수명이 다른 층을 한 상태에 두지 않아야 매일 바뀌는 쪽 때문에 거의 안 바뀌는 쪽이 위험해지지 않습니다.
단계
1. /root/iac-state/main.tf 에 random_id.server(byte_length 4)와, out/server-<그 hex>.txt 에 server <hex> 한 줄을 쓰는 local_file.inventory 를 두고 init·apply 하세요. 그다음 상태 파일을 /root/iac-state/backup/terraform.tfstate 로 복사하고, 그 사본에서 읽은 값으로 /root/iac-state/anatomy.txt 에 lineage=<값>, serial=<값>, resources=<리소스 블록 수> 세 줄을 적으세요.
2. /root/iac-state/lost/ 를 만들고 terraform.tfstate 와 terraform.tfstate.backup(있으면)을 그곳으로 옮기세요. tofu plan 출력을 /root/iac-state/lost-plan.txt 에 저장한 뒤 apply 하세요. 채점기는 옮긴 상태와 새 상태가 서로 다른 lineage 이고, out/ 에 서버 파일이 두 개 생겼는지 봅니다.
3. tofu state push lost/terraform.tfstate 로 옛 상태를 되돌려 놓으려 해 보세요. 출력(오류 포함)을 /root/iac-state/push.txt 에 저장합니다. -force 는 쓰지 않습니다. 채점기는 지금 상태의 lineage 가 옛 상태와 여전히 다른지도 봅니다.
4. /root/iac-state/rebuild/ 에 같은 main.tf 를 복사하고, import 블록으로 옛 상태(lost/terraform.tfstate)의 random_id.server 를 가져오세요. import 식별자는 옛 상태의 그 리소스 속성에서 찾습니다. rebuild 에서 init·apply 한 뒤 계획이 깨끗해야 합니다. 채점기는 rebuild 상태의 hex 가 옛 서버의 hex 와 같은지 봅니다.
5. /root/iac-state/lockdemo/main.tf 에 local-exec 로 15초 자는 terraform_data.slow 를 두고 init 하세요. apply 를 백그라운드로 시작하고, 끝나기 전에 같은 디렉터리에서 tofu plan 을 돌려 출력을 /root/iac-state/lock.txt 에 저장하세요. 이어서 tofu plan -lock-timeout=60s 를 돌려 잠금이 풀릴 때까지 기다린 뒤의 출력을 /root/iac-state/lockwait.txt 에 저장합니다. 채점기는 임시 디렉터리에서 같은 상황을 직접 만들어도 확인합니다.
6. /root/iac-state/network/ 에 random_id.vpc(byte_length 3)와 출력 vpc_id = "vpc-<hex>" 를, /root/iac-state/app/ 에는 terraform_remote_state 데이터 소스(local 백엔드, ../network/terraform.tfstate)로 그 출력을 읽어 out/app.conf 에 vpc=<vpc_id> 한 줄을 쓰는 local_file.app 을 두세요. network 를 먼저, app 을 나중에 init·apply 합니다. 두 디렉터리 모두 계획이 깨끗해야 합니다.
7. /root/iac-state/.gitignore 를 만드세요. git check-ignore 기준으로 terraform.tfstate, terraform.tfstate.backup, lost/terraform.tfstate, .terraform/(그 안의 파일), change.tfplan 같은 계획 파일은 무시되고, .terraform.lock.hcl 과 main.tf, app/main.tf 는 무시되지 않아야 합니다. 채점기는 임시 git 저장소에 이 .gitignore 를 두고 확인합니다.
참고
- 파드에는 OpenTofu 1.9.0 과 local·random 프로바이더 미러가 있어 인터넷 없이 돕니다. 이 실습의 백엔드는 모두 local 입니다.
- local 백엔드의 잠금은 운영체제 파일 잠금이라, 적용 중인 프로세스가 죽으면 잠금도 풀립니다. 그래서 강제 해제(force-unlock)가 필요한 '남은 잠금' 은 원격 백엔드에서만 생기며 이 파드에서는 재현하지 않습니다.
- 흔한 실수: 2단계에서 terraform.tfstate.backup 을 남겨 두는 것 — 백업이 있다고 도구가 자동으로 되살리지는 않지만, 나중에 어느 쪽이 진짜인지 헷갈리게 합니다.
- 흔한 실수: import 로 되찾을 때 식별자에 hex 를 넣는 것. 리소스마다 받는 식별자가 다르니 프로바이더 문서를 확인합니다.
- [State](https://opentofu.org/docs/language/state/) · [State Locking](https://opentofu.org/docs/language/state/locking/) · [tofu state push](https://opentofu.org/docs/cli/commands/state/push/) · [Import](https://opentofu.org/docs/language/import/) · [random_id (Import)](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/id) · [terraform_remote_state](https://opentofu.org/docs/language/state/remote-state-data/) · [Backend: local](https://opentofu.org/docs/language/settings/backends/local/)
단계 7개
- 상태 파일을 열어 본다
- 상태를 잃었더니 같은 서버가 하나 더 생겼다
- 옛 상태를 덮어쓰려 했더니 거절됐다
- 잃은 서버를 import 로 되찾는다
- 적용하는 동안 다른 계획은 잠금에 막힌다
- 수명이 다른 층은 상태를 나누고 출력으로만 잇는다
- 상태와 계획은 커밋하지 않고, 잠금 파일은 커밋한다