terraform plan 커맨드

terraform plan 커맨드

terraform plan 커맨드는 실행 플랜을 만들어서 Terraform이 인프라에 적용하려는 변경을 미리 볼 수 있게 해줘요. 실제로 변경을 수행하지 않으므로, 변경을 적용하거나 팀과 공유하기 전에 제안된 변경이 기대와 일치하는지 확인하는 데 사용할 수 있어요.

출처: 문서

본문

소개 (Introduction)

기본적으로 Terraform은 플랜을 만들 때 다음 작업을 수행해요:

  • 이미 존재하는 원격 객체의 현재 상태를 읽어서 Terraform 상태가 최신인지 확인해요.
  • 현재 설정을 이전 상태와 비교하고 차이점을 기록해요.
  • 적용하면 원격 객체가 설정과 일치하게 만드는 일련의 변경 작업을 제안해요.

실습: Terraform: Get Started 튜토리얼을 해보세요. plan 커맨드에 대한 더 깊이 있는 내용은 Create a Terraform Plan 튜토리얼을 확인하세요.

plan 커맨드 단독으로는 제안된 변경을 실제로 수행하지 않아요. 이 커맨드로 제안된 변경이 기대와 일치하는지 확인하거나, 변경을 적용하기 전에 팀과 공유해서 더 넓은 검토를 받을 수 있어요.

Terraform이 리소스 인스턴스나 루트 모듈 출력 값에 대해 변경이 필요 없다고 감지하면, terraform plan은 취할 작업이 없다고 보고해요.

대화형 터미널에서 Terraform을 직접 사용하고 Terraform이 제안하는 변경을 적용할 예정이라면, 대신 terraform apply를 직접 실행할 수도 있어요. 기본적으로 "apply" 커맨드는 새 플랜을 자동으로 생성하고 승인을 요청해요.

선택적 -out=FILE 옵션을 사용해서 생성된 플랜을 디스크의 파일로 저장할 수 있어요. 나중에 그 파일을 추가 인자로 terraform apply에 전달해서 실행할 수 있어요. 이 두 단계 워크플로는 주로 자동화에서 Terraform 실행할 때 사용하기 위한 것이에요.

-out=FILE 옵션 없이 terraform plan을 실행하면 탐색용(speculative) 플랜을 만드는데, 이는 플랜의 효과에 대한 설명이지만 실제로 적용할 의도는 없는 것이에요.

실제 인프라에 변경을 가하는 데 버전 관리와 코드 리뷰 워크플로를 사용하는 팀에서는, 개발자가 코드 리뷰에 제출하기 전에 변경 효과를 검증하는 데 탐색용 플랜을 사용할 수 있어요. 하지만 그 사이에 대상 시스템에 가해진 다른 변경 때문에 설정 변경의 최종 효과가 이전 탐색용 플랜이 나타낸 것과 달라질 수 있다는 점을 고려하는 게 중요해요. 따라서 적용 전에 항상 최종 비탐색용 플랜을 다시 확인해서 여전히 의도와 일치하는지 확인해야 해요.

사용법 (Usage)

사용법: terraform plan [options]

plan 하위 커맨드는 루트 모듈 설정을 위해 현재 작업 디렉터리를 봐요.

plan 커맨드는 Terraform의 주요 커맨드 중 하나이므로 다양한 옵션이 있어요. 이후 섹션에서 설명해요. 하지만 대부분의 경우 이 옵션 중 어떤 것도 설정할 필요가 없어요. 일반적인 작업에서는 특별한 추가 옵션 없이도 잘 동작하도록 Terraform 설정을 설계하는 것이 일반적이기 때문이에요.

이 페이지의 나머지 섹션들은 다양한 옵션을 설명해요:

플래닝 모드 (Planning Modes)

