들어가며

앞으로 몇 주간에 걸쳐 테라폼 기초 입문 실습 스터디에 참여하면서 배운 내용을 정리하려 합니다. 이번 글의 주제는 테라폼의 기본 사용법이며 “테라폼으로 시작하는 IaC” 책을 기준으로 정리하였습니다.

테라폼으로 시작하는 IaC

테라폼으로 시작하는 IaC

IaC 와 테라폼

하나의 서버를 운영하기 위해서는 수 많은 설치와 설정의 과정이 필요합니다. 서버에 운영체제를 설치하고, 패키지를 설치하고, 설정을 하는 기나긴 작업이 필요합니다. 이것으로 끝나는 것이 아니라 방화벽을 비롯한 네트워크 설정, 보안 설정, 모니터링 설정 등 다양한 설정이 필요합니다. 이러한 작업을 수동으로 진행하다 보면 시간도 많이 소요되고 실수할 가능성도 높아집니다.

하나의 서버를 설정하기 위해서도 이러한 작업이 필요한데, 수대, 수십대, 수백대의 서버를 운영한다면 시간과 실수할 가능성은 엄청 나게 늘어납니다. 이러한 문제를 해결하기 위해 나온 것이 IaC(Infrastructure as Code)입니다.

IaC(Infrastructure as Code)는 인프라를 코드로 관리하는 방식을 말하며, 코드를 git을 이용하여 버전 관리도 할 수 있고 코드 리뷰도 할 수 있습니다. 또한 코드를 통해 인프라를 구성하면 인프라를 재사용하기도 쉽고, 확장하기도 쉽습니다.

IaC에 대표적인 도구로는 테라폼(Terraform)이 있습니다. 테라폼은 인프라를 코드로 관리할 수 있는 도구로, 다양한 클라우드 서비스를 지원하며, 코드를 통해 인프라를 구성할 수 있습니다. 서버만을 예시로 들었지만 테라폼은 서버 뿐만 아니라 AWS와 같은 클라우드 상의 다양한 서비스를 관리할 수 있습니다.

테라폼은 크게 3가지 형태로 구성되어 있습니다.

  • On-premise : Terraform 이라 불리는 형태로, 사용자의 컴퓨팅 환경에 오픈소스 버전의 테라폼을 사용하는 형태입니다.
  • Hosted SaaS : Terraform Cloud 라 불리며, HashiCorp 에서 제공하는 SaaS 서비스로, HashiCorp 가 관리하는 서버 환경을 사용합니다.
  • Private Install : Terraform Enterprise 라 불리는 서버 설치형 구성 환경으로, 기업 내부에 설치하여 사용하는 형태입니다. 외부 네트워크와 격리가 가능합니다.

실행 환경 구성

제가 사용중인 macOS를 기준으로 작성하였습니다. macOS에서 테라폼을 설치하려면 Homebrew를 이용하여 설치할 수 있습니다.

