brunch

You can make anything
by writing

C.S.Lewis

by Master Seo Jul 03. 2023

32탄-3. 1주 차 - 테라폼-테라폼블럭더-2023

준비물

aws로그인  https://console.aws.amazon.com/

명령서버에서 사용할 pem키 필요

access-key 필요

secret-key 필요



cloudformation으로 명령 서버 1대를 만든다.





테라폼 코드는 여러가지 블록으로 구분이 된다.

테라폼 블록,프로바이더 버전,백엔드 블럭, 리소스 블럭




<1> 테라폼 블록, 테라폼 버전을 관리

<2> 프로바이더 버전 , AWS등 사용하고자 하는 프로바이더 버전을 관리

<3> 백엔드  블럭, 테라폼 상태를 저장하는 위치를 선언한다.

<4> 리소스 블럭,  AWS등 자원에 대해 정의한다.

<5> 수명주기 - create_before_destroy (bool) = 생성후 삭제

<6> prevent_destroy (bool): 삭제 방지

<7> ignore_changes (list): 리소스 요소에 선언된 인수의 변경 사항을 테라폼 실행 시 무시

<8> precondition: 리소스 요소에 선언해 인수의 조건을 검증

<9> postcondition: Plan과 Apply 이후의 결과를 속성 값으로 검증

<100> 참고자료 - 2023 테라폼 자료 - 몰아 보기




<1> 테라폼 블록, 테라폼 버전을 관리한다.


1

테라폼의 버전을 관리하는것이다.

테라폼 버전이나 프로바이더 버전과 같은 값들은 자동으로 설정되지만, 함께 작업할 때는 버전을 명시적으로 선언하고 필요한 조건을 입력하여 실행 오류를 최소화 한다.

코드 생성당시 버전과 같거나 비슷해야 추후 실행시 오류가 적다.


참고 코드


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"

  }

}


// 테라폼

// 프로바이더

// 백엔드 



2

버전 체계

# version = Major.Minor.Patch

version = 1.3.4



테라폼 버전 관리 - 선언 방식의 의미 ?


>= 1.0.0

테라폼 v1.0.0 이상의 모든 버전을 허용한다


~> 1.0.0.

테라폼 v1.0.0을 포함한 v1.0.x 버전을 하용하고 v1.x는 허용하지 않는다


>= 1.0, < 2.0.0

테라폼 v1.0.0 이상 v2.0.0 미만인 버전을 허용한다



3

mkdir 03

cd 03



4

# 현재 버전 정보 확인

terraform version

Terraform v1.5.2


// 1.0 이하로 설정 해보자.  지금 버전은 1.5.2 이다. 


 vi main.tf


terraform {

  required_version = "< 1.0.0"

}


resource "local_file" "abc" {

  content  = "abc!"

  filename = "${path.module}/abc.txt"

}


# 실행 결과는?

terraform init

...



에러.

나는 1.5라  에러남.

[root@myeks2-bastion-EC2 03]# terraform init

Initializing the backend...

│ Error: Unsupported Terraform Core version

│   on main.tf line 3, in terraform:

│    3:   required_version = "< 1.0.0"

│ This configuration does not support Terraform version 1.5.2. 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.




6

수정

1.0 이상


terraform {

  required_version = ">= 1.0.0"

}


resource "local_file" "abc" {

  content  = "abc!"

  filename = "${path.module}/abc.txt"

}



7

# 실행 결과는?

terraform init

성공

[root@myeks2-bastion-EC2 03]# terraform init

Initializing the backend...

Initializing provider plugins...

- Finding latest version of hashicorp/local...

- Installing hashicorp/local v2.4.0...

- Installed hashicorp/local v2.4.0 (signed by HashiCorp)

Terraform has created a lock file .terraform.lock.hcl to record the provider

selections it made above. Include this file in your version control repository

so that Terraform can guarantee to make the same selections by default when

you run "terraform init" in the future.

Terraform has been successfully initialized!






<2> 프로바이더 버전 , AWS등 사용하고자 하는 프로바이더 버전을 관리



1

프로바이더 버전 보기 

https://registry.terraform.io/browse/providers


사용하고자 하는 프로바이더 클릭   예)  AWS 

오른쪽위 USE Provider 클릭하여  설정법도 볼수 있다.



2

LOCAL PROVIDER 버전 확인하자.

2.4.0

https://registry.terraform.io/providers/hashicorp/local/latest



프로바이더 버전을 100으로 지정해 보자.

에러 난다.