이전 섹션은 원격 시스템을 설정에 가한 변경에 맞추는 Terraform의 기본 플래닝 동작을 설명했어요. Terraform에는 각각 다른 의도된 결과를 가진 플랜을 만드는 두 가지 대체 플래닝 모드가 있어요. 이 옵션은 terraform planterraform apply 모두에서 사용할 수 있어요.

  • Destroy 모드: 현재 존재하는 모든 원격 객체를 파괴하고 빈 Terraform 상태를 남기는 것이 목표인 플랜을 만들어요. terraform destroy를 실행하는 것과 같아요. Destroy 모드는 관리 객체가 개발 작업이 끝나면 더 이상 유용하지 않은 임시 개발 환경 같은 상황에서 유용해요. -destroy 커맨드라인 옵션으로 destroy 모드를 활성화해요.

  • Refresh-only 모드: Terraform 상태와 루트 모듈 출력 값을 Terraform 외부에서 원격 객체에 가해진 변경과 일치하도록 갱신하는 것이 목표인 플랜을 만들어요. 의도적으로 원격 객체 하나 이상을 평소 워크플로 밖에서 변경했을 때(예: 인시던트 대응 중) 유용해요. 이제 Terraform의 기록을 그 변경과 조정해야 하는 상황에서요. -refresh-only 커맨드라인 옵션으로 refresh-only 모드를 활성화해요.

대체 모드 중 어떤 것도 선택되지 않았을 때 Terraform이 사용하는 기본 플래닝 모드를 "일반 모드(Normal mode)"라고 불러요. 이 대체 모드들은 특수 상황 전용이므로, Terraform 문서 중 일부는 일반 플래닝 모드만 다룬답니다.

플래닝 모드는 서로 상호 배타적이에요. 기본이 아닌 플래닝 모드를 활성화하면 "일반" 플래닝 모드가 비활성화되고, 한 번에 두 개 이상의 대체 모드를 사용할 수 없어요.

참고: Terraform v0.15 이하에서 -destroy 옵션은 terraform plan 커맨드만 지원하고 terraform apply 커맨드는 지원하지 않아요. 이전 버전에서 destroy 모드 플랜을 만들고 적용하려면 terraform destroy를 실행해야 해요.

참고: -refresh-only 옵션은 Terraform v0.15.4 이상에서만 사용할 수 있어요.

실습: Refresh-Only 모드로 Terraform 상태 동기화 튜토리얼을 해보세요.

플래닝 옵션 (Planning Options)

대체 플래닝 모드 외에도 플래닝 동작을 수정할 수 있는 몇 가지 옵션이 있어요. 이 옵션은 terraform planterraform apply 모두에서 사용할 수 있어요.

  • -invoke=action..: 플랜을 만들 작업(action)을 지정해요. 설정하면 Terraform이 플랜에서 다른 모든 설정을 제외해요. 작업에 대한 자세한 내용은 작업 호출하기를 참고하세요.

  • -refresh=false - 설정 변경을 확인하기 전에 Terraform 상태를 원격 객체와 동기화하는 기본 동작을 비활성화해요. 이렇게 하면 원격 API 요청 수가 줄어들어 플래닝 작업이 더 빨라질 수 있어요. 하지만 refresh=false로 설정하면 Terraform이 외부 변경을 무시해서 불완전하거나 부정확한 플랜이 나올 수 있어요. refresh=false는 refresh-only 플래닝 모드에서는 사용할 수 없어요. 플래닝 작업 전체를 사실상 비활성화하게 되기 때문이에요.

  • -replace=ADDRESS - 주어진 주소의 리소스 인스턴스를 교체하도록 플랜을 만들라고 Terraform에 지시해요. 하나 이상의 원격 객체가 저하되었고, 같은 설정으로 교체 객체를 사용해서 변경 불가능(immutable) 인프라 패턴에 맞출 수 있을 때 유용해요. 지정된 리소스가 평소에는 "update" 작업을 일으키거나 아무 작업도 일으키지 않을 때 Terraform은 "replace" 작업을 사용해요. 여러 객체를 한 번에 교체하려면 이 옵션을 여러 번 포함하세요. -replace-destroy 옵션과 함께 사용할 수 없고, Terraform v0.15.2부터 사용할 수 있어요. 이전 버전에서는 비슷한 결과를 얻으려면 terraform taint를 사용하세요.

  • -target=ADDRESS - 플래닝 작업을 주어진 주소와 일치하는 리소스 인스턴스와 그 인스턴스가 의존하는 객체에만 집중하라고 Terraform에 지시해요.

    참고: 실수 복구나 Terraform 제한 우회와 같은 예외적인 상황에서만 -target=ADDRESS를 사용하세요. 자세한 내용은 리소스 타게팅을 참고하세요.

  • -var 'NAME=VALUE' - 설정의 루트 모듈에 선언된 단일 입력 변수에 값을 설정해요. 여러 변수를 설정하려면 이 옵션을 여러 번 사용하세요. 자세한 내용은 명령줄의 입력 변수를 참고하세요.

  • -var-file=FILENAME - 설정의 루트 모듈에 선언된 많은 입력 변수.tfvars 파일의 정의를 사용해 값을 설정해요. 여러 파일의 값을 포함하려면 이 옵션을 여러 번 사용하세요. 루트 모듈의 입력 변수에 값을 설정하는 방법은 -var-var-file 옵션 외에도 여러 가지가 있어요. 자세한 내용은 입력 변수에 값 할당을 참고하세요.

