본문 바로가기
DevOps

[T1014-이론] 5장 State

by 서어켜엉 2024. 7. 7.
해당 내용은 cloudNet@ 팀의 가시다 님이 진행하는 테라폼 스터디 T101 4기에서 다룬 내용과 "테라폼으로 시작하는 IaC" (한빛미디어) 저서 내용을 정리한 것입니다.

 

1. State의 목적과 의미

  • terraform apply 명령을 실행하면 이전에 생성된 리소스와 비교해 생성, 수정, 삭제 동작이 수행된다.
  • 이 때 테라폼은 State를 사용해 대상 환경에서 어떤 리소스가 테라폼으로 관리되는 리소스인지 판별하고 결과를 기록한다. 
  • State의 역할
    • State에는 테라폼 구성과 실제를 동기화하고 각 리소스에 고유한 아이디(리소스 주소)를 매핑
    • 리소스 종속성과 같은 메타데이터를 저장하고 추적
    • 테라폼 구성으로 프로비저닝된 결과를 캐싱하는 역할을 수행
  • 예제 코드
provider "aws" {
  region  = "ap-northeast-2"
}

resource "aws_vpc" "myvpc" {
  cidr_block       = "10.10.0.0/16"

  tags = {
    Name = "t101-study"
  }
}
terraform init && terraform plan && terraform apply -auto-approve
cat terraform.tfstate | jq | grep "serial"

serial : 1

  • tag 수정 후 다시 아래 명령어 실행하면 serial 번호가 바뀐 것을 확인할 수 있다.
cat terraform.tfstate | jq | grep "serial"

serial : 3

 

이론 내용

출처: https://www.youtube.com/watch?v=E2n3bZrzpKE&t=0s

  • 상태 파일은 배포할 때마다 변경되는 Private API로, 오직 테라폼 내부에서 사용하기 위한 것.
  • 테라폼 상태 파일을 직접 편집하거나 직접 읽는 코드로 작성해서는 안된다.

팀 단위에서 테라폼 운영 시 문제점

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

상태 파일 공유로 버전 관리 시스템 비추천

  1. 수동 오류
    • 테라폼을 실행하기 전에 최신 변경 사항을 가져오거나 실행하고 나서 push 하는 것을 잊기 쉽습니다(?).
    • 팀의 누군가가 이전 버전의 상태 파일로 테라폼을 실행하고, 그 결과 실수로 이전 버전으로 롤백하거나 이전에 배포된 인프라를 복제하는 문제가 발생 할 수 있음.
  2. 잠금
    • 대부분의 버전 관리 시스템은 여러 명의 팀 구성원이 동시에 하나의 상태 파일에 terraform apply 명령을 실행하지 못하게 하는 잠금 기능이 제공되지 않음.
  3. 시크릿 (보안)
    • 테라폼 상태 파일의 모든 데이터는 평문으로 저장됨. 민감 정보가 노출될 위험.

지원되는 원격 백엔드

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

  1. 수동 오류 해결
    • plan/apply 실행 시 마다 해당 백엔드에서 파일을 자동을 로드, apply 후 상태 파일을 백엔드에 자동 저장
  2. 잠금
    • apply 실행 시 테라폼은 자동으로 잠금을 활성화, -lock-timout=<TIME> 로 대기 시간 설정 지정 가능
  3. 시크릿
    • 대부분 원격 백엔드는 기본적으로 데이터를 보내거나 상태 파일을 저장할 때 암호화하는 기능을 지원

 

2. State 동기화

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

 

  • 유형별 실습 + 문제상황 -> 복구 import *
유형 구성 리소스 정의 State 구성 데이터 실제 리소스 기본 예상 동작
1 있음     리소스 생성
2 있음 있음   리소스 생성
3 있음 있음 있음 리소스 생성
4   있음 있음 리소스 삭제
5     있음 동작 없음

 

유형1 : 신규 리소스 정의 -> Apply -> 리소스 생성

locals {
  name = "t1014-smlim"
}

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

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

 