(홈브루 설치 방법은 https://whalec.io/homebrew-설치-및-사용-방법 를 참고하세요.)

# tfenv 설치
brew install tfenv

# 테라폼 1.8.5 설치
tfenv install 1.8.5

# 테라폼 1.8.5 버전을 사용
tfenv use 1.8.5

# 버전 확인
terraform version

# 자동완성 스크립트 추가
terraform -install-autocomplete

# 자동완성 스크립트 적용 (zsh의 경우)
source ~/.zshrc

terraform 명령의 주요 서브 커맨드

  • terraform init : 현재 디렉토리에 terraform 설정 파일들을 생성하고 초기화합니다. 새로운 프로젝트를 만든다는 느낌입니다.
  • terraform validate : terraform 설정 파일들을 검증합니다. 설정 파일들이 올바르게 작성되었는지 확인합니다.
  • terraform plan : terraform 설정 파일들을 기반으로 실행할 계획을 확인합니다. 실제로 실행되는 것은 아닙니다. 어떤 리소스가 생성되고, 삭제되며, 변경되는지 등을 확인할 수 있습니다.
    • terraform plan -out=tfplan : 실행할 계획을 파일로 저장합니다. 이후 terraform apply plan.out으로 실행할 수 있습니다.
  • terraform apply : terraform 설정 파일들을 기반으로 실제 작업을 실행합니다. 사전에 terraform plan으로 변경사항을 확인하고 실행해야 합니다.
    • terraform apply -replace=리소스 : 프로비저닝이 완료된 후 특정 리소스를 삭제 후 다시 생성 합니다. plan, apply 모두 적용 가능합니다.
  • terraform state list : 생성된 리소스들의 목록을 확인합니다.
  • terraform destroy : terraform 설정 파일들을 기반으로 생성된 리소스들을 모두 삭제합니다.
  • terraform fmt : terraform 설정 파일들을 표준 형식과 표준 스타일로 정렬하여 가독성을 높입니다.

terraform 명령의 주요 옵션

  • -auto-approve : terraform apply 시 Y/N을 묻지 않고 자동으로 승인합니다.
  • -help : 도움말을 확인합니다. terraform apply -help와 같이 명렁어와 함께 사용시 해당 명령어의 옵션을 확인 할 수 있습니다.
  • -no-color : <-[0m<[1m 과 같은 문자가 표시되는 경우 색상 정보를 안 나오게하여 정상적으로 나오게 합니다. terraform validate -no-color와 같이 사용할 수 있습니다.

HCL

HCL은 HashiCorp Configuration Language의 약자로, HashiCorp에서 만든 IaC와 구성정보를 명시하기 위한 언어입니다. HCL은 네이티브 문법과 json 호환 문법을 지원합니다. 네이티브 문법의 경우 보통 .tf 확장자를, json 호환 문법의 경우 .tf.json 확장자를 사용합니다.

네이티브 문법이 더 가독성이 좋고 작성하기 편하기 때문에 보통 네이티브 문법을 사용합니다. 주요 문법 적인 특징은 다음과 같습니다.

  • 쿠버네티스 처럼 선언적인 구조를 가지고 있습니다. 즉, 어떻게 하는지 절차를 기록하는것이 아닌, 최종 결과를 정하면 Terraform이 적절한 절차의 계획(plan)을 세워서 적용합니다..
  • 변수와 문자열 값을 함께 사용하는 인터폴레이션(interpolation)을 지원합니다.
    • 예) name = "Hello~ {$var.name}!"
  • HCL은 코드의 모듈화와 재사용성을 위한 기능을 제공합니다.

HCL 네이티브 문법 예시

// 한줄 주석 방법1
# 한줄 주석 방법2

/*
라인
주석
*/

locals {
  key1     = "value1"     # = 를 기준으로 키와 값이 구분되며
  myStr    = "TF ♡ UTF-8" # UTF-8 문자를 지원한다.
  multiStr = <<EOF
  Multi
  Line
  String
  with anytext
EOF

  boolean1    = true   # boolean true
  boolean2    = false  # boolean false를 지원한다.
  deciaml     = 123    # 기본적으로 숫자는 10진수,
  octal       = 0123   # 0으로 시작하는 숫자는 8진수,
  hexadecimal = "0xD5" # 0x 값을 포함하는 스트링은 16진수,
  scientific  = 1e10   # 과학표기 법도 지원한다.

  # funtion 호출 예
  myprojectname = format("%s is myproject name", var.project)

  # 3항 연산자 조건문을 지원한다.
  credentials = var.credentials == "" ? file(var.credentials_file) : var.credentials
}
  • HCL은 주석 부터 변수 정의, 연산, 조건문 등 프로그래밍적인 요소를 가지고 있고, 구성 편의성을 높이기 위한 function을 제공합니다.
  • 테라폼으로 인프라를 구성하기 위한 terraform, resource, data, variable, local, output 과 같은 선언 블록도 다수 존재합니다.

테라폼 블록

테라폼은 다양한 블록을 제공하며, 각 블록은 특정한 역할을 수행합니다.

terraform 블록

  • Terraform의 버전이나 프로바이더 버전 등을 지정 할 수 있고, 리소스를 생성하기 위한 설정을 지정할 수 있습니다.
  • 버전을 지정함으로써 오늘 실행하던, 3년 후에 실행하던 같은 결과를 보장할 수 있습니다.
  • terraform 블록 예시

    # main.tf
    terraform {
      required_version = "~> 1.3.0" # 테라폼 버전
      
      required_providers { # 프로바이더 버전을 나열
        random = {
          version = ">= 3.0.0, < 3.1.0"
        }
        aws = {
          version = "4.2.0"
        }
      }
      
      cloud { # Cloud/Enterprise 같은 원격 실행을 위한 정보
        organization = "<MY_ORG_NAME>"
        workspaces {
          name = "my-first-workspace"
        }
      }
      
      backend "local" { # state를 보관하는 위치를 지정
        path = "relative/path/to/terraform.tfstate"
      }
    }
    
  • 버전 표현 방법
    • 버전은 Semantic Versioning을 따릅니다. Semantic Versioning은 Major.Minor.Patch 형태로 버전을 관리합니다.
      • Major 버전 : 하위 호환성이 없는 변경 사항
      • Minor 버전 : 하위 호환성이 있는 변경 사항
      • Patch 버전 : 하위 호환성이 있는 버그 수정
    • 또한 버전은 제약 조건을 지정할 수 있습니다.
      • = 또는 연산자 없음 : 정확히 해당 버전
      • != : 지정된 버전을 제외
      • >, >=, <, <= : 각각 해당 버전보다 높은 버전, 높거나 같은 버전, 작은 버전, 작거나 같은 버전 사용
      • ~> : 지정된 버전에서 가장 자리수가 낮은 구성요소만 변경되는것을 허용
        • 예) ~> x.y 인 경우 y 버전에 대해서만, ~> x.y.z 인 경우 z 버전에 대해서만 변경을 허용
Terraform 버전 지정

위의 예제에서 본것 처럼 required_version을 통해 테라폼 버전을 지정할 수 있습니다. 지정된 버전의 조건에 맞을때만 테라폼이 실행됩니다.

  • Terraform 버전 확인
terraform version

# Terraform v1.8.5
# on darwin_arm64
# + provider registry.terraform.io/hashicorp/local v2.5.1
  • main.tf 수정
# main.tf
terraform {
  # 현재 설치된 terraform 버전인 1.8.5 미만으로 지정
  required_version = "< 1.8.5"
}
  • terraform plan 실행
terraform plan

# Error: Unsupported Terraform Core version
# 
#   on main.tf line 3, in terraform:
#    3:   required_version = "< 1.8.5"
# 
# This configuration does not support Terraform version 1.8.5. To proceed, either choose another supported Terraform version or update this version constraint. Version constraints
# are normally set for good reason, so updating the constraint may lead to other errors or unexpected behavior.

현재 설치된 버전보다 이전으로 지정되어서 에러가 나고 종료되는것을 확인 할 수 있습니다.

프로바이더 버전

terraform { required_providers { ... } } 블록을 사용하여 프로바이더 버전을 지정할 수 있습니다.

# main.tf
terraform {
  required_providers {
    aws = {
      source = "hashicorp/aws"
      version = "~> 4.2.0"
    }
    azurerm = {
      source = "hashicorp/azurerm"
      version = ">= 2.99.0"
    }
  }
}

아래의 주소에서 프로바이더들의 목록과 버전을 확인할 수 있습니다.

사이트 접속 후 원하는 프로바이더를 선택하고 우측 상단의 “USE PROVIDER”를 클릭하면 해당 프로바이더의 사용법을 확인할 수 있습니다.

cloud 블록

terraform { cloud { ... } } 블록을 사용하여 Terraform Cloud나 Terraform Enterprise 환경에서 사용하는 설정을 지정할 수 있습니다.

# main.tf
terraform {
  cloud {
    hostname = "app.terraform.io"        
    organization = "my-org"  
    workspaces {              
      name = "my-app-prod"
    }
  }
}
backend 블록

terraform { backend { ... } } 블록을 사용하여 state 파일을 저장하는 위치를 지정할 수 있습니다.

  • Local 파일 시스템을 사용하는 경우
# main.tf
terraform {
  backend "local" {
    path = "relative/path/to/terraform.tfstate"
  }
}
  • AWS S3를 사용하는 경우
# main.tf
terraform {
  backend "s3" {
    bucket = "mybucket"
    key    = "path/to/my/key"
    region = "us-west-2"
  }
}

resource 블록

resource 블록은 클라우드 서비스의 인스턴스, 네트워크, 스토리지 등과 같은 구성요소를 정의합니다.

  • resource는 resource "<프로바이더이름_리소스유형>" "<사용자 지정 리소스명>" { ... } 형태로 정의합니다.
  • local 프로바이더의 file 리소스를 사용하는 예시

    # main.tf
    resource "local_file" "abc" {
      content  = "123"
      filename = "${path.module}/abc.txt"
    }
    
  • AWS 프로바이더의 ec2 리소스를 사용하는 예시

    # main.tf
    resource "aws_instance" "web" {
      ami = "ami-a1b2c3d4"
      instance_type = "t2.micro"  
    }
    
  • 리소스 동작 보조 추가 메타인수를 정의 할 수 있습니다.
    • depends_on : 종속성을 선언하며, 선언된 구성요소와의 생성 시점에 대해 정의
    • count : 선언된 개수에 따라 여러 리소스를 생성
    • for_each : map 또는 set 타입의 데이터 배열의 값을 기준으로 여러 리소스를 생성
    • provider : 동일한 프로바이더가 다수 정의되어 있는 경우 지정
    • lifecycle : 리소스의 수명주기 관리
    • provisioner : 리소스 생성 후 추가 작업 정의
    • timeouts : 프로바이더에서 정의한 일부 리소스 유형에서는 create, update, delete에 대한 허용 시간 정의 가능
resource 의 종속성
  • 테라폼의 종속성은 resource와 module 선언으로 프로비저닝 되는 각 요소의 생성 순서를 정합니다.
  • 종속성의 종류
    • implicit (암시적) 종속성 : 리소스가 다른 리소스를 사용하는 등의 의존성이 있는 경우, 테라폼이 자동으로 종속성을 설정합니다.
    • explicit (명시적) 종속성 : depends_on 메타인수를 사용하여 명시적으로 종속성을 설정할 수 있습니다.
  • 종속성은 terraform graph 명령어를 통해 시각적으로 확인할 수 있습니다.
  • 종속성이 없는 상태 확인

    # main.tf
    resource "local_file" "abc" {
      content  = "123!"
      filename = "${path.module}/abc.txt"
    }
      
    resource "local_file" "def" {
      content  = "456!"
      filename = "${path.module}/def.txt"
    }
    

    위와같은 파일을 만들고 terraform graph > graph-1.dot 을 실행하고 vscode의 graphviz 확장을 설치하면 아래와 같은 그래프를 확인할 수 있습니다.

    local_file.abc local_file.def
  • 암시적 종속성이 있는 상태 확인

    # main.tf
    resource "local_file" "abc" {
      content  = "123!"
      filename = "${path.module}/abc.txt"
    }
      
    resource "local_file" "def" {
      content  = local_file.abc.content + "456!"
      filename = "${path.module}/def.txt"
    }
    
    local_file.abc local_file.def
  • 명시적 종속성이 있는 상태 확인

    # main.tf
    resource "local_file" "abc" {
      depends_on = [  # 명시적 종속성 선언
        local_file.def
      ]
      
      content  = "123!"
      filename = "${path.module}/abc.txt"
    }
      
    resource "local_file" "def" {
      content  = "456!"
      filename = "${path.module}/def.txt"
    }
    
    local_file.abc local_file.def
리소스 속성 참조
  • 리소스 구성에서 참조 가능한 인수와 속성이 있습니다.
    • 인수 (arguments) : 리소스를 생성할 때 사용자가 선언 하는 값
    • 속성 (attributes) : 사용자가 설정할 수는 없지만, 리소스가 생성되면 읽을 수 있는 리소스의 고유 값
    # main.tf
    resource "<프로바이더_유형>" "<이름>" {
      <인수>           = <값>
    }
      
    # 리소스 참조
    <프로바이더_유형>.<이름>.<인수>
    <프로바이더_유형>.<이름>.<속성>
    
  • 리소스가 생성될때 사용자가 입력한 인수를 받아서 실제 리소스가 생성되면, 일부 리소스는 자동으로 기본값이나 추가되는 속성이 부여됩니다.
    • 예) aws_instance 리소스의 경우 ami, instance_type 등의 인수를 받아서 리소스가 생성되면 id, public_ip 등의 속성이 부여됩니다.
