테라폼 버전 업그레이드 절차: 호환성 약속, no-op 검증, 롤백 대비
테라폼 CLI 버전 업그레이드는 미루기 쉽지만, 미룰수록 격차가 쌓여 더 무서워지는 종류의 작업입니다. 결론을 먼저 적으면, 1.x 안의 마이너 업그레이드는 호환성 약속 덕분에 무겁지 않고, 핵심은 세 가지 순서입니다. 체인지로그 확인, 비프로덕션 스택에서 no-op plan 검증, 그리고 팀·CI 버전 통일입니다. 이 글 작성 시점의 안정 버전은 1.15이고 1.16이 베타 단계입니다(2026-08 기준, 도입 시점에 최신 확인). CLI와 별개 축인 provider 메이저 업그레이드는 다음 글에서 따로 다룹니다.
전제: 1.x 호환성 약속 #
테라폼 1.0부터는 호환성 약속(v1.x Compatibility Promises)이 적용됩니다. 1.x 범위 안에서는 기존 구성 파일과 기본 워크플로가 계속 동작하도록 유지된다는 공식 약속으로, 0.x 시절처럼 마이너 버전마다 문법이 바뀌고 마이그레이션 도구를 돌리던 시대와는 다릅니다. 그래서 1.x 마이너 업그레이드는 순차로 밟을 필요 없이 건너뛰어도 됩니다. 1.11에서 1.15로 바로 올려도 구성이 깨지지 않는 것이 원칙입니다.
약속이 커버하지 않는 것도 있습니다. 실험적 기능, 문서화되지 않은 동작, 그리고 deprecated로 예고된 기능의 최종 제거입니다. 그래서 절차의 첫 단계가 체인지로그 확인입니다. 건너뛰는 버전들의 CHANGELOG에서 removed와 deprecated 항목만 훑어도 지뢰는 대부분 드러납니다. 최근 버전대의 실질 변화(네이티브 S3 잠금 use_lockfile, ephemeral 값 등)는 기초 #9 원격 state와 협업에서 다룬 대로 오히려 업그레이드의 이유가 되는 기능들입니다.
업그레이드 절차: no-op이 통과 기준입니다 #
- 체인지로그를 확인합니다: 현재 버전에서 목표 버전까지의 removed·deprecated 항목을 봅니다. 자기 코드에서 쓰는 기능이 걸리는지가 확인 포인트입니다.
- 비프로덕션 스택에서 먼저 올립니다: 개발 환경 스택에서 새 버전으로
terraform plan을 실행합니다. 통과 기준은 “No changes"입니다. 코드도 인프라도 안 바꿨는데 버전만 올려서 diff가 나온다면 원인을 이해할 때까지 진행을 멈춥니다. - plan 출력의 경고를 읽습니다: 새 버전이 내는 deprecation 경고는 다음 업그레이드의 숙제 목록입니다. 이번에 고치면 다음이 가벼워집니다.
- 스택별로 점진 적용합니다: 중요도가 낮은 스택부터 프로덕션까지 순서대로 올리고, 각 스택에서 no-op plan을 같은 기준으로 확인합니다.
- required_version을 갱신합니다: 완료 후
required_version = "~> 1.15.0"처럼 하한과 범위를 새 버전으로 고정해, 구버전 CLI가 실수로 실행되는 것을 차단합니다.
여기서 CLI 업그레이드와 provider 업그레이드를 섞지 않는 것이 중요합니다. terraform init -upgrade는 provider를 잠금 파일 범위 안에서 최신으로 올리는 명령이라, CLI 버전을 올리는 김에 습관적으로 실행하면 두 변수가 동시에 바뀌어 diff의 원인을 특정할 수 없게 됩니다. CLI를 먼저 올려 no-op을 확인하고, provider는 별도 PR에서 올리는 분리가 원칙입니다.
롤백 대비: state 버전의 일방통행 #
되돌릴 계획도 준비해야 하는 이유는 state에 있습니다. 새 CLI가 state를 쓰면 파일 안의 버전 정보가 갱신되는데, 경우에 따라 구버전 CLI가 그 state를 읽지 못합니다. 즉 팀의 절반이 1.15로 apply를 시작한 뒤에는 1.13으로 자연스럽게 돌아갈 수 없는 상황이 생깁니다.
대비는 두 가지입니다. 첫째, S3 백엔드의 버저닝을 확인해 둡니다. 롤백이 필요해지면 새 버전이 쓰기 전의 state 객체 버전으로 되돌리는 것이 복구 경로이고, 이것은 tfstate 삭제 복구에서 다룬 것과 같은 버저닝 의존입니다. 둘째, 업그레이드를 짧은 기간에 팀 전체가 함께 넘어가는 이벤트로 만듭니다. 몇 주씩 신구 버전이 섞여 돌아가는 상태가 가장 위험합니다.
팀·CI 통일: 버전은 파일로 고정합니다 #
로컬만 올리고 CI가 구버전이면, 로컬에서 쓴 state를 CI가 못 읽는 사고가 바로 위의 시나리오대로 납니다. 버전을 사람의 기억이 아니라 파일로 고정합니다.
- required_version: 구성 차원의 강제선입니다. 범위를 벗어난 CLI는 init부터 거부됩니다.
- tfenv 또는 mise: 로컬 버전 관리자입니다. 리포지토리에
.terraform-version파일을 커밋해 두면 체크아웃한 사람 모두 같은 버전이 선택됩니다. mise를 쓰면 테라폼 외 도구 버전까지 한 파일로 관리됩니다. - CI 이미지·셋업 액션의 버전 명시: GitHub Actions라면 setup-terraform의 버전 입력을
.terraform-version과 같은 값으로 맞춥니다. “latest"로 두면 CI가 어느 날 먼저 올라가 버립니다.
업그레이드 작업 자체도 이 파일들을 바꾸는 PR 하나로 표현됩니다. .terraform-version, required_version, CI 설정이 한 커밋에서 함께 바뀌면 리뷰어가 범위를 한눈에 봅니다.
정리 #
- 1.x 호환성 약속 덕분에 마이너 업그레이드는 순차가 아니라 건너뛰기가 가능합니다. 확인할 것은 체인지로그의 removed·deprecated입니다.
- 통과 기준은 no-op plan입니다. 버전만 바꿨는데 diff가 나면 원인을 이해할 때까지 멈춥니다.
- CLI와 provider 업그레이드는 분리합니다. init -upgrade를 습관적으로 섞으면 diff 원인을 특정할 수 없습니다.
- 새 버전이 쓴 state는 구버전이 못 읽을 수 있습니다. S3 버저닝 확인과 짧은 전환 기간이 롤백 대비입니다.
- 버전은 required_version, .terraform-version(tfenv/mise), CI 설정의 세 파일로 고정하고, 업그레이드는 이 파일들을 바꾸는 PR 하나로 만듭니다.