의존성 잠금 파일
의존성 잠금 파일 (Dependency Lock File)
Terraform이 외부 의존성(프로바이더, 모듈)의 버전 선택을 어떻게 고정하고 검증하는지 설명해 드릴게요. .terraform.lock.hcl 파일의 역할과 관리 방법을 이해하면 재현 가능한 구성 관리에 큰 도움이 돼요.
출처: 문서
본문
참고: 이 페이지는 Terraform 0.14 이상의 기능에 관한 내용이에요. 이전 버전의 Terraform은 의존성 선택을 추적하지 않았으므로 여기의 정보는 해당 버전과 무관해요.
실습: 프로바이더 버전 잠금 및 업그레이드 튜토리얼을 해보세요.
Terraform 구성은 자체 코드베이스 밖에서 오는 두 종류의 외부 의존성을 참조할 수 있어요:
- 프로바이더 (Providers): 다양한 외부 시스템과 상호작용하는 지원을 추가하는 Terraform 플러그인.
- 모듈 (Modules): Terraform 구성 구문(그룹)을 재사용 가능한 추상화로 쪼갤 수 있게 해주는 것.
이 두 의존성 유형은 Terraform 자체 및 이들을 의존하는 구성과 독립적으로 배포·업데이트될 수 있어요. 그래서 Terraform은 현재 구성과 잠재적으로 호환되는 의존성 버전이 무엇인지, 그리고 현재 사용하도록 선택된 버전이 무엇인지 결정해야 해요.
구성 안의 버전 제약 (Version constraints)이 잠재적으로 호환되는 의존성 버전을 결정해요. 하지만 각 의존성의 특정 버전을 선택한 뒤에는 Terraform이 내린 결정을 의존성 잠금 파일(dependency lock file)에 기억해서, (기본적으로) 나중에도 같은 결정을 내릴 수 있게 해요.
현재 의존성 잠금 파일은 프로바이더 의존성만 추적해요. Terraform은 원격 모듈의 버전 선택을 기억하지 않으므로, 항상 지정된 버전 제약을 충족하는 가장 최신 모듈 버전을 선택해요. 정확한 버전 제약을 사용하면 Terraform이 항상 같은 모듈 버전을 선택하도록 보장할 수 있어요.
잠금 파일 위치 (Lock File Location)
의존성 잠금 파일은 구성의 각 개별 모듈이 아니라 구성 전체에 속하는 파일이에요. 그래서 Terraform은 이를 생성하고, Terraform을 실행하는 현재 작업 디렉터리(구성의 루트 모듈 .tf 파일이 있는 디렉터리)에서 찾을 것으로 기대해요.
잠금 파일은 항상 .terraform.lock.hcl라는 이름을 가지며, 이 이름은 작업 디렉터리의 .terraform 하위 디렉터리에 Terraform이 캐시하는 다양한 항목에 대한 잠금 파일임을 의미해요.
Terraform은 terraform init 명령을 실행할 때마다 의존성 잠금 파일을 자동으로 생성하거나 업데이트해요. 이 파일을 버전 관리 저장소에 포함해서, 구성 자체의 잠재적 변경을 논의하듯이 외부 의존성의 잠재적 변경도 코드 리뷰를 통해 논의할 수 있어야 해요.
의존성 잠금 파일은 Terraform 언어와 같은 저수준 문법을 사용하지만, 그 자체가 Terraform 언어 구성 파일은 아니에요. 그 차이를 나타내기 위해 .tf 대신 .hcl 접미사를 사용해요.
의존성 설치 동작 (Dependency Installation Behavior)
terraform init이 구성에 필요한 모든 프로바이더 설치를 처리할 때, Terraform은 구성의 버전 제약과 잠금 파일에 기록된 버전 선택을 모두 고려해요.
- 특정 프로바이더에 기존 기록 선택이 없다면, Terraform은 주어진 버전 제약과 일치하는 가장 최신 버전을 선택하고 잠금 파일에 그 선택을 포함해요.
- 특정 프로바이더가 이미 잠금 파일에 선택이 기록되어 있다면, Terraform은 항상 그 버전을 재선택해서 설치해요 (더 새로운 버전이 나왔더라도요).
terraform init실행 시-upgrade옵션을 추가하면 이 동작을 재정의할 수 있어요. 그러면 Terraform은 기존 선택을 무시하고 버전 제약과 일치하는 가장 최신 버전을 다시 선택해요.
특정 terraform init 호출이 잠금 파일을 변경했다면, Terraform은 출력에서 이를 언급해요:
Terraform has made some changes to the provider dependency selections recorded
in the .terraform.lock.hcl file. Review those changes and commit them to your
version control system if they represent changes you intended to make.
이 메시지를 보면 버전 관리 시스템으로 Terraform이 제안한 변경 사항을 검토할 수 있고, 의도한 변경이라면 팀의 평소 코드 리뷰 절차를 통해 보낼 수 있어요.
체크섬 검증 (Checksum verification)
Terraform은 설치하는 각 패키지가 잠금 파일에 이전에 기록된 체크섬 중 적어도 하나와 일치하는지도 검증해요. 일치하는 체크섬이 없으면 오류를 반환해요:
Error: Failed to install provider
Error while installing hashicorp/azurerm v2.1.0: the current package for
registry.terraform.io/hashicorp/azurerm 2.1.0 doesn't match any of the
checksums previously recorded in the dependency lock file.
이 체크섬 검증은 최초 신뢰 (trust on first use) 접근 방식을 나타내요. 새 프로바이더를 처음 추가할 때 어떤 방식으로든(관련 규정이 요구하는 방식으로든) 검증하고 나면, 같은 프로바이더 버전에 대해 향후 terraform init 실행에서 일치하지 않는 패키지를 만나면 Terraform이 오류를 발생시킨다고 신뢰할 수 있어요.
"최초 신뢰" 모델에는 두 가지 특별한 고려 사항이 있어요:
- 암호화 서명으로 서명된 체크섬을 제공하는 원본 레지스트리에서 프로바이더를 설치하면, 하나의 체크섬이 일치하는 한 Terraform은 서명된 모든 체크섬을 유효하게 취급해요. 따라서 잠금 파일에는 현재 플랫폼용으로 설치한 패키지와 다른 플랫폼에서 사용 가능한 다른 패키지의 체크섬이 모두 포함돼요. 이 경우
terraform init출력에 서명 키의 지문이 포함되며,(signed by a HashiCorp partner, key ID DC9FC6B1FCE47986)같은 메시지가 나타나요. 서명된 체크섬이 포함된 잠금 파일을 커밋하기 전에 해당 키 보유자를 신뢰하는지 확인하거나, 해당 프로바이더 버전의 전체 사용 가능 패키지 세트를 검색해 검증할 수 있어요. - 파일시스템 또는 네트워크 미러 같은 대체 설치 방법으로 프로바이더를 처음 설치하면, Terraform은
terraform init을 실행한 플랫폼 외의 다른 플랫폼 체크섬을 검증할 수 없어요. 그래서 다른 플랫폼의 체크섬을 기록하지 않으며, 구성은 다른 어떤 플랫폼에서도 사용할 수 없게 돼요.
이 문제를 피하려면 terraform providers lock 명령으로 잠금 파일에 여러 플랫폼의 체크섬을 미리 채워둘 수 있어요. 그러면 이후 terraform init 호출이 선택한 미러에서 사용 가능한 패키지가 프로바이더 원본 레지스트리의 공식 패키지와 일치하는지 검증할 수 있게 돼요.
잠금 파일 변경 사항 이해하기 (Understanding Lock File Changes)
의존성 잠금 파일은 주로 사용자나 팀이 수동으로 업데이트하는 것이 아니라 Terraform 자체가 자동으로 유지보수하므로, 버전 관리 시스템이 파일이 변경되었다고 표시할 수 있어요. 제안된 변경 사항을 검토하려면 Terraform이 잠금 파일에 만들 수 있는 몇 가지 변경 유형을 이해해야 해요.
새 프로바이더에 대한 의존성 (Dependency on a new provider)
구성의 아무 모듈에 프로바이더 요구사항에 새 항목을 추가하거나, 새 프로바이더 의존성을 포함하는 외부 모듈을 추가하면, terraform init이 이를 확인해 구성의 모든 버전 제약을 충족하는 프로바이더의 최신 버전을 선택하고, 그 결정을 의존성 잠금 파일의 새 provider 블록으로 기록해요:
provider "registry.terraform.io/hashicorp/azurerm" {
version = "2.30.0"
constraints = "~> 2.12"
hashes = [
"h1:FJwsuowaG5CIdZ0WQyFZH9r6kIJeRKts9+GcRsTz1+Y=",
"h1:c/ntSXrDYM1mUir2KufijYebPcwKqS9CRGd3duDSGfY=",
"zh:04f0a50bb2ba92f3bea6f0a9e549ace5a4c13ef0cbb6975494cac0ef7d4acb43",
"zh:2082e12548ebcdd6fd73580e83f626ed4ed13f8cdfd51205d8696ffe54f30734",
]
}
새 잠금 파일 항목은 몇 가지 정보를 기록해요:
version: 구성의 버전 제약에 기반해 Terraform이 선택한 정확한 버전.constraints: 이 선택을 할 때 Terraform이 고려한 모든 버전 제약. (Terraform은 이 정보로 설치 결정을 내리지 않지만, 사람이 읽는 독자에게 이전 결정이 어떻게 내려졌는지 설명하는 데 포함해요.)hashes: 다른 플랫폼에서 이 프로바이더의 선택된 버전을 구현하는 패키지에 대해 유효하다고 간주되는 여러 체크섬.
기존 프로바이더의 새 버전 (New version of an existing provider)
terraform init -upgrade를 실행해 구성된 버전 제약과 여전히 일치하는 더 새로운 프로바이더 버전을 고려하도록 요청하면, Terraform이 프로바이더의 더 새로운 버전을 선택하고 기존 provider 블록을 그 변경을 반영하도록 업데이트할 수 있어요.
새 프로바이더 버전을 선택하는 주된 효과는 provider 블록의 version 값을 변경하는 것이에요. 업그레이드와 함께 구성된 버전 제약의 변경이 있었다면 Terraform은 그 변경도 constraints 값에 기록해요. 각 버전은 자신만의 배포 패키지 세트를 가지므로, 새 버전으로 전환하면 hashes의 모든 값도 새 버전 패키지의 체크섬을 반영하도록 교체되는 경향이 있어요.
새 프로바이더 패키지 체크섬 (New provider package checksums)
provider 블록에서 볼 수 있는 더 미묘한 변경은, 블록의 다른 것은 아무것도 변하지 않았는데 이전에 기록되지 않았던 새 체크섬이 추가되는 경우예요.
hashes 값에 새 체크섬을 추가하는 것은 Terraform이 서로 다른 해싱 방식 사이를 점진적으로 전환하고 있음을 나타내요. 값의 h1: 및 zh: 접두사는 서로 다른 해싱 방식을 나타내며, 각각 다른 알고리즘으로 체크섬을 계산하는 것을 의미해요. 기존 방식의 한계를 알게 되거나 새 방식이 상당한 추가 이점을 제공하면 때때로 새 해싱 방식을 도입할 수 있어요.
현재 지원되는 두 해싱 방식:
zh:: "zip hash"의 약자로, Terraform 프로바이더 레지스트리 프로토콜의 일부인 레거시 해시 형식이에요. 원본 레지스트리에서 직접 설치하는 프로바이더에 사용돼요. 원본 레지스트리에 인덱싱된 각 공식.zip패키지의 SHA256 해시를 캡처해요. 레지스트리에서 설치할 때 공식 릴리스 패키지를 검증하는 데 효과적이지만, 압축 해제된 디렉터리 레이아웃을 사용하는 파일시스템 미러 같은 다른 프로바이더 설치 방법에서 오는 패키지를 검증하기에는 적합하지 않아요.h1:: "hash scheme 1"의 약자로, 현재 선호되는 해싱 방식이에요. Hash scheme 1도 SHA256 해시지만, 패키지가 담긴.zip아카이브가 아니라 프로바이더 배포 패키지의 내용에서 계산돼요. 그래서 공식.zip파일, 같은 내용의 압축 해제된 디렉터리, 또는 같은 파일을 담지만 다른 메타데이터·압축 방식을 가질 수 있는 재압축된.zip파일 모두에 대해 계산될 수 있다는 장점이 있어요.
zh: 방식의 범위 제한 때문에 Terraform은 이를 알게 될 때마다 기회적으로 해당 h1: 체크섬을 추가해요. h1: 새 해시는 기존 해시 중 하나와도 일치하는 패키지에서 계산된 경우에만 기존 프로바이더에 추가돼요. zh: 체크섬이 일치하는지 확인한 뒤 Terraform은 해당 h1: 체크섬을 기록해서 이전 방식에서 새 방식으로 점진적으로 이전해요.
특정 프로바이더를 처음 설치할 때(기존 provider 블록이 없을 때), Terraform은 프로바이더 개발자의 암호화 서명에 포함된 모든 체크섬으로 hashes 값을 미리 채워요. 이는 보통 지원되는 모든 플랫폼에 걸친 해당 프로바이더 버전의 모든 사용 가능한 패키지를 포함해요. 하지만 프로바이더 레지스트리 프로토콜이 여전히 zh: 방식을 사용하므로 초기 세트는 주로 그 방식을 사용하는 해시로 구성되고, 다른 플랫폼에서 패키지를 설치하면서 Terraform이 기회적으로 업그레이드해요.
새 대상 플랫폼에서 구성 작업을 하면서 새 h1: 해시가 계속 추가되는 것을 피하고 싶거나, 공식 서명 체크섬을 제공할 수 없는 미러에서 프로바이더를 설치하는 경우, terraform providers lock 명령으로 선택한 플랫폼 세트의 해시를 미리 채울 수 있어요:
terraform providers lock \
-platform=linux_arm64 \
-platform=linux_amd64 \
-platform=darwin_amd64 \
-platform=windows_amd64
위 명령은 주어진 네 플랫폼 모두에 대해 필요한 모든 프로바이더의 공식 패키지를 다운로드해 검증한 뒤, 잠금 파일에 각각에 대한 zh: 및 h1: 체크섬을 모두 기록해서 Terraform이 나중에야 h1: 대응물을 알게 되는 경우를 피해요.
더 이상 필요하지 않은 프로바이더 (Providers that are no longer required)
주어진 프로바이더에 대한 의존성이 여전히 존재하는지 판단하기 위해 Terraform은 구성과 state 두 가지 진실 공급원을 사용해요. 특정 프로바이더에 대한 마지막 의존성을 구성과 state 양쪽에서 제거하면, terraform init이 해당 프로바이더의 기존 잠금 파일 항목을 제거해요.
나중에 같은 프로바이더에 대한 새 요구사항을 추가하고 terraform init을 다시 실행하면, Terraform은 이를 완전히 새로운 프로바이더인 것처럼 취급하므로 이전에 선택된 것과 같은 버전을 선택하지 않을 수 있고 체크섬이 변경되지 않았는지 검증할 수도 없어요.
참고: Terraform v1.0 이하에서는
terraform init이 더 이상 필요하지 않은 프로바이더를 잠금 파일에서 자동으로 제거하지 않고 그냥 무시해요. 이전 버전을 사용하는 동안 프로바이더 의존성을 제거한 후 Terraform v1.1 이상으로 업그레이드했다면, 오래된 잠금 파일 항목을 가리키는 "missing or corrupted provider plugins" 오류가 보일 수 있어요. 그렇다면 새 Terraform 버전으로terraform init을 실행해 불필요한 항목을 정리한 뒤 이전 작업을 다시 시도해요.