리소스의 수명 주기
  • lifecycle은 리소스의 기본 수명 주기를 사용자가 제어할 수 있게 해줍니다.
    • create_before_destroy (bool) : 리소스를 새로 생성하기 전에 기존 리소스를 삭제합니다.
    • prevent_destroy (bool) : 리소스가 삭제되지 않도록 방지합니다.
    • ignore_changes (list) : 특정 인수의 변경을 무시합니다.
    • precondition : 리소스를 생성하기 전에 특정 조건을 검증합니다.
    • postcondition : Plan 과 Apply 이후의 결과를 속성값으로 검증합니다.
  • create_before_destroy
    • 테라폼은 기본 수명 주기가 삭제 후 생성입니다. 즉, 리소스를 새로 생성하기 전에 기존 리소스를 삭제합니다.
    • 의도적으로 생성 후 삭제를 원할때 create_before_destroy = true를 사용합니다.

      # main.tf
      resource "local_file" "abc" {
        content  = "lifecycle - step 1"
        filename = "${path.module}/abc.txt"
        
        lifecycle {
          create_before_destroy = true
        }
      }
      
    • 하지만 이 상태에서 terraform apply를 실행하면 파일이 삭제 됩니다. 이는 abc.txt 라는 파일을 생성 한 다음 삭제하기 때문에, 마지막 동작이 삭제이기 때문에 파일이 없습니다.
  • prevent_destroy
    • 리소스가 삭제되지 않도록 방지합니다. 이 속성은 특정 리소스가 삭제되지 않도록 방지할 때 사용합니다.

      # main.tf
      resource "local_file" "abc" {
        content  = "lifecycle - step 1"
        filename = "${path.module}/abc.txt"
        
        lifecycle {
          prevent_destroy = true
        }
      }
      
    • 이 상태에서 terraform destroy를 실행하면 아래와 같은 에러가 발생합니다.

      terraform destroy
          
      # Error: Instance cannot be destroyed
      #  
      #  on main.tf line 1:
      #   1: resource "local_file" "abc" {
      #  
      # Resource local_file.abc has lifecycle.prevent_destroy set, but the plan calls for this resource to be destroyed. To avoid this error and continue with the plan, either disable
      # lifecycle.prevent_destroy or reduce the scope of the plan using the -target option.    
      
    • 하지만 리소스를 수정한 다음 terraform apply -auto-approve를 실행해도 수정시 동일한 오류가 발생합니다.
    • destroy 했을때는 이해가 가지만 apply 시에도 동일한 오류가 발생하는 이유는 수정 동작이 삭제 후 생성으로 인식되기 때문입니다. 즉 apply 시에도 리소스가 수정되면 삭제 단계가 있기 때문에 prevent_destroy가 적용되어 삭제되지 않습니다.
  • ignore_changes
    • 특정 인수의 변경을 무시합니다. 이 속성은 특정 인수의 변경을 무시하고 리소스를 업데이트할 때 사용합니다.

      # main.tf
      resource "local_file" "abc" {
        content  = "lifecycle - step 1"
        filename = "${path.module}/abc.txt"
        
        lifecycle {
          ignore_changes = [
            content
          ]
        }
      }
      
    • 모든 변경울 무시하고 싶다면 ignore_changes = all을 사용합니다.

  • precondition
    • 리소스를 생성하기 전에 특정 조건을 검증합니다.
    • conditiontrue인지 확인 하고, 조건이 맞지 않는 경우 error_message로 지정된 에러메시지를 표시합니다.

      variable "file_name" {
        default = "step0.txt"
      }
        
      resource "local_file" "abc" {
        content  = "lifecycle - step 6"
        filename = "${path.module}/${var.file_name}"
        
        lifecycle {
          precondition {
            condition     = var.file_name == "step6.txt"
            error_message = "file name is not \"step6.txt\""
          }
        }
      }  
      
  • postcondition
    • 프로비저닝 이후의 결과를 속성값으로 검증합니다.
    • 마찬가지로 condition 인수로 검증하고, 조건이 맞지 않는 경우 error_message로 지정된 에러메시지를 표시합니다.

      resource "local_file" "abc" {
        content  = ""
        filename = "${path.module}/step7.txt"
      
        lifecycle {
          postcondition {
            condition     = self.content != ""
            error_message = "content cannot empty"
          }
        }
      }
      
      output "step7_content" {
        value = local_file.abc.id
      }
      

