본문 바로가기

study/T101 4기

T101 4기 4주차 두번째

State

테라폼 State 소개 및 실습 - 블로그 Github

 

State의 목적과 의미

상태 파일 확인 실습

mkdir 5.0 && cd 5.0
touch vpc.tf
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

# 상태 파일 확인(VSCODE) : JSON 형식
ls
cat terraform.tfstate | jq
...
"serial": 2,
...

# 아래 정보는 terraform.tfstate 정보를 통해 출력
terraform state list
terraform state show aws_vpc.myvpc

 

확인

provider "aws" {
  region  = "ap-northeast-2"
}

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

  tags = {
    Name = "tf-state"
  }
}

 

 

태그 수정 후 확인

provider "aws" {
  region  = "ap-northeast-2"
}

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

  tags = {
    Name = "tf-state"
  }
}

 

# 배포 : plan 시 tfstate 상태와 코드 내용을 비교해서 검토
terraform plan && terraform apply -auto-approve

# 상태 파일 비교 : 백업 파일 생성됨
ls terraform.tfstate*
terraform.tfstate        terraform.tfstate.backup

diff terraform.tfstate terraform.tfstate.backup
<   "serial": 4,
---
>   "serial": 2,
...

 

한 번 더 수정

provider "aws" {
  region  = "ap-northeast-2"
}

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

  tags = {
    Name = "tf-state-tag-change"
  }
}
# 배포
terraform plan && terraform apply -auto-approve

# 상태 파일 비교(바로 직전 상태 백업)
ls terraform.tfstate*
terraform.tfstate        terraform.tfstate.backup

diff terraform.tfstate terraform.tfstate.backup
<   "serial": 6,
---
>   "serial": 4,
...

 

확인

 

 

삭제

terraform destroy -auto-approve

 

 

이론

 

State 동기화

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

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

 

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

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

 

지원되는 원격 백엔드 : AWS S3, Azure Blob Storage, Google Cloud Storage, Consul, Postgres database, k8s secret 등 - 링크

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

 

 

 

실습을 위해서 5.1 디렉터리를 신규 생성 후 열기 → main.tf 파일 생성 - random_provider password

 

Terraform Registry

 

registry.terraform.io

mkdir 5.1 && cd 5.1
touch main.tf
resource "random_password" "mypw" {
  length           = 16
  special          = true
  override_special = "!#$%"
}

 

확인

# 
terraform init && terraform plan
ls *.tfstate

#
terraform apply -auto-approve
terraform state list
terraform state show random_password.mypw

# (참고) sensitive value 내용은 테라폼 콘솔에서 보일까요? 
echo "random_password.mypw" | terraform console
echo "random_password.mypw.result" | terraform console

# VSCODE에서 확인
ls *.tfstate
cat terraform.tfstate | jq
cat terraform.tfstate | jq | grep result
YLGmKyb3jOuI8sEf

 

  • 테라폼에서는 JSON 형태로 작성된 State를 통해 속성인수를 읽고 확인할 수 있다. 테라폼에서는 typename으로 고유한 리소스분류하며, 해당 리소스의 속성인수를 구성과 비교해 대상 리소스생성, 수정, 삭제한다.
  • State는 테라폼만을 위한 API로 정의할 수도 있다. Plan을 실행하면 암묵적으로 refresh 동작을 수행하면서 리소스 생성의 대상(클라우드 등)과 State를 기준으로 비교하는 과정을 거친다. 이 작업은 프로비저닝 대상의 응답 속도와 기존 작성된 State의 리소스 양에 따라 속도 차이가 발생한다. 대량의 리소스를 관리해야 하는 경우 Plan 명령에서 -refresh=false 플래그를 사용해 State를 기준으로 실행 계획을 생성하고, 이를 실행에 활용해 대상 환경과의 동기화 과정을 생략할 수 있다.
# 실행 계획 생성 시 저장되어 있는 State와 실제 형상을 비교하는 기본 실행
time terraform plan

# 실행 계획 생성 시 실제 형상과 비교하지 않고 실행 계획을 생성하는 -refresh=false 옵션
time terraform plan -refresh=false

 

 

 

 

 

유형 별 실습 + 문제상황 → 복구 import : 테라폼 구성에 추가된 리소스와 State에 따라 어떤 동작이 발생하는지 다음 표로 살펴본다

 

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

  • 실습을 위해서 5.2 디렉터리를 신규 생성 후 열기 → main.tf 파일 생성
