공부하면서/Terraform

[T1012] 4주차 - State & 모듈 (State)

omelette master 2023. 7. 27. 23:00
해당 내용은 T1012 스터디에 나온 내용과 '테라폼으로 시작하는 IaC' 책을 기준으로 정리 했습니다

State?

state에는 작업자가 정의한 코드와 실제 반영된 프로비저닝 결과를 저장

state 정보를 가지고 리소스 생성, 수정, 삭제에 대한 동작 판단 작업을 수행함

 

개인적으로 작업시 로컬 환경에 json 형태로 terraform.tfstate 파일이 저장된다

팀단위로 작업시 공동 관리를 위해 원격 저장소에 저장해서 공유 (참고문서: remote)

 

5.1 State의 목적과 의미

 

State | Terraform | HashiCorp Developer

An introduction to state, information that Terraform uses to map resources to a configuration, track metadata, and improve performance.

developer.hashicorp.com

State(상태 파일)는 테라폼을 위한 API로 정의할수 있는데

plan을 실행하면 refresh 를 수행하면서 리소스 대상과 state를 기준으로 비교한다

이 작업은 프로비저닝 대상의 응답속도와 기존 작성된 stste의 양에 따라 속도차이 발생하기에

대량의 리소스를 관리하는 경우 plan 명령에서 -refresh=flase 플래그를 사용하여 state 를 기준으로 동기화 과정을 생략하여 plan을 생성할수 있다.

주의할점

테라폼 state 파일을 직접 편집하거나 직접 코드로 작성해서는 안된다
조작이 필요할 경우 import나 state 명령을 사용

State 역할

state에는 테라폼 구성과 실제를 동기화 하고 각 리소스에 고유한 아이디(리소스 주소)로 맵핑

리소스 종속성과 같은 메타데이터를 저장하고 추적

테라폼 구성으로 프로비저닝 결과를 캐싱하는 역할 수행

더보기
# 실습을 위한 5.1 폴더 생성
mkdir 5.1 && cd 5.1

# random 프로바이더를 사용하여 무작위 password를 생성할 예정
# main.tf 생성
resource "random_password" "mypw" {
  length           = 16
  special          = true
  override_special = "!#$%"
}

# 초기화 및 실행
terraform init && terraform plan
terraform apply -auto-approve

# 확인
terraform state list
terraform state show random_password.mypw

sensitive value로 내용이 출력되지 않음!

terraform console에서도 출력이 되지 않는다

하지만...

terraform.tfstate 조회시 "result"에 값이 출력된다

팀 단위 테라폼 운영 시 발생하는 문제점

  1. 상태 파일을 저장하는 공유 스토리지
    • 각 팀원이 동일한 테라폼 상태 파일 사용을 위해서, 공유 위치에 저장이 필요
  2. 상태 파일 잠금
    • 잠금 기능 없이 두 팀원이 동시에 테라폼 실행 시 여러 테라폼 프로세스가 상태 파일을 동시에 업데이트하여 충돌 가능(race condition)
  3. 상태 파일 격리
    • 테스트 dev 와 검증 stage 과 상용 prodction 각 환경에 대한 격리가 필요

그러면 이런 문제를 방지하기 위해 버전관리를 사용하면 될까?

State 파일 공유를 위해 버전관리 시스템 비추천!

ex) git, svn, ...
  1. 수동 오류
    • 테라폼을 실행하기전 최신 변경사항을 가져오거나 실행후 push 하는것을 잊기 쉽다
      팀의 누군가 최신 사항을 사용하지 않고 반영 해버린다면...?😨
  2. 대부분 잠금기능 지원하지 않음
    • 각자의 로컬환경에서 apply 하는경우 locking되지 않기 때문에 race condition이 발생하지 않음
  3. 민감 정보 노출
    • state 파일의 모든 데이터는 평문으로 저장되어 민감정보가 노출될 위험이 크다

그러면 위의 문제점들을 위해 어떤걸 사용해야 하나? (물론 완벽해 지는건 아님!)

지원되는 원격 백엔드

AWS S3, Azure Blob Storage, Google Cloud Storage, Consul, Postgres database 등
 

Backend Type: local | Terraform | HashiCorp Developer

Terraform can store the state remotely, making it easier to version and work with in a team.

developer.hashicorp.com

지원되는 백엔드들을 볼수 있다

  1. 수동 오류를 해결해줌
    • plan/apply 실행할때마다 해당 백엔드에서 파일을 자동으로 로드하고 apply 후 state 파일을 백엔드에 자동 저장한다
  2. 잠금기능 지원
    • apply 실행시 테라폼은 자동으로 locking 활성화, -lick-timeout=<TIME> 옵션으로 대기시간 설정 가능
  3. 민감정보 암호화 처리
    • 기본적으로 데이터를 보내거나 state파일을 저장할때 암호화하는 기능을 지원한다

 

