본문 바로가기

study/T101 4기

T101 4기 1주차 세번째

백엔드 블록

  • 백엔드 블록의 구성은 테라폼 실행 시 저장되는 **State(상태 파일)**의 저장 위치를 선언한다.
  • 주의할 점은 하나의 백엔드만 허용한다는 점이다.
  • 테라폼은 State의 데이터를 사용해 코드로 관리된 리소스를 탐색하고 추적한다.
  • 작업자 간의 협업을 고려한다면 테라폼으로 생성한 리소스의 상태 저장 파일을 공유할 수 있는 외부 백엔드 저장소가 필요하다.
  • 그리고 State에는 외부로 노출되면 안 되는 패스워드 또는 인증서 정보 같은 민감한 데이터들이 포함될 수 있으므로 State의 접근 제어가 필요하다.

State 잠금 동작

  • 기본적으로 활성화되는 백엔드local이다.
  • 상태를 작업자의 로컬 환경저장하고 관리하는 방식이다.
  • 이 밖의 다른 백엔드 구성은 동시에 여러 작업자가 접근해 사용할 수 있도록 공유 스토리지 같은 개념을 갖는다.
  • 공유되는 백엔드에 State가 관리되면 테라폼이 실행되는 동안 .terraform.tfstate.lock.info 파일이 생성되면서 해당 State를 동시에 사용하지 못하도록 잠금 처리를 한다.
  • 파일 생성을 확인하고 싶다면 terraform apply를 실행하고 생성되는 잠금 파일을 확인해보자. 잠금 파일 내의 정보는 다음과 같다.
ID:        30773305-a78d-49f1-8f3f-5604d742b66f
Operation: OperationTypeApply                      # 어떤 동작으로 인해 해당 잠금 파일이 생성되었는지 명기
Info:
Who:       gasida@seojonghoui-MacBookPro.local     # 작업자 정보
Version:   1.5.1                                   # 실행한 테라폼 버전
Created:   2023-06-28 12:23:59.113608 +0000 UTC
Path:      state/terraform.tfstate                 # 잠긴 state 파일의 위치

 

  • 잠금 파일이 테라폼 실행에 어떤 영향을 주는지 확인해보자.
  • 코드 파일 수정 : content 내용을 수정, 문서 서식
resource "local_file" "abc" {
  content  = "123456!"
  filename = "${path.module}/abc.txt"
}

 

 

# 터미널1
terraform apply
...
Enter a value: 대기

# 터미널2
terraform apply
...
ls -a

 

파일 하나가 생성되면서

아래 처럼 오류가 발생한다.

 

 

백엔드 설정 변경

  • 현재 State 파일 정보 확인
ls terraform.tfstate*
terraform.tfstate        terraform.tfstate.backup

# 리소스 확인
terraform state list

# State 파일 정보 확인
cat terraform.tfstate
  • 백엔드가 설정되면 다시 init 명령을 수행해 State의 위치를 재설정해야 한다.
  • 백엔드 블록에 local을 정의해 terraform init을 수행해본다.
# 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

 

코드수정

terraform {
  backend "local" {
    path = "state/terraform.tfstate"
  }
}

resource "local_file" "abc" {
  content  = "123456789!"
  filename = "${path.module}/abc.txt"
}

 

apply

#
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          # 예시)현재: 10
cat state/terraform.tfstate.backup | jq -r .serial   # 예시)백업: 7

# 이전 사용 state 파일 삭제 후 확인
rm -rf terraform.tfstate*
ls -al

# 
terraform plan
terraform apply -auto-approve
cat abc.txt

 

확인

 

 

- 리소스

  • 리소스 구성 resource
    • 실습을 위해서 03.end 디렉터리를 신규 생성 후 열기 → main.tf 파일 생성
cd ..
rm -rf 03.start
mkdir 03.end
cd 03.end
touch main.tf

 

  • 리소스 블록은 resource로 시작한다. 이후 리소스 블록이 생성할 ‘리소스 유형’을 정의한다.
  • 리소스 선언 : 리소스 유형(프로바이더이름_제공리소스유형), 동일한 유형에 대한 식별자 역할로 고유한 이름, 구성 인수들이 이름 뒤에 중괄호 내에 선언됨
resource "<리소스 유형>" "<이름>" {
  <인수> = <값>
}

resource "local_file" "abc" {
  content  = "123"
  filename = "${path.module}/abc.txt"
}

 

 

