Programming/IaC

[IaC] Terraform state -상태파일격리

Hayley Shim 2023. 10. 28. 17:49

안녕하세요. CloudNet@ Terraform Study를 진행하며 해당 내용을 이해하고 공유하기 위해 작성한 글입니다. 도서 ‘Terraform: Up & Running(By Yevgeniy Brikman)’ 의 내용 및 스터디 시간 동안 언급된 주요 내용 위주로 간단히 정리했습니다.

상태 파일 격리 필요성

  • 원문 참고  all my environments shared a state file, so when something bad happened to that state file they all got equally fucked.
  • 동일한 상태파일 사용 시, 해당 파일이 모든 환경에 영향을 미칠 수 있기 때문에 환경별 상태 파일 격리가 필요합니다.
  • 즉, 테라폼을 처음 사용하기 시작하면 모든 인프라를 단 하나의 테라폼 파일, 또는 같은 폴더에 들어있는 단 하나의 테라폼 파일 세트로 정의하게 되는데 이는 모든 테라폼 상태가 하나의 파일에 저장되므로 실수로 전체를 날려버릴 수 있습니다.
  • 상태 파일을 격리하는 방법은 2가지가 있습니다
  1. 작업 공간(workspace)를 통한 격리 : 동일한 구성에서 빠르고 격리된 테스트 환경에 유용
  2. 파일 레이아웃을 이용한 격리: 보다 강력하게 분리해야 하는 운영 환경에 적합

작업 공간(workspace)를 통한 격리

  • 테라폼은 기본 ‘default’ 작업 공간을 사용합니다. 새 작업 공간을 만들거나 전환하려면 terraform workspace 명령을 사용합니다.
 
# 배포
$ terraform init -force-copy && terraform plan && terraform apply -auto-approve
$ terraform state list# 워크스페이스 확인
$ terraform workspace show
default# 새 작업 공간 workspace 생성 : mywork1
terraform workspace new mywork1# plan 시 어떤 결과 내용이 출력되나요?
terraform plan# apply
terraform apply -auto-approve# 새 작업 공간 workspace 생성 : mywork2
terraform workspace new mywork2# plan & apply
terraform plan && terraform apply -auto-approve# workspace 정보 확인
terraform workspace show
mywork2terraform workspace list
  default
  mywork1
* mywork2# 작업 공간 전환
terraform workspace select mywork1
Switched to workspace "mywork1".terraform workspace show
mywork1# S3 버킷의 정보를 확인해보자 : "env: 폴더" 아래 각 작업 공간이름의 아래 tfstate 파일이 존재
  • 각 작업 공간(workspace) 내에서 테라폼은 backend 구성에서 지정한 key를 사용합니다.
  • 작업 공간(workspace)마다 별도의 상태 파일이 있으므로 example1과 example2 작업 공간을 사용하면 테라폼은 example1/workspaces-example/terraform.tfstate과 example2/workspaces-example/terraform.tfstate를 찾아야합니다.
  • 즉, 다른 작업 공간(workspace)으로 전환하는 것은 상태 파일이 저장된 경로를 변경하는 것과 같습니다.
  • 작업 공간(workspace)을 나누는 기능은 코드 리팩터링(code refactoring) 을 시도하는 것 같이 이미 배포되어 있는 인프라에 영향을 주지 않고 테라폼 모듈을 테스트 할 때 유용합니다.
  • terraform workspace new 명령어로 새로운 작업 공간을 생성하여 완전히 동일한 인프라의 복사본을 배포할 수 있지만 상태 정보는 별도의 파일에 저장합니다.
  • 3항 연산자를 사용한 아래 1개의 코드 파일로 작업 공간 별로 다른 설정이 적용될 있습니다.
 

작업 공간 단점

  1. 모든 작업 공간의 상태 파일은 동일한 백엔드(예. 동일한 S3 버킷)에 저장됩니다. 즉, 모든 작업 공간이 동일한 인증과 접근 통제를 사용합니다. 예를 들면 검증과 운영 환경이 다른 백엔드를 사용하고, 해당 백엔드에 다른 보안 수준의 통제 설정이 불가능합니다.
  2. terraform workspace 명령을 실행하지 않으면 코드나 터미널에 현재 작업 공간에 대한 정보가 표시 되지 않습니다. 코드 탐색 시 한 작업 공간에 배치된 모듈은 다른 모든 작업 공간에 배치된 모듈과 동일합니다. 이로 인해 인프라를 제대로 파악하기 어려워 유지 관리가 어렵습니다.
  3. 위 두 항목의 결합된 문제가 발생 할 수 있습니다. 예를 들면 검증 환경이 아닌 운영 환경에서 terraform destroy 명령을 실행 할 수 있습니다. 검증과 운영 환경이 동일한 인증 매커니즘을 사용하기 때문에 위 오류에서 보호할 방법이 없습니다.