5.2 State 동기화

테라폼 구성 파일은 기존 state와 구성을 비교해 실행 계획에서 생성,수정,삭제 여부를 결정

 

테라폼 구성과 state 흐름

plen과 apply 중 각 리소스에 발생할수 있는 네가지 사항

기호 의미
+ Create
- Destroy
-/+ (기본값) Replace
+/- (create_before_destroy=true인경우) Replace
~ Updated in-place

 

유형별 실습

테라폼 구성에 추가된 리소스와 state에 따라 어떤 동작이 발생하는지에 대한 표
유형 구성 리소스 정의 state 구성 데이터 실제 리소스 기본 예상 동작
1 있음     리소스 생성
2 있음 있음   리소스 생성
3 있음 있음 있음 동작 없음
4   있음 있음 리소스 삭제
5     있음 동작 없음

 

유형1 (신규 리소스 정의 → Apply ⇒ 리소스 생성)

더보기
# 실습을 위한 5.2 폴더 생성
mkdir 5.2 && cd 5.2

# main.tf 생성
locals {
  name = "mytest"
}

resource "aws_iam_user" "myiamuser1" {
  name = "${local.name}1"
}

resource "aws_iam_user" "myiamuser2" {
  name = "${local.name}2"
}

# 초기화 및 실행
terraform init && terraform apply -auto-approve

# 확인
terraform state list
terraform state show aws_iam_user.myiamuser1

#
ls *.tfstate
cat terraform.tfstate | jq

#
terraform apply -auto-approve
ls *.tfstate

# iam 사용자 리스트 확인
aws iam list-users | jq

예상하던 대로 리소스를 생성했다

유형2 (실제 리소스 수동 제거 → Apply ⇒ 리소스 생성)

더보기
# 실제 리소스 수동 제거
aws iam delete-user --user-name mytest1
aws iam delete-user --user-name mytest2
aws iam list-users | jq

다시 하나밖에 없다

# 아래 명령어 실행 결과 차이는?
terraform plan
terraform plan -refresh=false
cat terraform.tfstate | jq .serial

terraform plan을 진행하니 해당 리소스의 aws iam이 없는것을 확인하고

다시 생성하려고 한다

-refresh=false 옵션을 추가하니 state파일만 바라보고 동기화 하지 않아, 차이점을 못찾고 있다

serial 번호는 2

# 실행
terraform apply -auto-approve
terraform state list
cat terraform.tfstate | jq .serial

# iam 사용자 리스트 확인
aws iam list-users | jq

실제 없는것을 확인하고 다시 iam 2개를 생성

serial 번호는 5로 늘어났다

다시 생성된 IAM

유형3 (Apply → Apply ⇒ 코드, state, 형상 모두 일치한 경우)

더보기
# serial에 변화가 있는지 확인
terraform apply -auto-approve
cat terraform.tfstate | jq .serial
terraform apply -auto-approve
cat terraform.tfstate | jq .serial
terraform apply -auto-approve
cat terraform.tfstate | jq .serial

테라폼 코드의 변화 없이

계속 apply를 해도 동일한 serial을 유지하고 있다

유형4 (코드에서 일부 리소스 삭제 → Apply)

더보기
# main.tf 파일 수정
locals {
  name = "mytest"
}

resource "aws_iam_user" "myiamuser1" {
  name = "${local.name}1"
}
# 실행
terraform apply -auto-approve
# 확인
terraform state list
terraform state show aws_iam_user.myiamuser1
ls *.tfstate
cat terraform.tfstate | jq

# iam 사용자 리스트 확인
aws iam list-users | jq

유형5 (코드와 state는 없고 실제 리소스만 있는경우)

테라폼으로 관리되지 않은 리소스기 때문에 아무런 작업을 할수 없다!

실수로 tfstate 파일 삭제 → plan/apply

더보기

이미 mytest1 IAM user가 있는 상황!

# 🤭🤫실수로 tfstate 파일 삭제
rm -rf terraform.tfstate*

#
terraform plan
terraform plan -refresh=false

state파일이 없으니 테라폼 입장에서는 신규 리소스로 인지하여 create 하려고 함

#
terraform apply -auto-approve
terraform state list
cat terraform.tfstate | jq

# iam 사용자 리스트 확인
aws iam list-users | jq

실행시켜보면 myiamuser1이 이미 있다고 출력된다 (aws 출력)

새로 생성된 tfstate 모습

 

해결방법으로는 import 등의 방법이 있다고 하지만

아직 경험이 없다보니 막막할것 같다😥

5.3 워크스페이스

State를 관리하는 논리적인 가상 공간을 워크스페이스라고 한다
 

