LabHub
배우기 러닝패스 코스

Terraform/OpenTofu Fundamentals

One Edited Line in the Lock File Stopped init

LabHub 에서 이어서 보기

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

목표

의존성 잠금 파일을 직접 만들고, 제약을 붙여 좁히고, 지웠다 다시 만들고, 해시를 깨뜨렸다 되살립니다. init 이 매번 무엇을 확인하는지, 왜 이 파일만 커밋하고 설치 디렉터리는 커밋하지 않는지를 손으로 확인합니다.

왜 중요한가

잠금 파일은 읽는 파일이 아니라 팀의 계약서입니다. 어떤 버전을 골랐는지(version), 무엇을 허용했는지(constraints), 그 꾸러미가 그때 그것과 같은지(hashes) 세 가지가 여기 적히고, init 은 매번 이 셋을 확인합니다. 계약서가 없으면 어떤 명령도 계획을 세우지 못하고, 체크섬이 어긋나면 설치가 그 자리에서 막힙니다. 이 파일을 커밋하지 않는 팀은 사람마다 다른 버전을 받고, 그래서 '내 노트북에서는 되는데' 가 프로바이더 단위로 생깁니다. 반대로 설치 디렉터리는 커밋하지 않습니다 — 플랫폼마다 다른 바이너리라 저장소가 부풀고, init 이 언제든 다시 만들어 주기 때문입니다.

단계

  1. /root/tfb-lock/app/main.tf 에 local·random 두 프로바이더를 버전 제약 없이 선언하고, random_pet.tag(length 2)와 그 id 를 note.txt 에 쓰는 local_file.note 를 두세요. init 한 뒤 생긴 .terraform.lock.hcl 을 읽어 /root/tfb-lock/lock-read.txtlocal_version=<값>, random_version=<값>, local_hashes=<local 블록의 h1 해시 줄 수> 세 줄을 적으세요.
  2. /root/tfb-lock/pinned/main.tf 를 새로 만들되 이번에는 처음부터 local 에 version = "2.9.0" 을 적고 random 은 제약 없이 두세요. local_file.fixedfixed.txt 하나를 선언하고 init 하세요. 그다음 잠금 파일에서 프로바이더별 constraints 값을 읽어 /root/tfb-lock/constraints.txtlocal=<값>random=none 두 줄을 적으세요.
  3. /root/tfb-lock/app/.terraform/providers/ 아래에서 실제로 설치된 프로바이더 꾸러미의 위치를 찾아 /root/tfb-lock/installed.txtlocal=<버전>/<플랫폼>random=<버전>/<플랫폼> 두 줄을 적으세요.
  4. /root/tfb-lock/fresh/ 를 만들고 /root/tfb-lock/app/main.tf 만 복사하세요(잠금 파일과 .terraform/ 은 가져오지 않습니다). init 없이 tofu plan 을 돌려 오류 출력을 /root/tfb-lock/no-init.txt 에 저장하세요. fresh 에서는 init 을 하지 마세요.
  5. /root/tfb-lock/badpin/main.tf 에 local 만 쓰되 version = "2.5.0" 으로 못 박고 local_file.pinned 하나를 두세요. init 을 돌려 실패 출력을 /root/tfb-lock/pin-fail.txt 에 저장한 뒤, 제약을 2.9.0 으로 고쳐 init 이 성공하게 만드세요.
  6. /root/tfb-lock/app/main.tf 의 local 에 이제서야 version = "2.9.0" 을 붙이고 다시 init 하세요. 잠금 파일의 local 블록에 constraints 줄이 생겼는지 확인해 /root/tfb-lock/stale-lock.txt 의 첫 줄에 after_init=<그 값, 없으면 none> 을 적으세요. 그다음 .terraform.lock.hcl 을 지우고 init 대신 tofu providers lock -fs-mirror=/opt/tofu-mirror -platform=linux_amd64 로 다시 만든 뒤, 그 출력을 /root/tfb-lock/relock.txt 에 저장하고 stale-lock.txt 둘째 줄에 after_relock=<지금 값> 을 적으세요.
  7. /root/tfb-lock/app/.terraform.lock.hcl 의 local 해시 한 줄을 아무 값으로 바꾸고 .terraform/ 을 지운 뒤 init 하세요. 체크섬 오류 출력을 /root/tfb-lock/tamper.txt 에 저장합니다. 그다음 잠금 파일을 지우고 다시 init 해서 제대로 된 해시로 되돌리세요.
  8. /root/tfb-lock/audit.sh 를 만드세요. 첫 인자로 받은 디렉터리의 .terraform.lock.hcl 을 읽어 constraints 줄이 없는 provider 블록의 이름을 한 줄씩 찍고, 하나라도 있으면 종료 코드 1, 없으면 0 으로 끝나야 합니다. /root/tfb-lock/app 에 돌린 결과를 /root/tfb-lock/audit-app.txt 에, /root/tfb-lock/badpin 에 돌린 결과를 /root/tfb-lock/audit-pin.txt 에 저장하고 각 파일의 마지막 줄에 exit=<종료 코드> 를 덧붙이세요.