terraform init && terraform apply -auto-approve
aws iam list-users | jq

 

유형 2 : 실제 리소스 수정 제거 -> Apply -> 리소스 생성

aws iam delete-user --user-name t1014-smlim1
aws iam delete-user --user-name t1014-smlim2
aws iam list-users | jq
terraform state list

t1014-smlim1 , t1014-smlim2 역할 삭제

terraform plan
terraform plan -refresh=false
cat terraform.tfstate | jq .serial

terraform plan 실행 시
terraform plan -refresh=false 실행 시

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

# apply 전후 serial 비교
cat terraform.tfstate | jq .serial

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

 

유형 3 : Apply -> apply <- 코드, State, 형상 모두 일치한 경우

#
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

3번 다 변경 사항 없음. Serial 번호도 변동 없음 -> 멱등성 보장

 

유형 4 : 코드에서 일부러 리소스 삭제 -> Apply

locals {
  name = "t1014-smlim"
}

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

1 destroyed 확인

aws iam list-users | jq

t1014-smlim2 역할 삭제된 것을 확인.

유형 5 : 실수로 tfstate 파일 삭제 -> plan / apply

리소스 (iam 역할)가 없다고 판단 ( 실제로는 존재 )
같은 이름의 iam 생성을 시도하다가 에러가 발생

 

유형 5 의 경우 해결 방법

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

# import 도움말 : 빨간색 설명 출력...
terraform import

# ADDR은 리소스주소 , ID는 
# terraform [global options] import [options] ADDR ID
terraform import aws_iam_user.myiamuser1 t1014-smlim1
aws_iam_user.myiamuser1: Importing from ID "t1014-smlim1"...
aws_iam_user.myiamuser1: Import prepared!
  Prepared aws_iam_user for import
aws_iam_user.myiamuser1: Refreshing state... [id=t1014-smlim1]

Import successful!

The resources that were imported are shown above. These resources are now in
your Terraform state and will henceforth be managed by Terraform.

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

terraform.tfstate 파일이 생성된 것을 확인할 수 있음.

 

import 로 state 파일 생성 후 apply를 하면 아무 동작이 일어나지 않음.

 

 

3. 워크스페이스

State를 관리하는 논리적인 가상 공간을 워크스페이스라고 한다. 테라폼 구성파일은 동일하지만 작업자는 서로 다른 State를 갖는 실제 대상을 프로비저닝할 수 있다. 워크스페이스는 기본 default로 정의된다.

 

 

  • 예제 코드
resource "aws_instance" "mysrv1" {
  ami           = "ami-0ea4d4b8dc1e46212"
  instance_type = "t2.micro"
  tags = {
    Name = "t1014-study"
  }
}
terraform workspace list

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

인스턴스가 생성되었다

terraform workspace new smlim1

terraform workspace show

새로운 워크스페이스 생성 및 변경

terraform plan

main.tf 파일을 수정하지 않았음에도 불구하고, 새로운 리소스 추가 동작을 준비한다.

terraform workspace select default

terraform destroy -auto-approve

workspace 를 "default"로 선택하고 destroy 명령을 실행하면 기존에 생성했던 aws_instance 리소스를 삭제한다.

 

terraform workspace delete [워크스페이스 이름]

사용하지 않는 workspace 를 위 명령어로 삭제한다.

 

다수의 워크스페이스를 사용할 때의 장점

  • 하나의 루트 모듈에서 다른 환경을 위한 리소스를 동일한 테라폼 구성으로 프로비저닝하고 관리
  • 기존 프로비저닝된 환경에 영향을 주지 않고 변경 사항 실험 가능
  • 깃의 브랜치 전략처럼 동일한 구성에서 서로 다른 리소스 결과 관리

단점

  • State 가 동일한 저장소에 저장되어 State 접근 권한 관리가 불가능
  • 모든 환경이 동일한 리소스를 요구하지 않을 수 있으므로 테라폼 구성에 분기 처리가 다수 발생 가능
  • 프로비저닝 대상에 대한 인증 요소를 완벽히 분리하기 어려움