⇒ 파일 레이아웃을 이용한 격리를 권장!

# 실습 리소스 삭제
terraform workspace select default
terraform destroy -auto-approve
terraform workspace select mywork1
terraform destroy -auto-approve
terraform workspace select mywork2
terraform destroy -auto-approve# S3 버킷에 객체 삭제
aws s3 rm s3://hayley-t101study-tfstate-week3 --recursive# S3 버킷에 버저닝 객체 삭제 
aws s3api delete-objects \
    --bucket $NICKNAME-t101study-tfstate-week3 \
    --delete "$(aws s3api list-object-versions \
    --bucket "${NICKNAME}-t101study-tfstate-week3" \
    --output=json \
    --query='{Objects: Versions[].{Key:Key,VersionId:VersionId}}')"# S3 버킷에 삭제마커 삭제
aws s3api delete-objects --bucket hayley-t101study-tfstate-week3 \
    --delete "$(aws s3api list-object-versions --bucket "hayley-t101study-tfstate-week3" \
    --query='{Objects: DeleteMarkers[].{Key:Key,VersionId:VersionId}}')"# 백엔드 리소스 삭제
tfstate-backend$ terraform destroy -auto-approve# 관련 디렉터리/파일 삭제

파일 레이아웃을 이용한 격리

  • 각 테라폼 구성 파일을 분리된 폴더에 넣기 (예. stage , prod) : 어떤 환경에 배포할지 훨씬 명확해지고 별도의 상태파일을 사용하게 되어 한 환경에서 문제가 발생하더라도 다른 환경에 영향을 줄 가능성이 크게 줄어듦
  • 각 환경에 서로 다른 백엔드 구성(예. S3 버킷 백엔드의 AWS 계정을 분리)

file layout for Terraform projects

  • stage : 테스트 환경과 같은 사전 프로덕션 워크로드 workload 환경
  • prod : 사용자용 맵 같은 프로덕션 워크로드 환경
  • mgmt : 베스천 호스트 Bastion Host, 젠킨스 Jenkins 와 같은 데브옵스 도구 환경
  • global : S3, IAM과 같이 모든 환경에서 사용되는 리소스를 배치

각 환경별 구성 요소

  • vpc : 해당 환경을 위한 네트워크 토폴로지
  • services : 해당 환경에서 서비스되는 애플리케이션, 각 앱은 자체 폴더에 위치하여 다른 앱과 분리
  • data-storage : 해당 환경 별 데이터 저장소. 각 데이터 저장소 역시 자체 폴더에 위치하여 다른 데이터 저장소와 분리

명명 규칙

파일 레이아웃 실습

