Infrastructure as Code · 드리프트와 임포트 · 실습
두 저장소가 같은 설정 파일을 서로 되돌리고 있었다
목표
두 상태가 한 자원을 두고 싸우는 모습을 재현해 removed 블록으로 소유를 정리하고, 이미 있는 값을 import 블록·설정 생성·CLI import 로 지우지 않고 데려와 계획이 빈 상태로 관리를 시작합니다.
왜 중요한가
IaC 를 도입할 때는 백지에서 시작하지 않습니다. 손으로 만든 자원이 이미 있고, 그것을 코드로 옮기는 동안 모양만 따라 적으면 도구는 새로 만들어 기존 값을 쓰던 곳을 깨뜨립니다. 그래서 import 로 상태에 먼저 등록하고, 계획이 빌 때까지 코드를 다듬어야 끝난 것입니다. 반대로 한 자원을 두 코드베이스가 관리하면 오류 하나 없이 서로를 되돌리므로, 소유를 넘길 때는 리소스 블록을 지우는(=삭제) 대신 상태에서만 빼는 방법을 써야 합니다.
단계
1. /root/iac-own/team-a/main.tf 와 /root/iac-own/team-b/main.tf 에 각각 local_file.conf 를 두세요. 둘 다 /root/iac-own/shared/app.conf 를 관리하고, 내용은 owner=team-a, owner=team-b 한 줄입니다. 각 디렉터리를 init 한 뒤 team-a, team-b, team-a, team-b 순서로 apply 하고, apply 할 때마다 파일 내용을 /root/iac-own/flip.txt 에 한 줄씩 덧붙이세요.
2. team-b 가 소유를 넘기기로 했습니다. team-b 의 리소스 블록을 지우고 removed { from = local_file.conf } 블록을 두세요. team-b 에서 tofu plan 출력을 /root/iac-own/forget.txt 에 저장한 뒤 apply 하고, 이어서 team-a 를 apply 하세요. 파일은 남아 있어야 하고(team-a 의 내용), team-b 상태에는 local_file 이 없어야 하며, 두 디렉터리의 계획은 모두 깨끗해야 합니다.
3. /root/iac-own/legacy.env 에 손으로 만든 자원의 기록을 적으세요: DB_PASSWORD=Lb7qK2mZx9Wc4Rt8Yp3N, PORT=8123, PORT_RANGE=8000,8999, INSTANCE_ID=6f1c2a4e-3b7d-4c9a-8e2f-1a2b3c4d5e6f, TOKEN=abcDEF123(한 줄에 하나). 그다음 /root/iac-own/naive/main.tf 에 import 없이 random_password.db(길이 20), random_integer.port(8000 부터 8999), random_uuid.instance 를 적고 tofu plan -out=/root/iac-own/naive/naive.tfplan 으로 저장만 하세요(적용하지 않음).
4. /root/iac-own/adopt/main.tf 에 random 프로바이더 요구와 import 블록 셋만 두세요: random_password.db 는 legacy.env 의 비밀번호, random_integer.port 는 <값>,<최소>,<최대> 형식, random_uuid.instance 는 UUID 가 식별자입니다. 리소스 블록은 쓰지 않고 tofu plan -generate-config-out=generated.tf 로 설정을 뽑으세요. 계획이 3 to import, 0 to add, 0 to change, 0 to destroy 여야 합니다(적용하지 않음).
5. generated.tf 의 세 리소스를 adopt/main.tf 로 옮기되 값이 null 인 줄은 빼고, 기본값과 같은 인자도 빼서 짧게 다듬으세요(비밀번호 길이 20, 포트 범위 8000·8999 는 남깁니다). generated.tf 는 지웁니다. 계획이 3 to import, 0 to add, 0 to change, 0 to destroy 인지 확인한 뒤 apply 하세요. 채점기는 상태의 값이 legacy.env 와 같고 그 뒤 계획이 깨끗한지 봅니다.
6. legacy.env 의 TOKEN 을 random_string.token 으로 가져오세요. 이번에는 import 블록을 쓰지 말고 /root/iac-own/adopt/token.tf 에 리소스 블록(길이 9)을 먼저 둔 뒤 tofu import 명령으로 상태에 등록합니다. 그 뒤 계획이 깨끗해야 합니다.
7. /root/iac-own/owners.sh <작업디렉터리>... 를 만드세요. 각 디렉터리의 상태에서 local_file·local_sensitive_file 이 관리하는 파일 경로를 절대 경로로 모아, 같은 경로가 둘 이상의 디렉터리에 있으면 CONFLICT <경로> <디렉터리들(절대 경로, 정렬, 공백 구분)> 을 경로마다 한 줄씩 출력하고 3, 없으면 OK 와 0 으로 끝냅니다. 상대 경로 filename 은 그 작업 디렉터리 기준으로 풉니다. 채점기는 team-a·team-b(이제 OK)와 스스로 만든 충돌 디렉터리로 확인합니다.
참고
- 파드에는 OpenTofu 1.9.0 과 local·random 프로바이더 미러가 있어 인터넷 없이 돕니다.
- import 식별자 형식은 리소스마다 다릅니다: random_password 는 비밀번호 값, random_integer 는
<값>,<최소>,<최대>, random_uuid 는 UUID, random_string 은 문자열 값(프로바이더 문서의 Import 절). - 이 파드의 1.9.0 에서 removed 블록은 from 하나만 받고 늘 '상태에서만 뺀다' 로 동작합니다. 최신 OpenTofu 문서는 같은 뜻을
lifecycle { destroy = false }로 명시하라고 권하는데, 1.9.0 은 그 블록을 거절합니다(실측). - 흔한 실수: 소유를 넘기면서 리소스 블록만 지워 실물 삭제가 계획되는 것. 흔한 실수: 설정 생성 뒤 generated.tf 와 main.tf 에 같은 리소스를 두 번 두는 것.
- [Import](https://opentofu.org/docs/language/import/) · [Generating Configuration](https://opentofu.org/docs/language/import/generating-configuration/) · [tofu import](https://opentofu.org/docs/cli/commands/import/) · [Removing Resources](https://opentofu.org/docs/language/resources/syntax/#removing-resources) · [random_id (Import 형식 예)](https://registry.terraform.io/providers/hashicorp/random/latest/docs/resources/id)
단계 7개
- 두 팀이 같은 파일을 번갈아 되돌린다
- 한쪽이 소유를 내려놓는다 — 지우지 않고 상태에서만 뺀다
- 이미 있는 값을 모양만 따라 적으면 새로 만든다
- import 블록을 쓰고 설정은 도구에게 뽑게 한다
- 뽑은 설정을 다듬어 계획이 빈 채로 가져온다
- 블록 대신 명령으로 하나 더 가져온다
- 소유자가 둘인 파일을 찾아내는 점검