명령줄의 입력 변수 (Input Variables on the Command Line)

-var 커맨드라인 옵션을 사용해서 루트 모듈에 선언된 입력 변수에 값을 지정할 수 있어요.

다만 이렇게 하려면 선택한 커맨드라인 셸과 Terraform 모두가 구문 분석할 수 있는 커맨드라인을 작성해야 하는데, 따옴표와 이스케이프 시퀀스가 많은 표현식에서는 복잡할 수 있어요. 대부분의 경우 -var-file 옵션을 사용하고 실제 값을 별도의 파일에 작성해서, 셸 구문 분석 결과를 해석하는 대신 Terraform이 직접 값을 구문 분석하게 하는 것을 권장해요.

경고: 등호 앞이나 뒤에 공백을 포함하면 Terraform이 오류를 발생시켜요(예: -var "length = 2").

Linux나 macOS 같은 Unix 스타일 셸에서 -var를 사용하려면 옵션 인자를 작은따옴표 '로 감싸서 셸이 값을 리터럴로 해석하도록 하는 것을 권장해요:

terraform plan -var 'name=value'

의도한 값 안에 작은따옴표도 포함된다면, 셸이 올바르게 해석하도록 그 값을 이스케이프해야 해요. 그러려면 백슬래시 이스케이프 문자가 유효하도록 인용된 시퀀스를 잠시 끝내야 해요:

terraform plan -var 'name=va'\''lue'

Windows에서 Terraform을 사용할 때는 Windows Command Prompt(cmd.exe)를 사용하는 것을 권장해요. Windows Command Prompt에서 변수 값을 Terraform에 전달할 때는 인자를 큰따옴표 "로 감싸세요:

terraform plan -var "name=value"

의도한 값에 리터럴 큰따옴표가 포함된다면 백슬래시로 이스케이프해야 해요:

terraform plan -var "name=va\"lue"

Windows의 PowerShell은 외부 프로그램에 리터럴 따옴표를 올바르게 전달할 수 없으므로, Windows에서는 Terraform과 함께 PowerShell을 사용하지 않는 것을 권장해요. Windows Command Prompt를 대신 사용하세요.