실습

AWS에 배포하기

  • AWS를 사용하기 위해 awscli 설치

    brew install awscli 
    
  • AWS CLI의 로그인 credentials 설정

    aws configure
    
    # access key, secret key, 기본 region 입력
    

    서울 리전을 사용하기 위해 ap-northeast-2를 입력하였습니다.

  • AWS CLI를 사용하여 최신 ubuntu 22.04 AMI 이미지 얻기

    aws ec2 describe-images --owners 099720109477 \
      --filters "Name=name,Values=ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-*" "Name=state,Values=available" \
      --query 'Images|sort_by(@, &CreationDate)[-1].[ImageId, Name]' --output text
      
    # (결과)
    # ami-0bcdae8006538619a   ubuntu/images/hvm-ssd/ubuntu-jammy-22.04-amd64-server-20240614
    
  • 환경 변수에 AMI ID 저장

    export TF_VAR_ami_id="ami-0bcdae8006538619a"
    

    이렇게 TF_VAR_를 붙여서 환경변수를 셋팅하면 .tf 파일에서 해당 변수를 사용할 수 있습니다.

  • main.tf 파일 생성

    # main.tf
    provider "aws" {
      region = "ap-northeast-2"
    }
      
    # TF_VAR_ami_id 환경변수를 사용하기 위해 선언. var.ami_id 와 같이 사용 가능
    variable "ami_id" { }  
      
    resource "aws_instance" "example" {
      ami                    = "${var.ami_id}"
      instance_type          = "t2.micro"
      vpc_security_group_ids = [aws_security_group.instance.id]
      
      user_data = <<-EOF
                  #!/bin/bash
                  echo "Hello, T101 Study 9090" > index.html
                  nohup busybox httpd -f -p 9090 &
                  EOF
      
      user_data_replace_on_change = true
      
      tags = {
        Name = "Single-WebSrv"
      }
    }
      
    resource "aws_security_group" "instance" {
      name = var.security_group_name
      
      ingress {
        from_port   = 9090
        to_port     = 9090
        protocol    = "tcp"
        cidr_blocks = ["0.0.0.0/0"]
      }
    }
      
    variable "security_group_name" {
      description = "The name of the security group"
      type        = string
      default     = "terraform-example-instance"
    }
      
    output "public_ip" {
      value       = aws_instance.example.public_ip
      description = "The public IP of the Instance"
    } 
    
  • plan 확인 후 apply

    terraform plan
    # plan 확인
    terraform apply -auto-approve
    

    다음과 같이 32초 가량 소요 후 최종적으로 생성된 인스턴스의 public ip를 확인 할 수 있습니다.

    terraform apply 화면

    AWS 콘솔에서도 아래와 같이 잘 생성된 EC2 인스턴스와 보안 그룹이 생성된것을 확인 할 수 있었습니다.

    AWS 콘솔에서 EC2 인스턴스 확인

    물론 접속도 잘 됩니다.

    크롬에서 접속 확인

  • destroy 를 사용하여 리소스 삭제

    terraform destroy 
    

    삭제도 잘 되었습니다. :)

    destroy 확인

