安全规则复制到三处,偏偏漏了 prod
한국어 원문으로 표시합니다.
목표
이미 운영 중인 복붙 환경 둘을 moved 로 교체 없이 모듈 호출로 바꾸고, 모듈을 git 태그로 고정해 dev 만 새 버전을 쓰게 한 뒤, 변수 값이 들어오는 경로의 우선순위와 모듈 경계의 입력 검증을 확인합니다.
왜 중요한가
복붙한 환경은 한 곳을 고칠 때마다 나머지를 빼먹을 기회를 만듭니다. 그렇다고 이미 적용된 코드를 모듈로 옮기면서 리소스 주소가 바뀌면 도구는 그것을 지우고 다시 만들려 하므로, 리팩터링은 상태에 이동을 알리는 일과 함께 해야 합니다. 모듈에 버전이 없으면 모듈을 고친 순간 모든 환경이 같이 바뀌어 '관계없는 환경이 깨짐' 이 생기고, 값이 여러 경로로 들어오는 규칙을 모르면 실험하다 남긴 파일 하나가 운영 값을 조용히 바꿉니다.
단계
/root/iac-mod/dev/main.tf와/root/iac-mod/prod/main.tf에 같은 모양의 리소스 둘을 두세요.local_file.config는out/app.conf에name=api,env=<환경>,replicas=<수>세 줄(dev 1, prod 3),local_file.banner는out/banner.txt에api (<환경>)한 줄입니다. 두 디렉터리 모두 init·apply 하세요./root/iac-mod/modules/web/main.tf에 입력env(문자열)·replicas(수), 같은 두 리소스, 출력config_path를 둔 모듈을 만드세요. dev 의 main.tf 는replicas변수(기본 1)를 두고module "web"을source = "../modules/web"로 부르며,moved블록 두 개로 옛 주소를module.web.local_file.config·module.web.local_file.banner로 옮기세요. init 한 뒤 계획에 생성·삭제·교체가 없어야 하고, 그대로 apply 합니다./root/iac-mod/prod/main.tf도 같은 모듈을 부르게 바꾸세요(replicas기본 3, envprod, moved 두 개). 계획에 생성·삭제·교체가 없어야 하고 apply 합니다. 이제 규칙을 고칠 곳은 모듈 한 곳입니다./root/iac-mod/modules/web을 git 저장소로 만들어 지금 내용을 커밋하고 태그v1.0.0을 붙이세요. dev·prod 의 source 를git::file:///root/iac-mod/modules/web?ref=v1.0.0로 바꾸고tofu init -upgrade한 뒤 두 계획이 모두 깨끗해야 합니다.- 모듈에 두 가지를 더해 커밋하고 태그
v2.0.0을 붙이세요: config 내용 끝에owner=platform한 줄, 그리고replicas가 1 이상 10 이하인지 검사하는 validation. dev 만ref=v2.0.0으로 올려 init·apply 하고, prod 는 v1.0.0 에 남겨 계획이 깨끗해야 합니다. - dev 에서
replicas값을 여러 경로로 넣어 보며echo var.replicas | tofu console로 실제 값을 확인하고/root/iac-mod/precedence.txt에 적으세요. 모든 경우에 환경 변수TF_VAR_replicas=9가 있습니다.env_only(파일 없음),with_tfvars(terraform.tfvars 에 2),with_auto(여기에 a.auto.tfvars 3·b.auto.tfvars 4 추가),with_var_file(여기에-var-file=ops.tfvars, 값 6),with_var(-var-file=ops.tfvars -var replicas=5순서),var_then_file(-var replicas=5 -var-file=ops.tfvars순서) 여섯 줄을이름=값으로 씁니다. 끝나면 a·b.auto.tfvars 와 ops.tfvars 를 지우고 terraform.tfvars(2)만 남겨 apply 하세요. - dev 에서
tofu plan -var replicas=0을 실행해 출력(오류 포함)을/root/iac-mod/invalid.txt에 저장하세요. 채점기는 dev 의 사본에서 0 과 11 이 거부되고, prod(v1.0.0, 검사 없음)에서는 0 이 통과하는지 확인합니다. dev 와 prod 의 계획은 깨끗하게 남겨 둡니다.
참고
- 파드에는 OpenTofu 1.9.0, local 프로바이더 미러, git 이 있어 인터넷 없이 돕니다. 모듈 저장소는
/root/iac-mod/modules/web의 로컬 git 저장소입니다. - 모듈의 source 나 ref 를 바꾸면
tofu init(버전을 올릴 때는-upgrade)을 다시 해야 합니다. - 이 파드의 git 에는 사용자 이름·이메일이 설정돼 있지 않습니다. 커밋할 때
git -c user.name=… -c user.email=… commit처럼 넘기세요. - 흔한 실수: 모듈 안에서 path.module 로 파일 경로를 잡아 moved 뒤에 교체가 붙는 것. 흔한 실수: 우선순위 실험 파일(*.auto.tfvars)을 남겨 두는 것.
- Refactoring(moved) · Module Sources(git, ref) · Input Variables(우선순위·validation) · Terraform: Input Variables
복붙한 두 환경을 먼저 적용해 둔다
/root/iac-mod/dev/main.tf 와 /root/iac-mod/prod/main.tf 에 같은 모양의 리소스 둘을 두세요. local_file.config 는 out/app.conf 에 name=api, env=<환경>, replicas=<수> 세 줄(dev 1, prod 3), local_file.banner 는 out/banner.txt 에 api (<환경>) 한 줄입니다. 두 디렉터리 모두 init·apply 하세요.
이 단계는 '복붙한 코드가 이미 운영 중' 인 출발점을 만드는 것입니다. 두 파일의 차이가 환경 이름과 레플리카 수뿐이라는 점을 확인해 두세요 — 그것이 모듈의 입력이 됩니다.
dev 를 모듈 호출로 바꾸되 아무것도 다시 만들지 않는다
/root/iac-mod/modules/web/main.tf 에 입력 env(문자열)·replicas(수), 같은 두 리소스, 출력 config_path 를 둔 모듈을 만드세요. dev 의 main.tf 는 replicas 변수(기본 1)를 두고 module "web" 을 source = "../modules/web" 로 부르며, moved 블록 두 개로 옛 주소를 module.web.local_file.config·module.web.local_file.banner 로 옮기세요. init 한 뒤 계획에 생성·삭제·교체가 없어야 하고, 그대로 apply 합니다.
모듈 안의 path.module 은 모듈 디렉터리입니다. 파일이 호출한 환경 디렉터리 아래에 있어야 하므로 path.root 를 씁니다 — 이 경로가 옛 값과 한 글자라도 다르면 이동 뒤 교체가 따라옵니다. 모듈을 추가·변경하면 init 을 다시 해야 합니다.
prod 도 같은 모듈로 옮긴다
/root/iac-mod/prod/main.tf 도 같은 모듈을 부르게 바꾸세요(replicas 기본 3, env prod, moved 두 개). 계획에 생성·삭제·교체가 없어야 하고 apply 합니다. 이제 규칙을 고칠 곳은 모듈 한 곳입니다.
dev 와 같은 절차입니다. 차이는 입력값뿐이어야 합니다 — 모듈 안에 env == "prod" 같은 분기를 넣고 싶어지면 그 값은 인자로 받아야 한다는 신호입니다.
모듈에 버전을 붙이고 두 환경을 그 버전에 고정한다
/root/iac-mod/modules/web 을 git 저장소로 만들어 지금 내용을 커밋하고 태그 v1.0.0 을 붙이세요. dev·prod 의 source 를 git::file:///root/iac-mod/modules/web?ref=v1.0.0 로 바꾸고 tofu init -upgrade 한 뒤 두 계획이 모두 깨끗해야 합니다.
로컬 경로 source 는 버전이 없어서, 모듈을 고치는 순간 부르는 모든 환경이 함께 바뀝니다. git 주소의 ref 로 태그를 고정하면 init 이 그 시점의 사본을 .terraform/modules 에 받아 둡니다. 이 파드의 git 에는 사용자 정보가 없으니 git -c user.name=... -c user.email=... 로 커밋하세요.
새 버전은 dev 에서 먼저, prod 는 그대로
모듈에 두 가지를 더해 커밋하고 태그 v2.0.0 을 붙이세요: config 내용 끝에 owner=platform 한 줄, 그리고 replicas 가 1 이상 10 이하인지 검사하는 validation. dev 만 ref=v2.0.0 으로 올려 init·apply 하고, prod 는 v1.0.0 에 남겨 계획이 깨끗해야 합니다.
태그를 고정했기 때문에 모듈 저장소의 main 이 바뀌어도 prod 는 영향을 받지 않습니다. dev 의 계획에서 config 가 어떻게 바뀌는지(내용 변경이라 교체) 확인하고 적용하세요.
같은 변수에 값이 여러 곳에서 들어오면 누가 이기나
dev 에서 replicas 값을 여러 경로로 넣어 보며 echo var.replicas | tofu console 로 실제 값을 확인하고 /root/iac-mod/precedence.txt 에 적으세요. 모든 경우에 환경 변수 TF_VAR_replicas=9 가 있습니다. env_only(파일 없음), with_tfvars(terraform.tfvars 에 2), with_auto(여기에 a.auto.tfvars 3·b.auto.tfvars 4 추가), with_var_file(여기에 -var-file=ops.tfvars, 값 6), with_var(-var-file=ops.tfvars -var replicas=5 순서), var_then_file(-var replicas=5 -var-file=ops.tfvars 순서) 여섯 줄을 이름=값 으로 씁니다. 끝나면 a·b.auto.tfvars 와 ops.tfvars 를 지우고 terraform.tfvars(2)만 남겨 apply 하세요.
우선순위는 '나중에 읽은 것이 이긴다' 로 외우면 됩니다. 환경 변수가 가장 먼저, 그다음 terraform.tfvars, auto.tfvars 는 파일 이름 순서, 명령줄의 -var 와 -var-file 은 적은 순서대로 읽힙니다. 실험한 파일을 남겨 두면 다음 사람의 적용 값이 조용히 바뀝니다.
모듈 경계에서 잘못된 값을 막는다
dev 에서 tofu plan -var replicas=0 을 실행해 출력(오류 포함)을 /root/iac-mod/invalid.txt 에 저장하세요. 채점기는 dev 의 사본에서 0 과 11 이 거부되고, prod(v1.0.0, 검사 없음)에서는 0 이 통과하는지 확인합니다. dev 와 prod 의 계획은 깨끗하게 남겨 둡니다.
validation 은 모듈의 입력 변수에 붙어 있어서, 루트에서 어떤 경로로 값을 넣든 모듈 경계에서 막힙니다. 같은 입력이 prod 에서는 통과한다는 것은 v1 에 검사가 없기 때문이고, 그것이 버전 고정의 양면입니다.