변수 값을 작성하는 적절한 문법은 변수의 타입 제약에 따라 달라져요. 원시 타입인 string, number, bool은 위 예제에서 보여준 것처럼 셸이 요구하는 것 외에 특별한 구두점 없이 직접 문자열 값을 기대해요. list, map, set 타입과 특별한 any 키워드를 포함한 다른 모든 타입 제약에서는 값을 나타내는 유효한 Terraform 언어 표현식을 작성하고, 셸을 통해 리터럴하게 Terraform에 전달되도록 필요한 인용·이스케이프 문자를 작성해야 해요. 예를 들어 list(string) 타입 제약의 경우:

# Unix-style shell
terraform plan -var 'name=["a", "b", "c"]'

# Windows Command Prompt (do not use PowerShell on Windows)
terraform plan -var "name=[\"a\", \"b\", \"c\"]"

환경 변수를 사용해서 입력 변수를 설정할 때도 비슷한 제약이 적용돼요. 루트 모듈 입력 변수를 설정하는 다양한 방법에 대한 자세한 내용은 입력 변수에 값 할당을 참고하세요.

리소스 타게팅 (Resource Targeting)

실습: 리소스 타게팅 튜토리얼을 해보세요.

-target 옵션을 사용해서 Terraform의 주의를 리소스의 일부에만 집중시킬 수 있어요.

리소스 주소 문법을 사용해 제약을 지정할 수 있어요. Terraform은 리소스 주소를 다음과 같이 해석해요:

  • 주어진 주소가 특정 리소스 인스턴스 하나를 식별하면, Terraform은 그 인스턴스만 선택해요. countfor_each가 설정된 리소스의 경우, 리소스 인스턴스 주소는 aws_instance.example[0]처럼 인스턴스 인덱스 부분을 포함해야 해요.
  • 주어진 주소가 리소스 전체를 식별하면, Terraform은 그 리소스의 모든 인스턴스를 선택해요. countfor_each가 설정된 리소스의 경우, 이는 해당 리소스와 현재 연결된 모든 인스턴스 인덱스를 선택한다는 뜻이에요. 단일 인스턴스 리소스(countfor_each 없음)의 경우 리소스 주소와 리소스 인스턴스 주소가 동일하므로 이 가능성은 적용되지 않아요.
  • 주어진 주소가 전체 모듈 인스턴스를 식별하면, Terraform은 해당 모듈 인스턴스와 모든 하위 모듈 인스턴스에 속한 모든 리소스의 모든 인스턴스를 선택해요.

Terraform이 직접 타게팅한 리소스 인스턴스 하나 이상을 선택하면, 그 선택이 직접 또는 간접적으로 의존하는 모든 다른 객체까지 선택 범위를 확장해요.

이 타게팅 기능은 실수 복구나 Terraform 제한 우회 같은 예외적인 상황을 위해 제공돼요. 리소스의 실제 상태가 설정과 어떤 관련이 있는지에 대한 혼란과 감지되지 않은 설정 드리프트(configuration drift)로 이어질 수 있으므로, 일상적인 작업에 -target을 사용하는 것은 권장하지 않아요.

-target을 매우 큰 설정의 격리된 부분을 운영하는 수단으로 사용하는 대신, 큰 설정을 각각 독립적으로 적용할 수 있는 여러 개의 작은 설정으로 나누는 것을 선호하세요. 데이터 소스를 사용하면 다른 설정에서 생성된 리소스에 대한 정보에 접근할 수 있어서, 복잡한 시스템 아키텍처를 독립적으로 갱신할 수 있는 더 관리하기 쉬운 부분들로 나눌 수 있어요.

기타 옵션 (Other Options)

terraform plan 커맨드에는 Terraform이 만들 플랜의 종류를 사용자 정의하기보다는 플래닝 커맨드의 입력과 출력에 관련된 몇 가지 다른 옵션도 있어요. 이 커맨드들은 해당 커맨드의 문서에 별도로 명시되지 않는 한 terraform apply에서 반드시 사용할 수 있는 것은 아니에요.