도전과제 3 lifecycle의 precondition

  • 도전과제 : lifecycle의 precondition 실습 내용에서 step0.txt ~ step6.txt 총 7개의 파일 이름 중 하나가 일치 시 검증 조건 만족으로 코드 작성
  • 답안 : 정규표현식을 사용하여 아래와 같이 작성하였습니다.

    # main.tf
    variable "file_name" {
      default = "step0.txt"
    }
      
    resource "local_file" "abc" {
      content  = "lifecycle - step 6" # 수정
      filename = "${path.module}/${var.file_name}"
      
      lifecycle {
        precondition {
          condition     = length(regex("^step[0-6]\\.txt$", var.file_name)) > 0
          error_message = "file name is not \"step6.txt\""
        }
      }
    } 
    
  • 실행 결과

    terraform plan -var='file_name=step0.txt'
    terraform plan -var='file_name=step1.txt'
    terraform plan -var='file_name=step2.txt'
    terraform plan -var='file_name=step3.txt'
    terraform plan -var='file_name=step4.txt'
    terraform plan -var='file_name=step5.txt'
    terraform plan -var='file_name=step6.txt'
    
    # 아래와 같이 precondition이 true여서 계획이 성립됨
    #
    # Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
    # -/+ destroy and then create replacement
    #
    # Terraform will perform the following actions:
    # (이하 생략)  
    
    terraform plan -var='file_name=step7.txt'
      
    # step0.txt ~ step6.txt 이외의 파일명인 step7.txt가 입력되어서 아래와 같이 에러가 발생함
    #
    # Planning failed. Terraform encountered an error while generating this plan.
    

마치며

이상과 같이 첫주차에는 테라폼 설치에서 부터 lifecycle 까지 스터디 하였습니다. 생각보다 외워야 하는 부분이 많아서 나중에 다시 확인하기 위해 키워드 위주로 정리하여 보았습니다. HCL을 통해 선언적으로 .tf 파일을 만들면 알아서 계획을 만들고 프로비저닝 해준다니 참 똑똑한 도구인것 같습니다. 앞으로 배우는 내용들도 재밌을것 같아 기대됩니다.