mkdir 5.2 && cd 5.2
touch 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 apply -auto-approve
terraform state list
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

 

 

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

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

 

 

유형6 : 실수로 tfstate 파일 삭제 → plan/apply ← 책에는 없는 내용

  • 실행
# 실수로 tfstate 파일 삭제
terraform state list
aws_iam_user.myiamuser1

rm -rf terraform.tfstate*

#
terraform plan
terraform plan -refresh=false

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

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

 

 

유형7 : 실수로 tfstate 파일 삭제 시 → import 로 tfstate 파일 복구 - Docs Tutorials

https://malwareanalysis.tistory.com/633

 

실행

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

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

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

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

 

import 실행

 

 

 

 

Terraform Backend : AWS S3 + DynamoDB

 

https://developer.hashicorp.com/terraform/language/settings/backends/s3

  • [악분님] 실습 따라하기 - Blog
    1. [사전 준비] 리모트 공용 저장소 AWS S3 생성
#
git clone https://github.com/sungwook-practice/t101-study.git example
cd example/state/step3_remote_backend/s3_backend
tree

# VSCODE에서 코드 파일들 확인 : main.tf, variables.tf , terraform.tfvars
## S3 버킷에 버저닝 활성화 <- 권장 옵션 설정

# terraform.tfvars 파일 내용 수정 : 각자 자신의 '닉네임' 추가하여 S3 버킷 이름 작성
bucket_name = "<닉네임>-hello-t1014-remote-backend"
bucket_name = "gasida-hello-t1014-remote-backend"

# 생성
terraform init && terraform apply -auto-approve

# 확인
terraform state list
aws s3 ls

 

 

테라폼 자원 배포 시 ‘리모트 백엔드 저장소’ 설정 사용

# VSCODE에서 provider.tf 코드 확인
cd ../vpc
ls
cat provider.tf

# VSCODE에서 provider.tf 수정
...
  backend "s3" {
    #bucket         = "<닉네임>-hello-t1014-remote-backend"
    bucket         = "gasida-hello-t1014-remote-backend"
    key            = "terraform/state-test/terraform.tfstate"
    region         = "ap-northeast-2"
    #dynamodb_table = "terraform-lock" 주석처리
  }
...

# 테라폼 초기화
terraform init
Initializing the backend...

Successfully configured the backend "s3"! Terraform will automatically
use this backend unless the backend configuration changes.
...

# tfstate 파일 로컬 확인
terraform apply -auto-approve
terraform state list
ls 

# AWS S3 버킷 내에 tfstate 파일 확인
MYBUCKET=gasida-hello-t1014-remote-backend
aws s3 ls s3://$MYBUCKET --recursive --human-readable --summarize

 

 

Locking 을 위한 DynamoDB 활용을 위해 DynamoDB 생성

  • 테라폼에서 DynamoDB 잠금을 사용하기 위해서는 LockID 라는 기본 키가 있는 테이블을 생성해야됨
# VSCODE에서 provider.tf 코드 확인
cd ../dynamodb
ls
cat main.tf

# 생성
terraform init && terraform apply -auto-approve

# 확인
terraform state list
terraform state show aws_dynamodb_table.terraform_state_lock

# DynamoDB 테이블 생성 확인
aws dynamodb list-tables --output text
TABLENAMES	terraform-lock

aws dynamodb describe-table --table-name terraform-lock | jq
aws dynamodb describe-table --table-name terraform-lock --output table

 

2번 테라폼 자원 배포에 백엔드 설정 수정 및 적용

# VSCODE에서 provider.tf 코드 확인
cd ../vpc
cat provider.tf

# VSCODE에서 provider.tf 수정 : dynamodb_table = "terraform-lock" 주석 제거
...
  backend "s3" {
    bucket         = "gasida-hello-t1014-remote-backend"
    key            = "terraform/state-test/terraform.tfstate"
    region         = "ap-northeast-2"
    dynamodb_table = "terraform-lock"
  }
...

# backend설정이 달라졌으므로 terraform init 으로 적용
# Reconfigure a backend, and attempt to migrate any existing state.
terraform init -migrate-state

 

 

VPC tag 수정 후 apply 와서 Locking 확인 : 예전과 다르게 md5 Item은 생성되지 않는듯..

# main.tf 수정 : '2' 추가
resource "aws_vpc" "main" {
  cidr_block = var.vpc_cidr

  tags = {
    Name = "terraform VPC 2"
  }
}