사용 가능한 옵션은 다음과 같아요:

  • -compact-warnings - 경고에 오류가 함께 수반되어 경고 텍스트가 오류의 유용한 맥락이 될 수 있는 경우가 아니라면, 요약 메시지만 포함하는 간결한 형태로 경고 메시지를 표시해요.

  • -detailed-exitcode - 커맨드가 종료될 때 상세한 종료 코드를 반환해요. 제공하면 결과 플랜이 포함하는 내용에 대해 더 세분화된 정보를 제공하도록 종료 코드와 그 의미가 변경돼요:

    • 0 = 빈 diff로 성공 (변경 없음)
    • 1 = 오류
    • 2 = 비어 있지 않은 diff로 성공 (변경 있음)
  • -generate-config-out=PATH - (실험적) 설정에 import 블록이 있으면, 아직 존재하지 않는 가져온 리소스에 대한 HCL을 생성하도록 Terraform에 지시해요. 설정은 PATH의 새 파일에 작성되는데, 그 파일이 이미 존재하면 Terraform이 오류를 발생시켜요. 다른 이유로 플랜이 실패해도 Terraform이 설정 작성을 시도할 수 있어요.

  • -input=false - 달리 값을 할당받지 않은 루트 모듈 입력 변수에 대해 입력을 요청하는 Terraform의 기본 동작을 비활성화해요. 이 옵션은 비대화형 자동화 시스템에서 Terraform을 실행할 때 특히 유용해요.

  • -json - 기계가 읽을 수 있는 JSON UI 출력을 활성화해요. 이 옵션은 -input=false를 의미하므로, 계속하려면 설정에 할당되지 않은 변수 값이 없어야 해요.

  • -lock=false - 작업 중 상태 잠금을 유지하지 않아요. 다른 사람이 같은 워크스페이스에 대해 동시에 커맨드를 실행할 수 있다면 위험해요.

  • -lock-timeout=DURATION - -lock=false로 잠금을 비활성화하지 않았다면, 오류를 반환하기 전에 일정 시간 동안 잠금 획득을 재시도하도록 Terraform에 지시해요. 기간 문법은 숫자 뒤에 시간 단위 문자를 붙인 형태예요. 예: 3초는 "3s".

  • -no-color - 출력에서 터미널 형식 시퀀스를 비활성화해요. 출력이 터미널 형식을 해석할 수 없는 시스템에서 렌더링되는 맥락에서 Terraform을 실행할 때 사용하세요.

  • -out=FILENAME - 생성된 플랜을 불투명 파일 형식의 주어진 파일명으로 작성해요. 나중에 terraform apply에 전달해서 계획된 변경을 실행하거나, 저장된 플랜 파일로 작업할 수 있는 다른 Terraform 커맨드에 사용할 수 있어요. Terraform은 플랜 파일에 어떤 파일명도 허용하지만, 일반적인 관례는 tfplan이라는 이름을 붙이는 것이에요. Terraform이 다른 파일 형식으로 인식하는 접미사로 이름을 짓지 마세요. .tf 접미사를 사용하면 Terraform이 그 파일을 설정 소스 파일로 해석하려고 시도해서 이후 커맨드에서 구문 오류를 일으킬 거예요. 생성된 파일은 다른 소프트웨어가 소비하기 위한 표준 형식이 아니지만, 그 파일에는 완전한 설정, 계획된 변경과 연결된 모든 값, 그리고 입력 변수를 포함한 모든 플랜 옵션이 들어 있어요. 플랜에 어떤 종류의 민감한 데이터가 포함되어 있으면, Terraform의 터미널 출력에서 가려졌더라도 그 데이터가 플랜 파일에 평문으로 저장돼요. 따라서 저장된 플랜 파일은 잠재적으로 민감한 아티팩트로 취급해야 해요.

  • -parallelism=n - Terraform이 그래프를 탐색할 때 동시 작업 수를 제한해요. 기본값은 10이에요.