Workspaces - Terraform Cloud | Terraform | HashiCorp Developer

Workspaces enable Terraform Cloud to manage collections of infrastructure resources. Learn basics and recommended organization.

developer.hashicorp.com

테라폼 구성 파일은 동일하지만 작업자는 서로 다른 State를 갖는 실제 대상을 프로비저닝할 수 있다.

워크스페이스는 기본 default로 정의된다. 로컬 작업 환경의 워크스페이스 관리를 위한 CLI 명령어로 workspace가 있다.

terraform workspace list
* default

워크스페이스 실습

더보기
# 실습을 위한 5.3 폴더 생성
mkdir 5.3 && cd 5.3

# main.tf 생성
resource "aws_instance" "mysrv1" {
  ami           = "ami-0ea4d4b8dc1e46212"
  instance_type = "t2.micro"
  tags = {
    Name = "t101-week4"
  }
}
# 실행

export AWS_PAGER=""
while true; do aws ec2 describe-instances --query "Reservations[*].Instances[*].{PublicIPAdd:PublicIpAddress,InstanceName:Tags[?Key=='Name']|[0].Value,Status:State.Name}" --filters Name=instance-state-name,Values=running --output text ; echo "------------------------------" ; sleep 1; done
ec2가 뜨는것을 while문으로 출력
terraform init && terraform apply -auto-approve
terraform state list
init & apply
cat terraform.tfstate | jq -r '.resources[0].instances[0].attributes.public_ip'
cat terraform.tfstate | jq -r '.resources[0].instances[0].attributes.private_ip'
# terraform.tfstate에 private 담긴 내용은?
cat terraform.tfstate | jq -r '.resources[0].instances[0].private' | base64 -d | jq
# 워크스페이스 확인
terraform workspace list
# graph 확인
terraform graph > graph.dot

신규 워크스페이스 생성 및 확인

더보기
# 새 작업 공간 workspace 생성 : mywork1
terraform workspace new mywork1
terraform workspace show

# 서브 디렉터리 확인
tree terraform.tfstate.d
terraform.tfstate.d
└── mywork1
이렇게 생겼다
# apply 해보자!
terraform apply -auto-approve

# 워크스페이스 확인
terraform workspace list

#
cat terraform.tfstate | jq -r '.resources[0].instances[0].attributes.public_ip'
cat terraform.tfstate.d/mywork1/terraform.tfstate | jq -r '.resources[0].instances[0].attributes.public_ip'

apply를 진행하니 ec2가 하나더 생성되었다

각자의 state에 담긴 public_ip도 다름을 확인할수 있다

# 새 작업 공간 workspace 생성 : mywork2
terraform workspace new mywork2

# 서브 디렉터리 확인
tree terraform.tfstate.d
...
# plan & apply
terraform plan && terraform apply -auto-approve
cat terraform.tfstate | jq -r '.resources[0].instances[0].attributes.public_ip'
cat terraform.tfstate.d/mywork1/terraform.tfstate | jq -r '.resources[0].instances[0].attributes.public_ip'
cat terraform.tfstate.d/mywork2/terraform.tfstate | jq -r '.resources[0].instances[0].attributes.public_ip'

# workspace 정보 확인
terraform workspace show
terraform workspace list
# 실습 리소스 삭제
terraform workspace select default
terraform destroy -auto-approve
terraform workspace select mywork1
terraform destroy -auto-approve
terraform workspace select mywork2
terraform destroy -auto-approve

워크스페이스의 장점과 단점

  • 장점
    • 하나의 루트 모듈에서 다른 환경을 위한 리소스를 동일한 테라폼 구성으로 프로비저닝 하고 관리 할수 있다
    • 기존 프로비저닝된 환경에 영향을 주지 않고 변경사항 실험 가능
    • git의 브랜치 전략처럼 동일한 구성에서 서로다른 리소스 결과 관리
  • 단점
    • State가 동일한 저장소(로컬 또는 백엔드)에 저장되어 State 접근 권한 관리가 불가능
    • 모든 환경이 동일한 리소스를 요구하지 않을 수 있으므로 테라폼 구성에 분기 처리가 다수 발생 가능
    • 프로비저닝 대상에 대한 인증 요소를 완벽히 분리하기 어려움⇒ 해결하기 위해 루트 모듈을 별도로 구성하는 디렉터리 기반의 레이아웃을 사용할 수 있다 or Terraform Cloud 환경의 워크스페이스를 활용
  • 가장큰 단점
    • 완벽한 격리 불가능
      이를 해결하기 위해 루트모듈을 별도로 구성하는 디렉터리 기반의 레이아웃을 사용 하거나
      Terraform Cloud 환경의 워크스페이스를 활용하는 방법이 있다