terraform {

  required_version = ">= 1.0.0"

  required_providers {

    local = {

      source  = "hashicorp/local"

      version = ">=100.0.0"

    }

  }

}


resource "local_file" "abc" {

  content  = "123!"

  filename = "${path.module}/abc.txt"

}



# 실행 결과는?

terraform init -upgrade

에러

Initializing the backend...

Initializing provider plugins...

- Finding hashicorp/local versions matching ">= 100.0.0"...

│ Error: Failed to query available provider packages

│ Could not retrieve the list of available versions for provider hashicorp/local: no available releases match the given

│ constraints >= 100.0.0




3

2.0 이상으로 변경



terraform {

  required_version = ">= 1.0.0"

  required_providers {

    local = {

      source  = "hashicorp/local"

      version = ">= 2.0.0"

    }

  }

}


resource "local_file" "abc" {

  content  = "123!"

  filename = "${path.module}/abc.txt"

}


# 실행 결과는?

terraform init -upgrade



잘됨.







<3> 백엔드  블럭, 테라폼 상태를 저장하는 위치를 선언한다.


1

백엔드 블록의 구성은 테라폼 실행 시 저장되는 State(상태 파일)의 저장 위치를 선언한다.

하나의 백엔드만 허용한다는 점이다.

테라폼은 State의 데이터를 사용해 코드로 관리된 리소스를 탐색하고 추적한다.



2

기본적으로 활성화되는 백엔드는 local이다.

상태를 작업자의 로컬 환경에 저장하고 관리하는 방식이다.



3

resource "local_file" "abc" {

  content  = "123456!"

  filename = "${path.module}/abc.txt"

}



# 터미널1

terraform apply

...

Enter a value: 대기


# 터미널2

terraform apply

...

ls -a


# 터미널1 취소 후 apply

terraform apply -auto-approve



ls terraform.tfstate*

terraform.tfstate        terraform.tfstate.backup


# 리소스 확인

terraform state list


# State 파일 정보 확인

cat terraform.tfstate



4

백엔드가 설정되면 다시 init 명령을 수행해 State의 위치를 재설정해야 한다


terraform {

  backend "local" {

    path = "state/terraform.tfstate"

  }

}

resource "local_file" "abc" {

  content  = "123456!"

  filename = "${path.module}/abc.txt"

}




5

# init 시 백엔드 변경에 따른 마이그레이션 안내

terraform init

...

Enter a value: yes

...

#

ls terraform.tfstate*

tree state

cat state/terraform.tfstate | jq

cat state/terraform.tfstate | jq -r .serial

terraform apply -auto-approve



6

terraform {

  backend "local" {

    path = "state/terraform.tfstate"

  }

}

resource "local_file" "abc" {

  content  = "123456789!"

  filename = "${path.module}/abc.txt"

}




7


#

terraform plan

terraform apply -auto-approve


#

cat abc.txt

ls terraform.tfstate*

tree state

cat state/terraform.tfstate | jq

cat state/terraform.tfstate | jq -r .serial



# 이전 사용 state 파일 삭제 후 확인

rm -rf terraform.tfstate*

ls -al


terraform plan

terraform apply -auto-approve

cat abc.txt





<4> 리소스 블럭,  AWS등 자원에 대해 정의한다.


1

cd

mkdir 03re

cd 03re



2

resource 블럭은 resource 로 시작한다.


resource "<리소스 유형>" "<이름>" {

  <인수> = <값>

}


resource "local_file" "abc" {

  content  = "123"

  filename = "${path.module}/abc.txt"

}



3

vi main.tf


resource "local_file" "abc" {

  content  = "123"

  filename = "${path.module}/abc.txt"

}


resource "aws_instance" "web" {

  ami = "ami-a1b2c3d4"

  instance_type = "t2.micro"  

}


// 리소스 유형은 local 이다.  local provider 로 file 유형이다.


//  aws언더바로 시작 = aws의  인스턴스이다.

//  web 은 이름이다. 이름은 테라폼이 구분하는 이름이다.  동일한 이름이 있으며 충돌 난다.

//  { 중괄호 }  는  인수의 값 내용이다.




4

# init 시 프로바이더 선언 없이도 리소스 추가로 자동 인식된 프로바이더 요구사항과 초기화


terraform init


tree .terraform


// 프로바이더 지정을 안하더라도 프로바이더가 다운로도 되었다.

// 코드를 보면 리소스 다음에 프로바이더가 나온다.  그래서  관련 라이블러리가 다운로드 된다.