리소스에서 사용되는 유형들은 프로바이더에 종속성을 갖는다. 특정 프로바이더의 유형만 추가해도 init 수행 시 해당 프로바이더를 설치한다.

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

resource "aws_instance" "web" {
  ami = "ami-a1b2c3d4"
  instance_type = "t2.micro"  
}

 

init

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

 

확인

 

 

  • 리소스 동작 보조 추가 메타인수를 정의 할 수 있다 → 뒤에서 자세히 설명
    • depends_on : 종속성을 선언하며, 선언된 구성요소와의 생성 시점에 대해 정의
    • count : 선언된 개수에 따라 여러 리소스를 생성
    • for_each : map 또는 set 타입의 데이터 배열의 값을 기준으로 여러 리소스를 생성
    • provider : 동일한 프로바이더가 다수 정의되어 있는 경우 지정
    • lifecycle : 리소스의 수명주기 관리
    • provisioner : 리소스 생성 후 추가 작업 정의
    • timeouts : 프로바이더에서 정의한 일부 리소스 유형에서는 create, update, delete에 대한 허용 시간 정의 가능

 

 

- 종속성

  • 테라폼 종속성은 resource, module 선언으로 프로비저인되는 각 요소의 생성 순서를 구분짓는다.
  • 기본적으로 다른 리소스에서 값을 참조해 불러올 경우 생성 선후 관계에 따라 작업자가 의도하지는 않았지만 자동으로 연관 관계가 정의되는 암시적 종속성을 갖게 되고, 강제로 리소스 간 명시적 종속성을 부여할 경우에는 메타인수인 depends_on을 활용한다. [참고: Docs]
  • 코드 파일 수정
resource "local_file" "abc" {
  content  = "123!"
  filename = "${path.module}/abc.txt"
}

resource "local_file" "def" {
  content  = "456!"
  filename = "${path.module}/def.txt"
}

 

  • apply 실행 : 서로 선후 관계가 없는 동일한 수준으로, 병렬(동시) 실행
  • VS Code 확장 graphviz 설치
# 모니터링 : 신규 터미널
cd 03.end
watch -d ls -l

# apply
terraform apply -auto-approve
...
Plan: 2 to add, 0 to change, 0 to destroy.
local_file.def: Creating...
local_file.abc: Creating...
local_file.abc: Creation complete after 0s [id=5f30576af23a25b7f44fa7f5fdf70325ee389155]
local_file.def: Creation complete after 0s [id=b9fbde4d33ab9c450a7ce303fb4788c9d2db9aed]

# 리소스 확인
ls *.txt
terraform state list
local_file.abc
local_file.def

# graph 확인 > graph-1.dot 파일 선택 후 오른쪽 상단 DOT 클릭
terraform graph
terraform graph > graph-1.dot

# 모든 리소스 제거
terraform destroy -auto-approve
ls *.txt
terraform state list

 

병렬로 실행된 것을 볼 수 있습니다. (의존 관계가 없음)

 

 

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

resource "local_file" "abc" {
  content  = "123!"
  filename = "${path.module}/abc.txt"
}

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

 

종속성 확인

 

 

 

리소스의 속성을 주입하지 않아도 두 리소스 간에 종속성이 필요한 경우에, depends_on 선언으로 적용 가능

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"
}
#
terraform destroy -auto-approve
terraform apply -auto-approve
...

# graph 확인 > graph-3.dot 파일 선택 후 오른쪽 상단 DOT 클릭
terraform graph
terraform graph > graph-3.dot

 

결과는 위에 그림과 같습니다.

 

 

리소스 속성 참조

  • 리소스 구성에서 참조 가능한 값은 인수속성이다
    • 인수 : 리소스 생성 시 사용자가 선언하는 값
    • 속성 : 사용자가 설정하는 것은 불가능하지만 리소스 생성 이후 획득 가능한 리소스 고유 값
  • 리소스 인수의 선언과 참조 가능한 인수 및 속성 패턴
# Terraform Code
resource "<리소스 유형>" "<이름>" {
  <인수> = <값>
}

# 리소스 참조
<리소스 유형>.<이름>.<인수>
<리소스 유형>.<이름>.<속성>

 

 

아래 코드는 쿠버네티스 프로바이더의 Namespace 리소스를 생성하고 이후 Secret을 해당 Namespace에 생성하는 종속성을 리소스 인수 값 값으로 생성하는 예이다. Namespace의 이름만 변경해도, 해당 Namespace를 참조하는 모든 리소스가 업데이트되어 영향을 받는다.

