LabHub
学习 学习路径 课程

Terraform 实战

把状态挪走、删掉、再导进来

在 LabHub 中继续学习

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

목표

이미 적용된 자원의 주소를 안전하게 옮기고, 관리 밖에 있던 자원을 상태에 편입시키고, 그 결과 코드와 상태가 어긋나지 않음을 종료 코드로 증명합니다.

왜 중요한가

상태 파일은 도구의 기억입니다. 코드는 "무엇이 있어야 하는가"를, 실물은 "무엇이 있는가"를 말하고, 상태는 "내가 마지막으로 알던 것"을 말합니다. 리팩터링은 이 셋 중 코드만 바꾸는 일이라, 상태를 함께 옮기지 않으면 도구는 옛 자원이 사라지고 새 자원이 생겼다고 판단해 파괴와 생성을 계획합니다. 그래서 이름 변경 같은 사소한 작업이 운영에서는 위험한 작업이 됩니다. 반대로 state rm 은 이름과 달리 실물을 지우지 않습니다 — 장부에서만 지우는 관리 포기 선언이고, 코드에 선언이 남아 있으면 다음 계획이 그 자원을 다시 만들려 듭니다. 이 비대칭을 정확히 알고 있어야 상태 수술이 무섭지 않습니다. 그리고 모든 수술 전에는 사본을 뜨세요. 되돌릴 수 있는 작업과 되돌릴 수 없는 작업의 차이는 그 파일 하나입니다.

단계

  1. /root/tf/surgery/main.tf 에 세 리소스를 선언하고 tofu init 후 적용하세요 — local_file.legacy(파일 /root/tf/surgery/files/legacy.txt), local_file.notes(파일 /root/tf/surgery/files/notes.txt), random_pet.orphan. 그다음 상태 파일을 /root/tf/surgery/backup/terraform.tfstate.bak 로 복사하세요. 사본은 올바른 JSON 이어야 하고 lineage 가 현재 상태와 같아야 하며 리소스가 3개 이상이어야 합니다.
  2. tofu state list 결과를 /root/tf/surgery/out/state-list.txt 로(3줄 이상), tofu state show local_file.legacy 결과를 /root/tf/surgery/out/show-legacy.txt 로 저장하세요. 두 번째 파일에는 id 속성 줄이 보여야 합니다.
  3. tofu state mv local_file.legacy local_file.renamed 로 상태의 주소를 바꾸고, 같은 작업 안에서 코드의 리소스 이름도 renamed 로 고치세요. 옛 local_file.legacy 블록은 주석 처리가 아니라 완전히 지워야 하며, 작업 디렉터리의 어떤 .tf 파일에도 남아 있으면 안 됩니다. 상태만 옮기고 코드를 그대로 두면 다음 계획이 옛 이름의 자원을 다시 만들려 듭니다. tofu plan 출력을 /root/tf/surgery/out/plan-after-rename.txt 로 저장하면 No changes 여야 합니다.
  4. /root/tf/surgery/modules/archive/ 디렉터리에 모듈을 만들어 같은 local_file 리소스를 renamed 라는 이름으로 선언하세요(파일 경로·내용 등 인자 값이 옮기기 전과 완전히 동일해야 합니다). 루트에 module "archive" 블록을 추가하고 tofu init 을 돌린 뒤 tofu state mv local_file.renamed module.archive.local_file.renamed 를 실행하고, 루트 main.tf 에서는 그 리소스 블록을 지우세요(여기서도 주석 처리가 아니라 삭제입니다 — 리소스 선언은 이제 모듈 파일에만 있어야 합니다). tofu plan 출력을 /root/tf/surgery/out/plan-after-module.txt 로 저장하면 No changes 여야 합니다.
  5. tofu state rm random_pet.orphan 을 실행한 뒤 tofu plan 출력을 /root/tf/surgery/out/plan-after-rm.txt 로 저장하세요. 계획에는 random_pet.orphan 을 다시 만들겠다는 내용(1 to add)이 있어야 합니다. 확인했으면 main.tf 에서도 그 리소스 블록을 지우고, /root/tf/surgery/out/rm-note.txtstate rmdestroy 의 차이를 한 줄로 적으세요.
  6. main.tfresource "terraform_data" "adopted" 를 빈 껍데기로 선언하고, 그 위에 import 블록을 두어 to = terraform_data.adopted, id = "labhub-adopted" 를 지정한 뒤 적용하세요. 상태의 terraform_data.adoptedid 속성이 labhub-adopted 여야 합니다.
  7. main.tfresource "terraform_data" "legacy_job" 을 선언하고, 이번에는 명령줄로 tofu import terraform_data.legacy_job labhub-legacy 를 실행하세요. 출력을 /root/tf/surgery/out/import.txt 로 저장하면 Import successful 문구가 보여야 하고, 상태의 terraform_data.legacy_jobidlabhub-legacy 여야 합니다.
  8. tofu plan -detailed-exitcode 를 실행하고 종료 코드만 /root/tf/surgery/out/final-exit.txt 에 적으세요(0 이어야 합니다). 그리고 /root/tf/surgery/out/inventory.json 을 만들어 addresses 에 현재 상태의 모든 주소를 배열로 담고 backup_takentrue 를 넣으세요. 주소 개수는 상태의 인스턴스 수와 정확히 같아야 하며, 목록에는 module.archive. 로 시작하는 주소와 가져온 adopted 주소가 포함돼야 합니다.

참고

수술 전 상태 사본 확보하기