로컬 백엔드를 사용하는 설정에서만 terraform plan은 레거시 커맨드라인 옵션인 -state를 받아요.

다른 설정 디렉터리 전달 (Passing a Different Configuration Directory)

Terraform v0.13 이하에서는 추가 위치 인자로 디렉터리 경로를 받았고, 그 경우 Terraform은 현재 작업 디렉터리 대신 그 디렉터리를 루트 모듈로 사용했어요.

이 사용법은 Terraform v0.14에서 더 이상 사용되지 않고 v0.15에서 제거됐어요. 루트 모듈 디렉터리를 재정의하는 워크플로에 의존한다면, 모든 커맨드에서 작동하고 Terraform이 현재 작업 디렉터리에서 평소 읽거나 쓰는 모든 파일에 대해 주어진 디렉터리를 일관되게 사용하게 하는 전역 -chdir 옵션을 대신 사용하세요.

이 레거시 패턴의 이전 사용이 루트 모듈 디렉터리가 재정의되었음에도 현재 작업 디렉터리에 .terraform 하위 디렉터리를 쓰는 것에 의존하고 있었다면, TF_DATA_DIR 환경 변수를 사용해서 Terraform이 .terraform 디렉터리를 현재 작업 디렉터리가 아닌 다른 위치에 쓰도록 지시하세요.

플랜 출력 이해 (Understand plan output)

Terraform이 플랜 작업을 실행하면 설정의 리소스에 대해 취할 모든 작업을 표시해요. Terraform은 리소스를 생성, 파괴, 또는 변경할 계획인지 표시하기 위해 다음 기호를 사용해요:

| | 기호 | 작업 | 설명 | | + | 생성 | 이 리소스는 현재 존재하지 않아요. Terraform이 생성할 거예요. | | - | 파괴 | Terraform이 이 리소스를 파괴할 거예요. | | ~ | 제자리 갱신 | Terraform이 이 리소스를 파괴·재생성하지 않고 갱신할 거예요. | | -/+ | 교체 | Terraform이 이 리소스를 파괴한 다음 재생성할 거예요. |

다음 예제는 리소스를 생성, 삭제, 갱신, 재생성하는 플랜을 보여줘요:

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create
  ~ update in-place
  - destroy
-/+ destroy and then create replacement

Terraform will perform the following actions:

  # aws_instance.api will be updated in-place
  ~ resource "aws_instance" "api" {
      ~ tags                                 = {
          + "Name" = "api"
        }
      ##...
    }

  # aws_instance.web must be replaced
  -/+ resource "aws_instance" "web" {
      ~ ami                                  = "ami-02c98622c4c3f017d" -> "ami-0d7d6fe23ca71032d" # forces replacement
      ##...

  # aws_s3_bucket.new_bucket will be created
  + resource "aws_s3_bucket" "new_bucket" {
      ##...

  # aws_s3_bucket.old_bucket will be destroyed
  # (because aws_s3_bucket.old_bucket is not in configuration)
  - resource "aws_s3_bucket" "old_bucket" {
      ##...

Plan: 2 to add, 1 to change, 2 to destroy.

예제 (Examples)

다음 예제들은 일반적인 사용 사례에 terraform plan 커맨드를 사용하는 방법을 보여줘요.

입력 변수에 값 전달 (Pass values to input variables)

다음 커맨드는 env 입력 변수를 prod로 설정해서 Terraform이 플랜을 만들 때 그 값을 사용하게 해요:

$ terraform plan -var='env=prod'

다음 커맨드는 my-vars.tfvars라는 로컬 파일을 사용해서 입력 변수 값을 설정해요:

$ terraform plan -var-file='my-vars.tfvars'

작업 호출 (Invoke actions)

다음 커맨드는 test라는 aws_lambda_invoke 작업을 호출하는 플랜을 만들어요:

$ terraform plan -invoke='action.aws_lambda_invoke.test'

더 알아보기 (Learn more)