참고

첫 init 이 만든 계약서를 읽는다

/root/tfb-lock/app/main.tf 에 local·random 두 프로바이더를 버전 제약 없이 선언하고, random_pet.tag(length 2)와 그 id 를 note.txt 에 쓰는 local_file.note 를 두세요. init 한 뒤 생긴 .terraform.lock.hcl 을 읽어 /root/tfb-lock/lock-read.txtlocal_version=<값>, random_version=<값>, local_hashes=<local 블록의 h1 해시 줄 수> 세 줄을 적으세요.

잠금 파일은 HCL 이고 프로바이더마다 provider 블록이 하나씩 생깁니다. 블록 안에 version, 필요하면 constraints, 그리고 hashes 목록이 들어갑니다. apply 는 아직 하지 않아도 됩니다.

제약을 적고 시작하면 계약서에 허용 범위가 함께 남는다

/root/tfb-lock/pinned/main.tf 를 새로 만들되 이번에는 처음부터 local 에 version = "2.9.0" 을 적고 random 은 제약 없이 두세요. local_file.fixedfixed.txt 하나를 선언하고 init 하세요. 그다음 잠금 파일에서 프로바이더별 constraints 값을 읽어 /root/tfb-lock/constraints.txtlocal=<값>random=none 두 줄을 적으세요.

constraints 줄은 설정에 버전 제약을 적었을 때만 잠금 파일에 나타납니다. 제약을 안 적은 프로바이더의 블록에는 아예 그 줄이 없습니다. 무엇을 골랐는가(version)와 무엇을 허용했는가(constraints)는 다른 정보입니다.

잠금 파일이 가리키는 실물이 어디 있는지 찾는다

/root/tfb-lock/app/.terraform/providers/ 아래에서 실제로 설치된 프로바이더 꾸러미의 위치를 찾아 /root/tfb-lock/installed.txtlocal=<버전>/<플랫폼>random=<버전>/<플랫폼> 두 줄을 적으세요.

설치 경로는 레지스트리 주소·네임스페이스·이름·버전·플랫폼 순으로 깊어집니다. 이 디렉터리는 init 이 다시 만들어 주므로 커밋하지 않지만, 잠금 파일은 사람이 리뷰해야 하므로 커밋합니다.

계약서가 없으면 계획조차 못 세운다

/root/tfb-lock/fresh/ 를 만들고 /root/tfb-lock/app/main.tf 만 복사하세요(잠금 파일과 .terraform/ 은 가져오지 않습니다). init 없이 tofu plan 을 돌려 오류 출력을 /root/tfb-lock/no-init.txt 에 저장하세요. fresh 에서는 init 을 하지 마세요.