# apply 후 DynamoDB 테이블 확인
terraform apply
...
 Enter a value: <입력하지 않고 대기>

# 아래 LockID 정보 확인 후 apply
# apply 완료 후 다시 DynamoDB 테이블 확인 : item 없음 확인

 

동시에 apply 못한다.

 

 

 

S3 버저닝 정보 확인

# main.tf 수정 : '3' 추가
resource "aws_vpc" "main" {
  cidr_block = var.vpc_cidr

  tags = {
    Name = "terraform VPC 3"
  }
}

# apply 
terraform apply -auto-approve

# S3 버킷에 파일 확인 
aws s3 ls s3://$MYBUCKET --recursive --human-readable --summarize

# 버저닝된 파일 확인
aws s3api list-object-versions --bucket $MYBUCKET | egrep "Key|VersionId|LastModified"
            "Key": "dev/terraform.tfstate",
            "VersionId": "oyo59fIIQ239_tVTY88upFoVgnp630BC",
            "LastModified": "2022-10-23T08:54:04+00:00",
            "Key": "dev/terraform.tfstate",
            "VersionId": "vlOO1wCPEy3mzAOB7W76171u_i3WSG8r",
            "LastModified": "2022-10-23T08:53:04+00:00",
            "Key": "dev/terraform.tfstate",
            "VersionId": "ukF5F_CMKQhoF_jDGftbsMO0eNIGLmDV",
            "LastModified": "2022-10-23T08:51:55+00:00",

 

 

실습 리소스 삭제

# 테라폼 배포 리소스 삭제 : 현재 vpc 디렉터리
terraform destroy -auto-approve

# DynamoDB 삭제
cd ../dynamodb
terraform destroy -auto-approve

# S3 삭제
cd ../s3_backend
terraform destroy -auto-approve

# S3 버킷에 객체 삭제
aws s3 rm s3://$MYBUCKET --recursive

# S3 버킷에 버저닝 객체 삭제 
aws s3api delete-objects \
    --bucket $MYBUCKET \
    --delete "$(aws s3api list-object-versions \
    --bucket "$MYBUCKET" \
    --output=json \
    --query='{Objects: Versions[].{Key:Key,VersionId:VersionId}}')"

# S3 버킷에 삭제마커 삭제
aws s3api delete-objects --bucket $MYBUCKET \
    --delete "$(aws s3api list-object-versions --bucket "$MYBUCKET" \
    --query='{Objects: DeleteMarkers[].{Key:Key,VersionId:VersionId}}')"

# S3 삭제
terraform destroy -auto-approve

 

 

워크스페이스

소개 : State관리하는 논리적인 가상 공간워크스페이스라고 한다 - 링크

 

Workspaces - HCP Terraform | Terraform | HashiCorp Developer

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

developer.hashicorp.com

  • 테라폼 구성 파일은 동일하지만 작업자는 서로 다른 State를 갖는 실제 대상을 프로비저닝할 수 있다.
  • 워크스페이스는 기본 default로 정의된다. 로컬 작업 환경의 워크스페이스 관리를 위한 CLI 명령어로 workspace가 있다.

 

mkdir 5.3 && cd 5.3
touch main.tf
resource "aws_instance" "mysrv1" {
  ami           = "ami-0ea4d4b8dc1e46212"
  instance_type = "t2.micro"
  tags = {
    Name = "t101-study"
  }
}

 

실행

# [분할/터미널1] 모니터링
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

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

#
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 workspace list

# graph 확인
terraform graph > graph.dot

 

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

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

# 서브 디렉터리 확인
tree terraform.tfstate.d
terraform.tfstate.d
└── mywork1

# plan 시 어떤 결과 내용이 출력되나요?
terraform plan

# 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'

# graph 확인
terraform graph > graph.dot


# 새 작업 공간 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

 

 

워크스페이스 생성

 

워크스페이스를 변경한 후

apply 하면 아래 파일이 생성된다

 

다시 워크스페이스 생성

 

tf state파일이 또 다시 생성된다

 

 

 

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

T101 4기 5주차 두번째  (0) 2024.07.07
T101 4기 5주차 첫번째  (0) 2024.07.07
T101 4기 4주차 첫번째  (0) 2024.06.30
T101 4기 3주차 두번째  (0) 2024.06.29
T101 4기 3주차 첫번째  (0) 2024.06.29