resource "aws_instance" "web" {




5

종속성 확인해보자 !!!


로컬 풇로바이더로 다 바꿔보자.


resource "local_file" "abc" {

  content  = "123!"

  filename = "${path.module}/abc.txt"

}


resource "local_file" "def" {

  content  = "456!"

  filename = "${path.module}/def.txt"

}


// 동일한 리소스 유형이지만 이름을 구분한다.   abc , def 이름으로  구분한다.




6

(선택)

VS Code 사용시에는 확장 프로그램 graphviz 설치하자.

그래프 형태로 연관 종속성을 보여 주는 플러그인이다.



7

배포

terraform apply -auto-approve



8

확인

2개의 파일이 만들어진다.


ls *.txt

abc.txt  def.txt



// 로컬_파일  ,  점 이름으로 생성이 된다.


terraform state list

local_file.abc

local_file.def



9

(선택)

VS Code 사용시


terraform graph

파일로 만들어보자.

terraform graph > graph-2.dot

파일을 클릭하고  VS Code 오른쪽위 DOT 클릭하면 그래프가 나온다.


지금은 2개 리소스가 병렬로 만들어진다!



10

제거

terraform destroy -auto-approve



11

리소스 참조값을 설정해 두 개의 리소스 간 암시적 종속성 부여 해보자!


resource "local_file" "abc" {

  content  = "123!"

  filename = "${path.module}/abc.txt"

}


resource "local_file" "def" {

  content  = local_file.abc.content

  filename = "${path.module}/def.txt"

}



terraform apply -auto-approve



생성 순서가 달라진다.

순차적으로 생성된다.

abc 만들고 def가 만들어진다!


abc에 의존된게 def 이다.

def만들때 abc 참고한다.




확인

ls *.txt

terraform state list


[root@myeks2-bastion-EC2 03-re]# ls *.txt

abc.txt  def.txt


[root@myeks2-bastion-EC2 03-re]# terraform state list

local_file.abc

local_file.def



terraform destroy -auto-approve



12

종속성 관련 코드가 있다!  depends_on


리소스 자체를 depends_on  지정 가능하다.

def는  abc만들고 만들어라.


resource "local_file" "abc" {

  content  = "123!"

  filename = "${path.module}/abc.txt"

}


resource "local_file" "def" {

  depends_on = [

    local_file.abc

  ]


  content  = "456!"

  filename = "${path.module}/def.txt"

}



13

terraform apply -auto-approve



[root@myeks2-bastion-EC2 03re]# more abc.txt

123!


[root@myeks2-bastion-EC2 03re]# more def.txt

456!



14

리소스 속성 참고 ?




 

<5> 수명주기 - create_before_destroy (bool) = 생성후 삭제



1

테라폼의 기본 수명주기는  삭제후 새로 생성한다. 

리소스 수정 시 신규 리소스를 우선 생성하고, 기존 리소스를 삭제하도록 하자.



기본 사례와 옵션을 잘못준 사례를 2가지를 알아보자.

파일을 생성후 삭제하면, 날아가 버리는 잘못된 예제도 알아보자.



2

mkdir life

cd life



3

기본 사례  false 일때.


resource "local_file" "abc" {

  content  = "lifecycle - step 1"

  filename = "${path.module}/abc.txt"


  lifecycle {

    create_before_destroy = false

  }

}



4

terraform init && terraform plan && terraform apply -auto-approve

terraform state list



# 파일 내용 확인

cat abc.txt

lifecycle - step 1


// 기본값은 false  이다




5

컨텐트 내용 수정해보자.


resource "local_file" "abc" {

  content  = "lifecycle - step 1111111111111111"

  filename = "${path.module}/abc.txt"


  lifecycle {

    create_before_destroy = false

  }

}




6

#

terraform plan && terraform apply -auto-approve

...

-/+ destroy and then create replacement


Terraform will perform the following actions:


  # local_file.abc must be replaced

-/+ resource "local_file" "abc" {

      ~ content              = "lifecycle - step 1" -> "lifecycle - step 1111111111111111" # forces replacement

...


replace 된다.

제거후 새로 만든다.



# 파일 내용 확인

cat abc.txt

lifecycle - step 11111111111111



7

내용 수정 저장


resource "local_file" "abc" {

  content  = "lifecycle - step 2"

  filename = "${path.module}/abc.txt"


  lifecycle {

    create_before_destroy = true

  }

}


// 컨텐츠 내용을 true로 변경하고 생성해보자.

파일을 만들고 삭제한다.

파일이 삭제 되어 버린다!!!

만든거도 삭제된다. (장애 상태) -  인스턴스 만들고 삭제 - -


terraform plan && terraform apply -auto-approve


terraform destroy -auto-approve



8

다시 apply 하면 만들어진다.





<6> prevent_destroy (bool): 삭제 방지


 해당 리소스를 삭제 Destroy 하려 할 때 명시적으로 거부


1

resource "local_file" "abc" {

  content  = "lifecycle - step 3"

  filename = "${path.module}/abc.txt"


  lifecycle {

    prevent_destroy = true

  }

}



2

terraform plan

terraform apply -auto-approve

...

│ Error: Instance cannot be destroyed

│ 

│   on main.tf line 1:

│    1: resource "local_file" "abc" {

...


// 삭제 방지를 true로 해놓는다.

// 실행하면 에러가 난다.  테라폼은 삭제후 다시 만들어야 하는데 삭제가 안되므로 에러가 난다.



코드를 수정하고 다시 실행하자.

terraform apply -auto-approve



3

cat abc.txt

lifecycle - step 3





<7> ignore_changes (list): 리소스 요소에 선언된 인수의 변경 사항을 테라폼 실행 시 무시



ignore_changes 리소스 요소의 인수를 지정해 수정 계획에 변경 사항이 반영되지 않도록 하는 것


content 내용을 수정하자.  4로 


1

resource "local_file" "abc" {

  content  = "lifecycle - step 4"

  filename = "${path.module}/abc.txt"


  lifecycle {

    ignore_changes = []

  }

}



2

terraform apply -auto-approve


cat abc.txt

lifecycle - step 4




3


content   내용을 다시 수정하자.  

5로 수정하자.


resource "local_file" "abc" {

  content  = "lifecycle - step 5"

  filename = "${path.module}/abc.txt"


  lifecycle {

    ignore_changes = [

      content

    ]

  }

}



// content 는 유지해줘 




4

#

terraform apply -auto-approve

cat abc.txt

lifecycle - step 4


// 변경되지 않음!!!





<8> precondition: 리소스 요소에 선언해 인수의 조건을 검증



리소스 생성 이전에  검사하는것이다.

리소스 생성 이전에 입력된 인수 값을 검증하는 데 사용해 프로비저닝 이전에 미리 약속된 값 이외의 값 또는 필수로 명시해야 하는 인수 값을 검증



1


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\""

    }

  }

}



