안녕하세요 늑대양 입니다
Terraform 관련 기초 스터디(Terraform 101 Study)를 참여하게 되어 해당 내용들을 주차별로 정리하고자 합니다.
해당 스터디는 CloudNet@ 팀의 Gasida 님이 호스트를 맡아 주셨으며,
https://gasidaseo.notion.site/CloudNet-Blog-c9dfa44a27ff431dafdd2edacc8a1863
스터디 메인 교재는 "테라폼으로 시작하는 IaC" 도서를 기준으로 진행 됩니다.
https://www.yes24.com/Product/Goods/119179333
아래의 내용은 4주차 - Provider & State 내용을 다루고 있습니다.
4주차 - Provider & State
Provider:
Provider 소개
https://registry.terraform.io/browse/providers
https://developer.hashicorp.com/terraform/language/providers
- 테라폼은 terraform 바이너리 파일을 시작으로 로컬 환경에나 배포 서버와 같은 원격 환경에서 원하는 대상을 호출하는 방식으로 실행
- 이때 ‘원하는 대상’은 호출하는 방식이 서로 다르지만 대상의 공급자, 즉 프로바이더가 제공하는 API를 호출해 상호작용
- 여기서 테라폼이 대상과의 상호작용을 할 수 있도록 하는 것이 ‘프로바이더’
- 각 프로바이더의 API구현은 서로 다르지만 테라폼의 고유 문법으로 동일한 동작을 수행하도록 구현되어 있음
- 프로바이더는 플러그인 형태로 테라폼에 결합되어 대상이 되는 클라우드, SaaS, 기타 서비스 API를 사용해 동작을 수행
- 각 프로바이더는 테라폼이 관리하는 리소스 유형과 데이터 소스를 사용할 수 있도록 연결
- 즉, 테라폼은 프로바이더 없이는 어떤 종류의 인프라와 서비스도 관리할 수 없다는 의미
- 대부분의 프로바이더는 대상 인프라 환경이나 서비스 환경에 대한 리소스를 관리하므로, 프로바이더를 구성할 때는 대상과의 연결과 인증에*(예. AWS 자격증명 등)* 필요한 정보가 제공되어야 함
- 각 프로바이더는 테라폼 실행 파일과는 별도로 자체 관리되고 게시되며, 테라폼 레지스트리 사이트에서 주요 프로바이더와 관련 문서를 확인 가능
4.1 Provider 구성
테라폼 레지스트리의 프로바이더 목록에는 유지 보수 및 게시에 대한 권한에 따라 티어 정보가 제공
https://registry.terraform.io/browse/providers
- 지정하는 프로바이더의 요구사항을 정의:
- 레지스트리의 Overview 항목 오른쪽에 있는 [USE PROVIDER] 클릭해 현재 버전의 정의 방법을 확인
- AWS Provider 예시:
로컬 이름과 프로바이더 지정
- terraform 블록의 required_providers 블록 내에 <로컬 이름> = { } 으로 여러 개의 프로바이더를 정의 가능
- 여기서 사용되는 로컬 이름은 테라폼 모듈 내에서 고유해야 함
- 로컬 이름과 리소스 접두사는 독립적으로 선언되며, 각 프로바이더의 소스 경로가 지정되면 프로바이더의 고유 접두사가 제공
- 만약 동일한 접두사를 사용하는 프로바이더가 선언되는 경우 로컬 이름을 달리해 관련 리소스에서 어떤 프로바이더를 사용하는지 명시적으로 지정 가능
- 예를 들어, 다음의 main.tf에서처럼 동일한 http 이름을 사용하는 다수의 프로바이더가 있는 경우 각 프로바이더에 고유한 이름을 부여하고 리소스와 데이터 소스에 어떤 프로바이더를 사용할지 provider 인수에 명시하며 동일한 source에 대해 다수의 정의는 불가능
- 동일한 http 접두사를 사용하는 다수의 프로바이더 사용 정의 예시
terraform {
required_providers {
architech-http = {
source = "architect-team/http"
version = "~> 3.0"
}
http = {
source = "hashicorp/http"
}
aws-http = {
source = "terraform-aws-modules/http"
}
}
}
data "http" "example" {
provider = aws-http
url = "https://checkpoint-api.hashicorp.com/v1/check/terraform"
request_headers = {
Accept = "application/json"
}
}
단일 프로바이더의 다중 정의
- 동일한 프로바이더를 사용하지만 다른 조건을 갖는 경우, 사용되는 리소스마다 별도로 선언된 프로바이더를 지정해야 하는 경우가 있다.
- 예를 들면, AWS 프로바이더를 사용하는데 서로 다른 권한의 IAM을 갖는 Access ID 또는 대상 리전을 지정해야 하는 경우
- 이때는 프로바이더 선언에서 alias를 명시하고 사용하는 리소스와 데이터 소스에서는 provider 메타인수를 사용해 특정 프로바이더를 지정 가능
- provider 메타인수에 지정되지 않은 경우 alias가 없는 프로바이더가 기본 프로바이더로 동작
# main.tf
provider "aws" {
region = "ap-southeast-1"
}
provider "aws" {
alias = "seoul"
region = "ap-northeast-2"
}
resource "aws_instance" "app_server1" {
ami = "ami-06b79cf2aee0d5c92"
instance_type = "t2.micro"
}
resource "aws_instance" "app_server2" {
provider = aws.seoul
ami = "ami-0ea4d4b8dc1e46212"
instance_type = "t2.micro"
}
# 배포 실행
terraform init && terraform plan
terraform apply -auto-approve
# 확인
terraform state list
echo "aws_instance.app_server1.public_ip" | terraform console
echo "aws_instance.app_server2.public_ip" | terraform console
aws ec2 describe-instances --filters Name=instance-state-name,Values=running --output table
aws ec2 describe-instances --filters Name=instance-state-name,Values=running --output table --region ap-southeast-1
# 삭제
terraform destroy -auto-approve
프로바이더 요구사항 정의
- 테라폼 실행 시 요구되는 프로바이더 요구사항은 terraform 블록의 required_providers 블록에 여러 개를 정의 가능
- source에는 프로바이더 다운로드 경로를 지정하고 version은 버전 제약을 명시
- 프로바이더 요구사항 정의 블록
terraform {
required_providers {
<프로바이더 로컬 이름> = {
source = [<호스트 주소>/]<네임스페이스>/<유형>
version = <버전 제약>
}
...
}
}
- 호스트 주소 : 프로바이더를 배포하는 주소로서 기본값은 registry.terraform.io
- 네임스페이스 : 지정된 레지스트리 내에서 구분하는 네임스페이스로, 공개된 레지스트리 및 Terraform Cloud의 비공개 레지스트리의 프로바이더를 게시하는 조직을 의미
- 유형 : 프로바이더에서 관리되는 플랫폼이나 서비스 이름으로 일반적으로 접두사와 일치하나 일부 예외가 있을 수 있음
- 프로바이더는 기능이나 조건이 시간이 지남에 따라 변경될 수 있다. 이 같은 변경에 특정 버전을 명시하거나 버전 호환성을 정의할 때, version에 명시할 수 있다. 이 값이 생략되는 경우 terraform init을 하는 당시의 가장 최신 버전으로 선택된다. 버전 상세 내용은 3.3장 버전 설정 확인
프로바이더 설치
- 테라폼을 실행하기 전 terraform init 명령을 통해 정의된 프로바이더를 다운로드, 복사, 캐시에서 읽어옴
- 항상 지정된 구성에 대해 동일한 프로바이더를 설치하도록 하려면 테라폼 구성에 사용되는 프로바이더에 대해 명시적으로 terraform 블록에 정의하거나 .terraform.lock.hcl 잠금 파일을 코드 저장소에 공유하는 방안이 요구
- 2장에서 살펴본 것처럼 required_providers에 지정된 프로바이더가 있는 경우 코드상 구성에서 사용 여부에 관계없이 프로바이더를 다운로드하게 되고, required_providers에 지정하지 않더라고 테라폼 구성 코드사에서 사용된 프로바이더를 테라폼에서 추론해 최신 버전의 프로바이더를 다운로드
프로바이더 간 전환 여부
- 클라우드를 대상으로 테라폼을 사용하는 경우 다른 클라우드 프로바이더로 전환이 가능할까? ⇒ 불가능하다!
- 테라폼은 인프라에 대한 단일 프로비저닝 도구로 사용되지만 대상이 되는 환경은 서로 다른 API로 구현된 프로바이더가 제공
4.2 Provider 에코시스템
테라폼의 에코시스템은 사용자가 사용하는 방식과 구조에 테라폼을 적용할 수 있도록 설계
- 에코시스템을 위한 테라폼 통합은 워크플로 파트너와 인프라 파트너로 나눔
- 워크플로 파트너는 테라폼 실행 및 Terraform Cloud/Enterprise와 연계하여 동작하는 기능을 제공하는 항목으로 구성
- 대표적으로 테라폼 구성을 관리하기 위한 VCS를 제공하는 깃허브, 깃랩, 비트버킷, 애저 데브옵스가 이 항목에 해당
- 프로바이더의 경우 인프라 파트너로 해당
- 인프라 파트너는 사용자가 테라폼으로 대상 플랫폼의 API로 상호작용 가능한 리소스를 관리
- 인프라 파트너의 분류와 프로바이더 대상은 아래와 같음
퍼블릭 클라우드
- IaaS, SaaS 및 PaaS를 포함한 다양한 서비스를 제공하는 대규모 글로벌 클라우드 제공
컨테이너 오케스트레이션
- 컨테이너 프로비저닝 및 배포를 지원
IaaS(Infrastructure-as-a-Service)
- 스토리지, 네트워킹 및 가상화와 같은 솔루션을 제공하는 인프라 및 IaaS 제공
보안 및 인증
- 인증 및 보안 모니터링 플랫폼
자산 관리
- 소프트웨어 라이선스, 하드웨어 자산 및 클라우드 리소스를 비롯한 주요 조직 및 IT 리소스의 자산 관리를 제공
CI/CD
- 지속적인 통합 및 지속적인 제공/배포
로깅 및 모니터링
- 로거, 측정 도구 및 모니터링 서비스와 같은 서비스를 구성하고 관리하는 기능
유틸리티
- 임의 값 생성, 파일 생성, http 상호 작용 및 시간 기반 리소스와 같은 도우미 기능
클라우드 자동화
- 구성 관리와 같은 전문화된 클라우드 인프라 자동화 관리 기능
데이터 관리
- 데이터 센터 스토리지, 백업 및 복구 솔루션
네트워킹
- 라우팅, 스위칭, 방화벽 및 SD-WAN 솔루션과 같은 네트워크별 하드웨어 및 가상화된 제품과 통합
VCS(버전 제어 시스템)
- Terraform 내에서 VCS(버전 제어 시스템) 프로젝트, 팀 및 리포지토리에 중점
통신 및 메시징
- 통신, 이메일 및 메시징 플랫폼과 통합
데이터베이스
- 데이터베이스 리소스를 프로비저닝 및 구성하는 기능
PaaS(Platform-as-a-Service)
- 다양한 하드웨어, 소프트웨어 및 애플리케이션 개발 도구를 제공하는 플랫폼 및 PaaS
웹 서비스
- 웹 호스팅, 웹 성능, CDN 및 DNS 서비스
- 퍼블릭 클라우드(Iaas, Paas) 프로바이더 + 프라이빗 클라우드/VM
- 컨테이너 오케스트레이터
- SaaS 서비스
- 기타 솔루션
4.3 Provider 경험해보기
[AWS] 실습. 2개의 리전에 Ubuntu EC2 배포:
2가지 주의 사항
- Warning 1 : Multiregion is hard 프로덕션 수준의 멀티 리전은 어려움
- Active-Active 멀티 리전 서비스를 위해서 ‘지역간 지연 시간, 고유 ID, 최종 일관성’ 등 여러가지 고려사항이 많아서 쉽지 않음
- Warning 2 : Use aliases sparingly Alias 를 빈번하게 사용하지 말자
- 별칭을 사용하여 두 리전에 배포하는 단일 테라폼 모듈은 한 리전이 다운 시, plan 과 apply 시도가 실패
- 프로덕션 환경은 멀티 리전의 별칭을 사용하는 것보다는, 3장에서 설명한 것 처럼 환경을 완전히 격리 필요
- 이를 통해 영향도를 최소화 가능
#provider_data.tf
provider "aws" {
region = "ap-northeast-2"
alias = "region_1"
}
provider "aws" {
region = "ap-southeast-1"
alias = "region_2"
}
data "aws_region" "region_1" {
provider = aws.region_1
}
data "aws_region" "region_2" {
provider = aws.region_2
}
data "aws_ami" "ubuntu_region_1" {
provider = aws.region_1
most_recent = true
owners = ["099720109477"] # Canonical
filter {
name = "name"
values = ["ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"]
}
}
data "aws_ami" "ubuntu_region_2" {
provider = aws.region_2
most_recent = true
owners = ["099720109477"] # Canonical
filter {
name = "name"
values = ["ubuntu/images/hvm-ssd/ubuntu-focal-20.04-amd64-server-*"]
}
}
# ec2.tf
resource "aws_instance" "region_1" {
provider = aws.region_1
ami = data.aws_ami.ubuntu_region_1.id
instance_type = "t2.micro"
}
resource "aws_instance" "region_2" {
provider = aws.region_2
ami = data.aws_ami.ubuntu_region_2.id
instance_type = "t2.micro"
}
# 실행
# [터미널1] ap-northeast-2
while true; do aws ec2 describe-instances --region ap-northeast-2 --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
# [터미널2] ap-southeast-1
while true; do aws ec2 describe-instances --region ap-southeast-1 --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
# init & plan & apply
terraform init && terraform plan && terraform apply -auto-approve
terraform state list
# 확인
aws ec2 describe-instances --region ap-northeast-2 --query "Reservations[*].Instances[*].{PublicIPAdd:PublicIpAddress,InstanceName:Tags[?Key=='Name']|[0].Value,Status:State.Name}" --filters Name=instance-state-name,Values=running --output text
aws ec2 describe-instances --region ap-southeast-1 --query "Reservations[*].Instances[*].{PublicIPAdd:PublicIpAddress,InstanceName:Tags[?Key=='Name']|[0].Value,Status:State.Name}" --filters Name=instance-state-name,Values=running --output text
# 삭제
terraform destroy -auto-approve
State:
https://developer.hashicorp.com/terraform/language/state
5.1 State의 목적과 의미
상태 파일 확인 실습.
# 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": 1,
...
# 아래 정보는 terraform.tfstate 정보를 통해 출력
terraform state list
terraform state show aws_vpc.myvpc
# vpc.tf 파일 수정
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": 3,
---
> "serial": 1,
...
# 확인 후 삭제
terraform destroy -auto-approve
- 상태 파일은 배포할 때마다 변경되는 프라이빗 API private API로, 오직 테라폼 내부에서 사용하기 위한 것
- 테라폼 상태 파일을 직접 편집하거나 직접 읽는 코드로 작성해서는 안됨
팀 단위에서 테라폼 운영 시, 문제점
- 상태 파일을 저장하는 공유 스토리지 Shared storage for state files
- 각 팀원이 동일한 테라폼 상태 파일 사용을 위해서, 공유 위치에 저장이 필요
- 상태 파일 잠금 Locking state files
- 잠금 기능 없이 두 팀원이 동시에 테라폼 실행 시 여러 테라폼 프로세스가 상태 파일을 동시에 업데이트하여 충돌 가능(경쟁 상태 race condition)
- 상태 파일 격리 Isolating state files
- 예를 들면 테스트 dev 와 검증 stage 과 상용 prodction 각 환경에 대한 격리가 필요
상태 파일 공유로 버전 관리 시스템 비추천
- 수동 오류 Manual error
- 테라폼을 실행하기 전에 최신 변경 사항을 가져오거나 실행하고 나서 push 하는 것을 잊기 쉽습니다(?).
- 팀의 누군가가 이전 버전의 상태 파일로 테라폼을 실행하고, 그 결과 실수로 이전 버전으로 롤백하거나 이전에 배포된 인프라를 복제하는 문제가 발생 할 수 있음.
- 잠금 Locking
- 대부분의 버전 관리 시스템은 여러 명의 팀 구성원이 동시에 하나의 상태 파일에 terraform apply 명령을 실행하지 못하게 하는 잠금 기능이 제공되지 않음.
- 시크릿 Secrets
- 테라폼 상태 파일의 모든 데이터는 평문으로 저장됨. 민감 정보가 노출될 위험.
지원되는 원격 백엔드
AWS S3, Azure Blob Storage, Google Cloud Storage, Consul, Postgres database, k8s secret 등 - 링크
- 수동 오류 해결: plan/apply 실행 시 마다 해당 백엔드에서 파일을 자동을 로드, apply 후 상태 파일을 백엔드에 자동 저장
- 잠금: apply 실행 시 테라폼은 자동으로 잠금을 활성화, -lock-timout=<TIME> 로 대기 시간 설정 지정 가능
- 시크릿: 대부분 원격 백엔드는 기본적으로 데이터를 보내거나 상태 파일을 저장할 때 암호화하는 기능을 지원
5.2 State 동기화
테라폼 구성 파일은 기존 State와 구성을 비교해 실행 계획에서 생성, 수정, 삭제 여부를 결정
State 유형 별 실습:
유형 1: 신규 리소스 정의 → Apply ⇒ 리소스 생성
# 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 state list
# 아래 명령어 실행 결과 차이는?
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
# 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: 실수로 tfstate 파일 삭제 → plan/apply ← 책에는 없는 내용
# 실수로 tfstate 파일 삭제
terraform state list
aws_iam_user.myiamuser1
rm -rf terraform.tfstate*
#
terraform plan
aws iam list-users | jq
terraform plan -refresh=false
#
terraform apply -auto-approve
terraform state list
cat terraform.tfstate | jq
# iam 사용자 리스트 확인
aws iam list-users | jq
# 위 상황에서 복구? 하는 방법은? import 등 방법이 가능
유형 6: 실수로 tfstate 파일 삭제 시 → import 로 tfstate 파일 복구
https://developer.hashicorp.com/terraform/cli/import
https://developer.hashicorp.com/terraform/tutorials/state/state-import
# 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
# 확인 후 리소스 삭제
terraform destroy -auto-approve
5.3 Terraform Backend: AWS S3 + DynamoDB
https://developer.hashicorp.com/terraform/language/settings/backends/s3
실습.
https://malwareanalysis.tistory.com/633#8.-state-%EB%B0%B1%EC%97%94%EB%93%9C
# [사전 준비 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 = "wolf-sheep-hello-t1014-remote-backend"
# 생성
terraform init && terraform apply -auto-approve
# 확인
terraform state list
aws s3 ls
# 2. 테라폼 자원 배포 시 ‘리모트 백엔드 저장소’ 설정 사용
# VSCODE에서 provider.tf 코드 확인
cd ../vpc
ls
cat provider.tf
# VSCODE에서 provider.tf 수정
...
backend "s3" {
#bucket = "<닉네임>-hello-t1014-remote-backend"
bucket = "wolf-sheep-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
# 3. 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
# 4. 2번 테라폼 자원 배포에 백엔드 설정 수정 및 적용
# VSCODE에서 provider.tf 코드 확인
cd ../vpc
cat provider.tf
# VSCODE에서 provider.tf 수정 : dynamodb_table = "terraform-lock" 주석 제거
...
backend "s3" {
bucket = "wolf-sheep-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
# 5. VPC tag 수정 후 apply 와서 Locking 확인
# 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 없음 확인
# 6. 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",
# 7. 실습 리소스 삭제
# 테라폼 배포 리소스 삭제 : 현재 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
테라폼 백엔드 단점
- 테라폼의 backend 블록에는 변수나 참조를 사용 할 수 없음
- 그 결과 S3 버킷 이름, 리전, DynamoDB 테이블 이름을 모두 테라폼 모듈에 수동으로 복사붙여녛어야 함
- 심지어 key 값은 중복되면 안되며 고유하게 넣어야함
- partial configuration 을 통해 일부 매개 변수를 전달해서 사용 할 수 있음
- 다만, 이 경우에도 모듈마다 서로 다른 key 값을 설정해야 하기 때문에 key 매개 변수는 테라폼 코드에 있어야함
- 부분적으로 구성한 것들을 모두 결합하려면 -backend-config 인수와 함께 terraform init 명령을 실행
terraform init -backend-config=backend.hcl
- 위의 단점을 보완해주는 오픈 소스 테라그런트(Terragrunt)가 있음
https://terragrunt.gruntwork.io/
5.4 Workspace
워크스페이스는 상태 관리의 '단위' 로 이해 가능
한 프로젝트 내에서 여러 개의 .tf 파일을 가진 디렉토리가 여러 워크스페이스로 동작 가능
https://developer.hashicorp.com/terraform/language/state/workspaces
- 작업 공간을 통한 격리 Isolation via workspaces
- 동일한 구성에서 빠르고 격리된 테스트 환경에 유용
- 파일 레이아웃을 이용한 격리 Isolation via file layout
- 보다 강력하게 분리해야 하는 운영 환경에 적합
- 테라폼 프로젝트의 파일 레이아웃 설명
- 각 테라폼 구성 파일을 분리된 폴더에 넣기. (예. stage , prod)
- 각 환경에 서로 다른 백엔드 구성. (예. S3 버킷 백엔드의 AWS 계정을 분리)
최상위 폴더
- stage : 테스트 환경과 같은 사전 프로덕션 워크로드 workload 환경
- prod : 사용자용 맵 같은 프로덕션 워크로드 환경
- mgmt : 베스천 호스트 Bastion Host, 젠킨스 Jenkins 와 같은 데브옵스 도구 환경
- global : S3, IAM과 같이 모든 환경에서 사용되는 리소스를 배치
각 환경별 구성 요소
- vpc : 해당 환경을 위한 네트워크 토폴로지
- services : 해당 환경에서 서비스되는 애플리케이션, 각 앱은 자체 폴더에 위치하여 다른 앱과 분리
- data-storage : 해당 환경 별 데이터 저장소. 각 데이터 저장소 역시 자체 폴더에 위치하여 다른 데이터 저장소와 분리
명명 규칙 naming conventions (예시)
- variables.tf : 입력 변수
- outputs.tf : 출력 변수
- main-xxx.tf : 리소스 → 개별 테라폼 파일 규모가 커지면 특정 기능을 기준으로 별도 파일로 분리 (ex. main-iam.tf, main-s3.tf 등) 혹은 모듈 단위로 나눔
- dependencies.tf : 데이터 소스
- providers.tf : 공급자
Tip 1. terraform-workspace-prompt
https://github.com/amatellanes/terraform-workspace-prompt
Tip 2. Terraform workspace CLI
https://developer.hashicorp.com/terraform/cli/workspaces
지금까지 Terraform 101 Study 4주차 내용이었습니다.
테라폼을 학습하시는 분들에게 도움이 되었으면 좋을 것 같습니다 🙏
긴 글 읽어주셔서 감사드립니다.
좋은 주말 보내세요!
감사합니다😊
'Terraform' 카테고리의 다른 글
Terraform 101 Study - 6주차 (0) | 2024.07.27 |
---|---|
Terraform 101 Study - 5주차 (0) | 2024.07.12 |
Terraform 101 Study - 3주차 (0) | 2024.06.30 |
Terraform 101 Study - 2주차 (0) | 2024.06.23 |
Terraform 101 Study - 1주차 (0) | 2024.06.16 |