# 배포 
$ terraform init && terraform plan && terraform apply -auto-approve  
# 배포 확인 
$ terraform state list
aws_dynamodb_table.hayley-dynamodbtable
aws_s3_bucket.hayleys3bucket
aws_s3_bucket_versioning.hayleys3bucket_versioning
$ aws s3 ls
2022-05-22 20:18:10 cf-templates-n5k2dslphny9-ap-northeast-2
2022-10-30 20:47:45 hayley-t101study-tfstate-week3-files$ aws dynamodb list-tables --output text
TABLENAMES      terraform-locks
# mac/Linux 
#export TF_VAR_db_username=”(YOUR_DB_USERNAME)” 
#export TF_VAR_db_password=”(YOUR_DB_PASSWORD)” 
export TF_VAR_db_username='cloudneta' 
export TF_VAR_db_password='cloudnetaQ!' 
export | grep TF_VAR
# [터미널1] RDS 생성 모니터링 
#aws rds describe-db-instances --query "*[].[DBInstanceIdentifier,Endpoint.Address,Endpoint.Port,MasterUsername]" --output text while true; do aws rds describe-db-instances --query "*[].[Endpoint.Address,Endpoint.Port,MasterUsername]" --output text  ; echo "------------------------------" ; sleep 1; done  
# plan & apply : RDS는 생성 시 6분 정도 시간 소요 
terraform plan && terraform apply -auto-approveaddress = "t10120221030120250323900000001.cjzeahiftlk0.ap-northeast-2.rds.amazonaws.com"
port = 3306
vpcid = "vpc-0f7e4fdde88f683e6"
# output 확인 
terraform outputaddress = "t10120221030120250323900000001.cjzeahiftlk0.ap-northeast-2.rds.amazonaws.com"
port = 3306
vpcid = "vpc-0f7e4fdde88f683e6"
#aws s3 ls s3://$NICKNAME-t101study-tfstate-week3-files --recursive --human-readable --summarize  
aws s3 cp s3://hayley-t101study-tfstate-week3-files/stage/data-stores/mysql/terraform.tfstate .
# 상태 파일에 시크릿이 어떻게 저장되어 있는가? ⇒ 백엔드는 저장 시 암호화를 해야되는가? 아닌가? -> 평문으로 암호화해야함
egrep 'cloudneta|"endpoint"|"port"' terraform.tfstate"port": {
            "endpoint": "t10120221030120250323900000001.cjzeahiftlk0.ap-northeast-2.rds.amazonaws.com:3306",
            "password": "cloudnetaQ!",
            "port": 3306,
            "username": "cloudneta",
# ALB DNS주소로 curl 접속 확인  
ALBDNS=$(terraform output -raw myalb_dns) while true; do curl --connect-timeout 1  http://$ALBDNS:8080 ; echo; echo "------------------------------"; date; sleep 1; done curl -s http://$ALBDNS:8080hayleyalb_dns = "t101-alb-1003215812.ap-northeast-2.elb.amazonaws.com"------------------------------
Sun Oct 30 22:14:39 KST 2022
<h1>T101 Study</h1>
<p>My RDS DB address: t10120221030120250323900000001.cjzeahiftlk0.ap-northeast-2.rds.amazonaws.com</p>
<p>My RDS DB port: 3306</p>------------------------------
Sun Oct 30 22:14:41 KST 2022
<h1>T101 Study</h1>
<p>My RDS DB address: t10120221030120250323900000001.cjzeahiftlk0.ap-northeast-2.rds.amazonaws.com</p>
<p>My RDS DB port: 3306</p>

실습 화면

리소스 삭제

# 각 폴더에서 리소스 삭제
stage/services/webserver-cluster$ terraform destroy -auto-approve
stage/data-stores/mysql$ terraform destroy -auto-approve
# S3 버킷에 객체 삭제
$ aws s3 rm s3://hayley-t101study-tfstate-week3-files --recursive
# S3 버킷에 버저닝 객체 삭제 
$ aws s3api delete-objects \
    --bucket hayley-t101study-tfstate-week3-files \
    --delete "$(aws s3api list-object-versions \
    --bucket "hayley-t101study-tfstate-week3-files" \
    --output=json \
    --query='{Objects: Versions[].{Key:Key,VersionId:VersionId}}')"
# S3 버킷에 삭제마커 삭제
$ aws s3api delete-objects --bucket hayley-t101study-tfstate-week3-files \
    --delete "$(aws s3api list-object-versions --bucket "hayley-t101study-tfstate-week3-files" \
    --query='{Objects: DeleteMarkers[].{Key:Key,VersionId:VersionId}}')"
# 백엔드 리소스 삭제
global/s3$ terraform destroy -auto-approve
# 관련 디렉터리 삭제

 

 

blog migration project

written in 2022.10.30

https://medium.com/techblog-hayleyshim/iac-terraform-state-%EC%83%81%ED%83%9C%ED%8C%8C%EC%9D%BC%EA%B2%A9%EB%A6%AC-890c8eb41ca

'Programming > IaC' 카테고리의 다른 글

[IaC] Terraform tips & tricks — Loops & Conditions  (0) 2023.10.28
[IaC] Terraform modules  (0) 2023.10.28
[IaC] Terraform state -상태파일공유  (0) 2023.10.28
[IaC] GKE configuration  (0) 2023.10.28
[IaC] Terraform Syntax-GCP  (0) 2023.10.28