// 컨디션 파일이름이  step6.txt 이여야 한다.

// 그런데, 디폴트라 step0.txt 이다. 

// 에러 메시지를 뿌려준다. 




2

terraform plan


local_file.abc: Refreshing state... [id=63cd1a0c571d59f5b4337364e612786cc63c1bb8]

Planning failed. Terraform encountered an error while generating this plan.

│ Error: Resource precondition failed

│   on main.tf line 22, in resource "local_file" "abc":

│   22:       condition     = var.file_name == "step6.txt"

│     ├────────────────

│     │ var.file_name is "step0.txt"

│ file name is not "step6.txt"



3

클라우드 인프라의 VM을 생성할 때 내부적으로 검증된 이미지 아이디를 사용하는지 등과 같은 구성을 미리 확인하고 사전에 잘못된 프로비저닝을 실행할 수 없도록 구성할 수 있다.





<9> postcondition: Plan과 Apply 이후의 결과를 속성 값으로 검증



프로비저닝 변경 이후 결과를 검증함과 동시에 의존성을 갖는 다른 구성의 변경을 맞는 효과



1


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

}


// 변경 이후의 결과

// 



2

# postcondition 조건에 맞지 않아 에러 발생


terraform apply -auto-approve

terraform state list

cat step7.txt




3

컨텐츠를 채운다.

적용한다.

정상 처리된다.


resource "local_file" "abc" {

  content  = "step7 file ok"

  filename = "${path.module}/step7.txt"


  lifecycle {

    postcondition {

      condition     = self.content != ""

      error_message = "content cannot empty"

    }

  }

}


output "step7_content" {

  value = local_file.abc.id

}





4

terraform apply -auto-approve

terraform state list

cat step7.txt









다음 과정은

https://brunch.co.kr/@topasvga/3360





<100> 참고자료 - 2023 테라폼 자료 - 몰아 보기


https://brunch.co.kr/@topasvga/3347

다음은 주말 CloudNet 테라폼 스터디 내용 참고하여  정리한 부분입니다.

https://gasidaseo.notion.site/gasidaseo/CloudNet-Blog-c9dfa44a27ff431dafdd2edacc8a1863

감사합니다.

브런치는 최신 브라우저에 최적화 되어있습니다. IE chrome safari