/root/tf/surgery/main.tf 에 세 리소스를 선언하고 tofu init 후 적용하세요 — local_file.legacy(파일 /root/tf/surgery/files/legacy.txt), local_file.notes(파일 /root/tf/surgery/files/notes.txt), random_pet.orphan. 그다음 상태 파일을 /root/tf/surgery/backup/terraform.tfstate.bak 로 복사하세요. 사본은 올바른 JSON 이어야 하고 lineage 가 현재 상태와 같아야 하며 리소스가 3개 이상이어야 합니다.

상태를 만지는 모든 작업 전에 파일을 복사합니다. 사본이 같은 상태의 것인지 확인하려면 계보 값을 비교하세요.

상태 목록과 개별 리소스 들여다보기

tofu state list 결과를 /root/tf/surgery/out/state-list.txt 로(3줄 이상), tofu state show local_file.legacy 결과를 /root/tf/surgery/out/show-legacy.txt 로 저장하세요. 두 번째 파일에는 id 속성 줄이 보여야 합니다.

목록 명령과 특정 주소의 속성을 통째로 보여 주는 명령은 다릅니다. 후자에는 id 속성이 보여야 합니다.

state mv 로 이름만 바꾸기

tofu state mv local_file.legacy local_file.renamed 로 상태의 주소를 바꾸고, 같은 작업 안에서 코드의 리소스 이름도 renamed 로 고치세요. 옛 local_file.legacy 블록은 주석 처리가 아니라 완전히 지워야 하며, 작업 디렉터리의 어떤 .tf 파일에도 남아 있으면 안 됩니다. 상태만 옮기고 코드를 그대로 두면 다음 계획이 옛 이름의 자원을 다시 만들려 듭니다. tofu plan 출력을 /root/tf/surgery/out/plan-after-rename.txt 로 저장하면 No changes 여야 합니다.

코드와 상태가 같은 이름을 가리켜야 계획이 빕니다. 상태만 옮기면 다음 계획이 옛 이름으로 다시 만들려 들고, 코드만 고치면 파괴와 생성이 나란히 뜹니다. 옛 이름의 블록은 주석이 아니라 삭제입니다.

리소스를 모듈 안으로 옮기기

/root/tf/surgery/modules/archive/ 디렉터리에 모듈을 만들어 같은 local_file 리소스를 renamed 라는 이름으로 선언하세요(파일 경로·내용 등 인자 값이 옮기기 전과 완전히 동일해야 합니다). 루트에 module "archive" 블록을 추가하고 tofu init 을 돌린 뒤 tofu state mv local_file.renamed module.archive.local_file.renamed 를 실행하고, 루트 main.tf 에서는 그 리소스 블록을 지우세요(여기서도 주석 처리가 아니라 삭제입니다 — 리소스 선언은 이제 모듈 파일에만 있어야 합니다). tofu plan 출력을 /root/tf/surgery/out/plan-after-module.txt 로 저장하면 No changes 여야 합니다.

모듈 블록을 먼저 만들고 init 을 돌린 뒤 옮깁니다. 모듈 안 리소스의 인자 값이 옮기기 전과 완전히 같아야 계획이 빕니다.

state rm 이 실물을 지우지 않음을 증명하기

tofu state rm random_pet.orphan 을 실행한 뒤 tofu plan 출력을 /root/tf/surgery/out/plan-after-rm.txt 로 저장하세요. 계획에는 random_pet.orphan 을 다시 만들겠다는 내용(1 to add)이 있어야 합니다. 확인했으면 main.tf 에서도 그 리소스 블록을 지우고, /root/tf/surgery/out/rm-note.txtstate rmdestroy 의 차이를 한 줄로 적으세요.

장부에서만 지우는 명령입니다. 코드에 선언이 남아 있으면 다음 계획이 무엇을 하려 드는지 보세요.

import 블록으로 자원 편입하기

main.tfresource "terraform_data" "adopted" 를 빈 껍데기로 선언하고, 그 위에 import 블록을 두어 to = terraform_data.adopted, id = "labhub-adopted" 를 지정한 뒤 적용하세요. 상태의 terraform_data.adoptedid 속성이 labhub-adopted 여야 합니다.

가져올 자리(리소스 블록)를 먼저 만들어야 합니다. 블록에는 어디로(to) 무엇을(id) 가져올지 적습니다.

명령줄 import 로 편입하기

main.tfresource "terraform_data" "legacy_job" 을 선언하고, 이번에는 명령줄로 tofu import terraform_data.legacy_job labhub-legacy 를 실행하세요. 출력을 /root/tf/surgery/out/import.txt 로 저장하면 Import successful 문구가 보여야 하고, 상태의 terraform_data.legacy_jobidlabhub-legacy 여야 합니다.

같은 일을 즉시 실행하는 방식입니다. 출력에 성공 문구가 남으니 파일로 저장하세요.

수술 후 일치 여부를 종료 코드로 증명하기

tofu plan -detailed-exitcode 를 실행하고 종료 코드만 /root/tf/surgery/out/final-exit.txt 에 적으세요(0 이어야 합니다). 그리고 /root/tf/surgery/out/inventory.json 을 만들어 addresses 에 현재 상태의 모든 주소를 배열로 담고 backup_takentrue 를 넣으세요. 주소 개수는 상태의 인스턴스 수와 정확히 같아야 하며, 목록에는 module.archive. 로 시작하는 주소와 가져온 adopted 주소가 포함돼야 합니다.

사람이 눈으로 읽는 판정은 자동화가 아닙니다. 계획의 종료 코드로 판정하고, 상태의 주소를 한 곳에 모아 개수를 맞춰 보세요.