새로 받은 저장소에서 사람들이 가장 먼저 만나는 오류입니다. 메시지가 무엇을 하라고 말하는지, 왜 계획 단계에서 막는지 생각해 보세요. 프로바이더 없이는 계획을 세울 수가 없습니다.

미러에 없는 버전을 못 박으면 init 이 거절한다

/root/tfb-lock/badpin/main.tf 에 local 만 쓰되 version = "2.5.0" 으로 못 박고 local_file.pinned 하나를 두세요. init 을 돌려 실패 출력을 /root/tfb-lock/pin-fail.txt 에 저장한 뒤, 제약을 2.9.0 으로 고쳐 init 이 성공하게 만드세요.

이 파드의 프로바이더는 오프라인 미러에서만 옵니다. 미러에 없는 버전을 요구하면 도구는 고를 것이 없다고 말합니다. 실무에서도 사내 미러만 쓰는 조직에서 똑같은 메시지를 만납니다.

뒤늦게 붙인 제약은 계약서에 저절로 반영되지 않는다

/root/tfb-lock/app/main.tf 의 local 에 이제서야 version = "2.9.0" 을 붙이고 다시 init 하세요. 잠금 파일의 local 블록에 constraints 줄이 생겼는지 확인해 /root/tfb-lock/stale-lock.txt 의 첫 줄에 after_init=<그 값, 없으면 none> 을 적으세요. 그다음 .terraform.lock.hcl 을 지우고 init 대신 tofu providers lock -fs-mirror=/opt/tofu-mirror -platform=linux_amd64 로 다시 만든 뒤, 그 출력을 /root/tfb-lock/relock.txt 에 저장하고 stale-lock.txt 둘째 줄에 after_relock=<지금 값> 을 적으세요.

init 은 이미 고른 선택이 여전히 제약에 맞으면 다시 고르지 않고, 그래서 잠금 파일을 새로 쓰지도 않습니다. 허용 범위를 계약서에 반영하려면 그 항목을 새로 만들게 해야 합니다. providers lock 은 꾸러미를 설치하지 않고 체크섬만 계산해 적습니다.

해시를 손대면 설치가 막힌다

/root/tfb-lock/app/.terraform.lock.hcl 의 local 해시 한 줄을 아무 값으로 바꾸고 .terraform/ 을 지운 뒤 init 하세요. 체크섬 오류 출력을 /root/tfb-lock/tamper.txt 에 저장합니다. 그다음 잠금 파일을 지우고 다시 init 해서 제대로 된 해시로 되돌리세요.

잠금 파일의 해시는 꾸러미가 그때 그것과 같은지를 확인하는 장치입니다. 손댄 해시로는 어떤 꾸러미도 맞지 않으므로 설치가 멈춥니다. 잘못된 해시를 그대로 둔 채 -upgrade 만 붙여서는 풀리지 않습니다.

제약 없는 프로바이더를 찾아내는 점검을 만든다

/root/tfb-lock/audit.sh 를 만드세요. 첫 인자로 받은 디렉터리의 .terraform.lock.hcl 을 읽어 constraints 줄이 없는 provider 블록의 이름을 한 줄씩 찍고, 하나라도 있으면 종료 코드 1, 없으면 0 으로 끝나야 합니다. /root/tfb-lock/app 에 돌린 결과를 /root/tfb-lock/audit-app.txt 에, /root/tfb-lock/badpin 에 돌린 결과를 /root/tfb-lock/audit-pin.txt 에 저장하고 각 파일의 마지막 줄에 exit=<종료 코드> 를 덧붙이세요.

잠금 파일은 한 줄씩 읽으면 됩니다. provider 로 시작하는 줄이 새 블록의 시작이고, 그 뒤에 constraints 줄이 나오는지만 기억하면 됩니다. awk 의 END 블록에서 마지막 블록도 판정해야 한 개를 놓치지 않습니다.