LabHub
배우기 러닝패스 코스

Terraform/OpenTofu基礎

ロックファイルを一行いじったら 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 블록에서 마지막 블록도 판정해야 한 개를 놓치지 않습니다.