resource "kubernetes_namespace" "example" {
  metadata {
    annotations = {
      name = "example-annotation"
    }
    name = "terraform-example-namespace"
  }
}

resource "kubernetes_secret" "example" {
  metadata {
    namespace = kubernetes_namespace.example.metadata.0.name # namespace 리소스 인수 참조
    name      = "terraform-example"
  }
  data = {
    password = "P4ssw0rd"
  }
}
  • 리소스가 생성될 때, 사용자가 입력한 ‘인수’를 받아 실제 리소스가 생성되면 일부 리소스는 자동으로 기본값이나 추가되는 ‘속성’이 부여된다.
  • 각 리소스마다 문서를 확인해보면 인수Arguments로 표현되어 있으며, 리소스 생성 후 추가되는 속성 값으로 Attributes에 안내되어 있다 - 링크
  • 리소스 속성을 참조하는 다른 리소스 또는 구성요소에서는 생성 후의 속성 값들도 인수로 가져올 수 있다.

 

 

수명주기

 

create_before_destroy (bool): 리소스 수정 시 신규 리소스를 우선 생성하고 기존 리소스를 삭제

  • 예를 들어 image 변경 되는 경우 해당 VM 리소스를 삭제하고 다시 생성
  • 테라폼의 기본 수명주기삭제 후 생성이기 때문에 작업자가 의도적으로 수정된 리소스를 먼저 생성하기를 원할 수 있다.
  • 이 경우 create_before_destroytrue로 선언되면 의도한 생성을 실행한 후 삭제로 동작한다.
  • 하지만 생성되는 리소스가 기존 리소스로 인해 생성이 실패되거나 삭제 시 함께 삭제될 수 있으니 주의해야 한다.
    • 잘못된 사례 1 : 리소스의 명시적 구분이 사용자가 지정한 특정 이름이나 ID인 경우 기존 리소스에 할당되어 있기 때문에 생성 실패
    • 잘못된 사례 2 : 생성 후 삭제 시 동일한 리소스에 대한 삭제 명령이 수행되어 리소스가 모두 삭제

 

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

resource "local_file" "abc" {
  content  = "lifecycle - step 3"
  filename = "${path.module}/abc.txt"

  lifecycle {
    prevent_destroy = true
  }
}

 

apply 시 에러 발생

 

 

수정수 apply

resource "local_file" "abc" {
  content  = "lifecycle - step 3"
  filename = "${path.module}/abc.txt"
}

 

 

 

 

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

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

resource "local_file" "abc" {
  content  = "lifecycle - step 4"
  filename = "${path.module}/abc.txt"

  lifecycle {
    ignore_changes = []
  }
}

 

수정 후 다시 apply

resource "local_file" "abc" {
  content  = "lifecycle - step 5"
  filename = "${path.module}/abc.txt"

  lifecycle {
    ignore_changes = [
      content
    ]
  }
}

 

ignore를 적용하면 파일이 수정 되지 않습니다.

 

 

 

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

  • 리소스 생성 이전에 입력된 인수 값을 검증하는 데 사용해 프로비저닝 이전에 미리 약속된 값 이외의 값 또는 필수로 명시해야 하는 인수 값을 검증할 수 있다.
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\""
    }
  }
}

 

실행하면 되지 않습니다.

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

 

파일 수정 후 apply

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
}

 

그래도 실행이 안된다 -> postcondition 조건에 맞지 않아 에러 발생

 

다시 수정

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
}

 

확인

  • 종속성을 갖는 여러 리소스를 구성하는 경우, 리소스의 데이터가 다른 리소스 생성 시 활용될 때 원하는 속성이 정의되어야 하는 경우를 확인할 수 있다.
  • 특히, 프로비저닝 이후에 생성되는 속성 값이 있으므로 영향을 받는 다른 리소스가 생성되기 전에 예상되지 않은 프로비저닝 작업을 방지할 수 있다.

 

 

'study > T101 4기' 카테고리의 다른 글

T101 4기 3주차 첫번째  (0) 2024.06.29
T101 4기 2주차 두번째  (0) 2024.06.22
T101 4기 2주차 첫번째  (0) 2024.06.22
T101 4기 1주차 두번째  (0) 2024.06.15
T101 4기 1주차 첫번째  (0) 2024.06.15