Adding a Second Region Left the Module Without a Provider
한국어 원문으로 표시합니다.
목표
같은 프로바이더를 두 벌 설정해 리소스마다 고르고, 모듈에 그 설정을 넘기고, 하나를 빠뜨렸을 때 무엇이 막는지 본 뒤, 버전 제약을 좁혀 가며 init 이 언제 통과하고 언제 거절하는지 직접 확인합니다.
왜 중요한가
인프라 코드가 한 리전·한 계정 안에 머무는 기간은 생각보다 짧습니다. 재해 복구용 두 번째 리전, 감사 로그를 따로 모으는 계정, 공용 레지스트리와 사설 레지스트리 — 어느 쪽이든 같은 프로바이더를 서로 다른 설정으로 두 벌 갖게 됩니다. 이때 리소스가 어느 설정으로 만들어졌는지는 코드가 아니라 상태에 남고, 그 기록이 틀리면 나중에 엉뚱한 곳을 지웁니다. 모듈은 한 걸음 더 나갑니다 — 모듈이 자기 프로바이더 설정을 스스로 만들면 그 모듈은 두 번 쓸 수 없게 되므로, 자리만 선언하고 부르는 쪽이 채우게 설계합니다. 버전 제약은 이 모든 것의 바닥입니다. 제약을 어떻게 적느냐가 '내일 아침 CI 가 새 판을 받아 와도 되는가' 를 결정하고, 잠금 파일이 그 결정의 근거를 남깁니다.
단계
/root/tfa-alias/main.tf에required_version = ">= 1.6.0"과required_providers의 random(source = "hashicorp/random",version = "3.9.0")을 두고, 기본 프로바이더 설정 블록 하나와random_pet.root(length 2)를 선언한 뒤 init·apply 하세요./root/tfa-alias/aliased.tf를 새로 만들어alias = "seeded"인 두 번째 random 프로바이더 설정과, 그 설정으로 만들어지는random_pet.aliased(length 4)를 선언하세요.main.tf의random_pet.root는 기본 설정 그대로 둡니다. apply 한 뒤 상태 파일에서 두 리소스의 프로바이더 주소가 어떻게 다른지 확인하세요./root/tfa-alias/modules/site/main.tf에configuration_aliases = [random.east, random.west]를 선언하고 각각으로 만드는random_pet.east·random_pet.west(둘 다 length 2)와 같은 이름의 출력 두 개를 두세요./root/tfa-alias/site.tf에서 그 모듈을 부르며providers맵을random.east = random과random.west = random.seeded로 채우고, 모듈의 두 출력을 루트 출력site_east·site_west로 올린 뒤 init·apply 하세요./root/tfa-alias/site.tf의providers맵에서random.west줄만 지우고tofu init을 돌려 오류를/root/tfa-alias/missing-provider.txt에 저장하세요(성공하면 안 됩니다). 그다음 지운 줄을 되돌리고 다시 init·apply 해서 계획이 깨끗한 상태로 마치세요./root/tfa-alias/probe/too-new/main.tf에 random 을version = ">= 4.0.0"으로 제약한required_providers만 두고 그 디렉터리에서 init 하세요. 출력은/root/tfa-alias/probe/too-new/init.txt에 저장합니다. 이 디렉터리에는 잠금 파일이 생기지 않아야 합니다.- 두 디렉터리에서 같은 프로바이더를 서로 다르게 제약해 결과를 견주세요.
/root/tfa-alias/probe/minor/main.tf에는 random 제약을~> 3.8로 둡니다./root/tfa-alias/probe/patch/main.tf에는 random 제약을~> 3.8.0으로 둡니다. 둘 다 init 한 뒤/root/tfa-alias/probe/verdict.tsv에minor·patch두 줄을 탭 세 칸(<이름>,ok또는fail, 설치된 버전 또는none)으로 적습니다. /root/tfa-alias/probe/core/main.tf에required_version = ">= 999.0.0"만 둔 뒤 init 해 오류를/root/tfa-alias/probe/core/init.txt에 저장하고, 지금 파드의 실제 코어 버전(tofu version첫 줄의 숫자만, 예:1.2.3꼴)을/root/tfa-alias/probe/core/version.txt에 한 줄로 적으세요./root/tfa-alias/report.tsv에 네 줄을 탭 두 칸으로 적으세요.lock_version= 루트 잠금 파일에 적힌 random 의 버전,lock_constraints= 그 잠금 파일에 적힌 제약 문자열,provider_configs= 루트 설정의 random 프로바이더 설정 블록 수,aliased_resources= 상태에서 별칭 설정으로 만들어진 리소스 수(모듈 안까지 셉니다).
참고
- 파드의 프로바이더 미러에는 random 3.9.0 한 판만 들어 있습니다. 그래서 제약을 만족하지 못하는 경우를 진짜 오류로 볼 수 있습니다.
- 물결표 제약은 맨 오른쪽 자리만 올라갈 수 있게 합니다. 자리를 두 개 적었을 때와 세 개 적었을 때가 허용하는 범위가 다릅니다.
- 흔한 실수: 리소스에 모듈용 메타 인자인 providers 를 쓰는 것. 리소스는 provider, 모듈은 providers 입니다.
- 흔한 실수: 5·6·7단계의 탐색용 디렉터리를 루트 안에 만들면서 루트의 설정 파일을 덮어쓰는 것. probe/ 아래에 따로 만드세요.
- 잠금 파일 자체의 구조와 해시 검증은 terraform-basics 에서 다룹니다. 여기서는 별칭과 제약이 잠금 파일에 무엇을 남기는지만 봅니다.
- Provider Configuration · Provider Requirements · Providers Within Modules · Version Constraints · Dependency Lock File
코어와 프로바이더의 버전을 못 박는다
/root/tfa-alias/main.tf 에 required_version = ">= 1.6.0" 과 required_providers 의 random(source = "hashicorp/random", version = "3.9.0")을 두고, 기본 프로바이더 설정 블록 하나와 random_pet.root(length 2)를 선언한 뒤 init·apply 하세요.
required_version 은 코어(OpenTofu 자체)의 버전을, required_providers 의 version 은 플러그인의 버전을 제약합니다. 둘은 서로 다른 것이라 한쪽만 적어도 init 은 됩니다. 잠금 파일이 무엇을 적어 두는지 apply 뒤에 열어 보세요.
같은 프로바이더를 두 벌 설정한다
/root/tfa-alias/aliased.tf 를 새로 만들어 alias = "seeded" 인 두 번째 random 프로바이더 설정과, 그 설정으로 만들어지는 random_pet.aliased(length 4)를 선언하세요. main.tf 의 random_pet.root 는 기본 설정 그대로 둡니다. apply 한 뒤 상태 파일에서 두 리소스의 프로바이더 주소가 어떻게 다른지 확인하세요.
리소스에서 별칭 설정을 고르는 메타 인자는 provider 입니다(providers 가 아닙니다 — 그건 모듈용입니다). 상태 파일의 각 리소스에는 어떤 프로바이더 설정으로 만들어졌는지가 문자열로 적혀 있고, 별칭이 붙은 쪽만 끝이 다릅니다.
모듈에 프로바이더 설정을 넘긴다
/root/tfa-alias/modules/site/main.tf 에 configuration_aliases = [random.east, random.west] 를 선언하고 각각으로 만드는 random_pet.east·random_pet.west(둘 다 length 2)와 같은 이름의 출력 두 개를 두세요. /root/tfa-alias/site.tf 에서 그 모듈을 부르며 providers 맵을 random.east = random 과 random.west = random.seeded 로 채우고, 모듈의 두 출력을 루트 출력 site_east·site_west 로 올린 뒤 init·apply 하세요.
configuration_aliases 는 '이 모듈은 이런 이름의 설정을 부르는 쪽에서 받는다' 는 선언입니다. 모듈 안에서 provider 블록을 만들지 않는 이유는, 모듈이 자기 자격증명을 스스로 정하면 재사용이 불가능해지기 때문입니다. providers 맵의 왼쪽은 모듈 안의 이름, 오른쪽은 루트의 설정입니다.
넘기는 것을 하나 빠뜨리면 무엇이 막나
/root/tfa-alias/site.tf 의 providers 맵에서 random.west 줄만 지우고 tofu init 을 돌려 오류를 /root/tfa-alias/missing-provider.txt 에 저장하세요(성공하면 안 됩니다). 그다음 지운 줄을 되돌리고 다시 init·apply 해서 계획이 깨끗한 상태로 마치세요.
모듈이 요구한 설정 자리를 부르는 쪽이 채우지 않으면 도구가 어떤 이름을 못 받았는지 콕 집어 말해 줍니다. 오류 메시지에 그 이름이 그대로 나오는지 보세요. 출력은 표준 오류로 나가니 2>&1 로 함께 받아야 합니다.
미러에 없는 버전을 요구해 본다
/root/tfa-alias/probe/too-new/main.tf 에 random 을 version = ">= 4.0.0" 으로 제약한 required_providers 만 두고 그 디렉터리에서 init 하세요. 출력은 /root/tfa-alias/probe/too-new/init.txt 에 저장합니다. 이 디렉터리에는 잠금 파일이 생기지 않아야 합니다.
이 파드의 프로바이더 미러에는 random 이 한 판만 들어 있습니다. 제약을 만족하는 판이 없을 때 도구가 '무엇을 찾다가 못 찾았는지' 를 그대로 말해 주는지 확인하세요. 실패한 init 은 잠금 파일을 남기지 않습니다.
물결표 제약 두 가지가 서로 다른 것을 허용한다
두 디렉터리에서 같은 프로바이더를 서로 다르게 제약해 결과를 견주세요.
/root/tfa-alias/probe/minor/main.tf 에는 random 제약을 ~> 3.8 로 둡니다.
/root/tfa-alias/probe/patch/main.tf 에는 random 제약을 ~> 3.8.0 으로 둡니다.
둘 다 init 한 뒤 /root/tfa-alias/probe/verdict.tsv 에 minor·patch 두 줄을 탭 세 칸(<이름>, ok 또는 fail, 설치된 버전 또는 none)으로 적습니다.
물결표 제약은 맨 오른쪽 자리만 올릴 수 있게 허용합니다. 자리를 몇 개 적었는지가 곧 '어디까지 올라가도 되는가' 입니다. 설치된 버전은 그 디렉터리의 잠금 파일에서 읽습니다.
코어 버전 제약은 플러그인보다 먼저 막는다
/root/tfa-alias/probe/core/main.tf 에 required_version = ">= 999.0.0" 만 둔 뒤 init 해 오류를 /root/tfa-alias/probe/core/init.txt 에 저장하고, 지금 파드의 실제 코어 버전(tofu version 첫 줄의 숫자만, 예: 1.2.3 꼴)을 /root/tfa-alias/probe/core/version.txt 에 한 줄로 적으세요.
코어 버전 제약은 프로바이더를 받기도 전에 검사합니다 — 그래서 required_providers 가 아예 없어도 막힙니다. 오류 메시지가 '지금 쓰는 버전' 을 그대로 말해 주니 version.txt 와 같은 숫자인지 견줘 보세요.
무엇이 어떤 설정으로 만들어졌는지 표로 낸다
/root/tfa-alias/report.tsv 에 네 줄을 탭 두 칸으로 적으세요. lock_version = 루트 잠금 파일에 적힌 random 의 버전, lock_constraints = 그 잠금 파일에 적힌 제약 문자열, provider_configs = 루트 설정의 random 프로바이더 설정 블록 수, aliased_resources = 상태에서 별칭 설정으로 만들어진 리소스 수(모듈 안까지 셉니다).
잠금 파일에는 고른 버전과 그때의 제약이 함께 적혀 있어서, 나중에 '왜 이 판이 골라졌나' 를 되짚을 수 있습니다. 별칭으로 만들어진 리소스는 상태의 provider 문자열 끝이 다릅니다 — jq 로 세어 보세요.