이번 포스팅에서는 terraform으로 협업하는 방법과 terraform의 Workflow에 대해 알아보겠다.
(본 포스팅은 cloud@net의 T101 스터디를 기반으로 작성된 글임을 밝힌다.)
인프라 규모가 커짐에 따라 Terraform 으로 관리해야할 리소스도 늘어나고, Terraform 관리자도 모듈 또는 프로젝트마다 다를 수 있다.
개인이 아닌 팀이 Terraform을 공유하고 관리할 때는 몇가지 주의사항이 있다.
참고: https://kschoi728.tistory.com/139
위 그림과 같이 여러 방식을 사용할 수 있는데, Best Practice는 유형3이라고 할 수 있겠다.
*.tf 파일들은 git과 같은 VCS에 저장하고, state파일은 AWS의 dynamoDB 또는
Azure blobStorage와 같은 Locking 기능을 제공하는 저장소를 사용하는 방법이다.
VCS로 github 또는 gitlab을 사용할 경우, 각각 Pull Request, Merge Request를 사용하여, 동료의 코드를 리뷰하면서 terraform 코드를 관리할 수 있으므로 안정성, 동기화의 장점을 갖는다.
state 파일의 경우, terraform 코드와, 실제로 클라우드에 배포된 리소스들의 상태를 비교할 때 쓰이는 중요한 파일로, Locking 기능이 있는 저장소를 통해 관리한다.
공유제외 대상
git을 통해 terraform 코드를 관리할 때 업로드해서는 안될 소스들이 있다.
- .terraform 디렉터리 : init 실행 시 작성되므로 제외 → 사이즈가 커질 수 있으므로 init시 각 로컬에 다운로드 받는 것 권장
- .tfstate 파일 : 프로비저닝 결과 데이터 소스 정보, 민감 데이터가 포함, 다른 사용자가 같은 State 파일을 사용하는 경우 인프라 불합치 유발
- tfvars 파일 : 프로비저닝 시 적용할 변수 값을 보관하는 파일로, 작업자 마다 별도 변수 사용 → TFC/TFE는 변수관리 기능 제공
- 시크릿 파일 : 인프라 구성에 필요한 시크릿 정보 파일 → Credentials 는 안전하게 별도로 관리 필요
- terraformrc 파일 : 작업자의 CLI 설정 파일
.gitignore 예시
# .gitignore
# Local .terraform directories
**/.terraform/*
# .tfstate files
*.tfstate
*.tfstate.*
# Crash log files
crash.log
crash.*.log
# Exclude all .tfvars files, which are likely to contain sensitive data, such as
# password, private keys, and other secrets. These should not be part of version
# control as they are data points which are potentially sensitive and subject
# to change depending on the environment.
*.tfvars
*.tfvars.json
# no creds
*.pem
# Ignore override files as they are usually used to override resources locally and so
# are not checked in
override.tf
override.tf.json
*_override.tf
*_override.tf.json
# Include override files you do wish to add to version control using negated pattern
# !example_override.tf
# Include tfplan files to ignore the plan output of command: terraform plan -out=tfplan
# example: *tfplan*
# Ignore CLI configuration files
.terraformrc
terraform.rc
민감정보나, 불필요하게 사이즈가 큰 파일들을 git으로 공유할 경우 보안이나 협업에 문제가 생길 수 있으므로, 주의하도록 하자.
state 백엔드
앞서 설명한 바와 같이 state 파일 관리를 위해서는 Locking 기능이 있는 스토리지를 사용한다. AWS, Azure 뿐 만 아니라 TFC(Terraform Cloud)를 활용하는 방법도 있는데, 실습을 통해 이해해보자.
참고로, TFC는 무료로 사용하는 것도 가능하다. (리소스 500개 까지 무료)
https://app.terraform.io/session 에서 계정을 먼저 생성해 준다.
위 화면에서 Organization을 생성하는데, S3와 같이 고유한 값이다.
#
terraform login
yes 입력
...
Terraform will store the token in plain text in the following file
for use by subsequent commands:
/Users/gasida/.terraform.d/credentials.tfrc.json
Token for app.terraform.io:
Enter a value: <자신의 토큰 입력>
...
# 토큰 확인
cat ~/.terraform.d/credentials.tfrc.json | jq
위 커맨드를 통해 terraform login을 하게되면, token을 통해 로그인을 하게된다. token을 TFC의 User Setting 페이지에서 Create an API token 버튼을 통해 생성할 수 있다.
로그인 완료화면
git clone https://github.com/terraform101/terraform-aws-collaboration
예제코드를 다운 받은 후 2개의 저장소로 나눈 후 main.tf의 내용을 아래와 같이 수정해준다.
# Clone 받은 저장소를 tom & jerry 이름으로 복제
mv terraform-aws-collaboration terraform-aws-collaboration-tom
cp -r terraform-aws-collaboration-tom terraform-aws-collaboration-jerry
# main.tf 파일에 프로바이더 블럭 수정
provider "aws" {
region = var.region
default_tags {
tags = {
Project = "workshop" # 기존 "<project name>"
}
}
}
tom 모듈에서 실행
#
cd ..
cd terraform-aws-collaboration-tom
#
terraform init
terraform plan -var=prefix=dev
terraform apply -auto-approve -var=prefix=dev
# 확인
terraform workspace list
terraform state list
ls terraform.tfstate*
terraform output
잘 배포가 되었다. 그럼 다시 jerry 디렉토리로 가서, terraform plan을 해보면 어떻게 될까?
#
cd ..
cd terraform-aws-collaboration-jerry
git pull
# plan 결과 어떻게 되나요?
terraform init
terraform plan -var=prefix=dev
# State 파일이 동기화 되어있으므로 변동사항 없음!
같은 리소스를 생성하는 코드임에도 불구하고, terraform plan 시 리소스를 생성하겠다고 나온다.
이유는? state 파일을 공유하지 않고, 각각의 디렉토리에 보관하고 있기 때문에 생긴 문제이다.
그럼 이제 TFC를 통해서 state backend를 세팅해보자. tom 과 jerry의 디렉토리에서 main.tf를 아래와 같이 각각 수정해준다. organization은 위에서 개인이 생성한 값을 넣어줘야한다.
terraform {
cloud {
organization = "kimchigood" # 생성한 ORG 이름 지정
hostname = "app.terraform.io" # default
workspaces {
name = "terraform-aws-collaboration" # 없으면 생성됨
}
}
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 4.0"
}
}
}
현재 TFC 페이지에 가서 보면, organization에 workspace가 존재하지 않는다.
main.tf에 cloud를 추가하였으므로, terrform init을 통해 변경사항을 저장한다.
다시 TFC 페이지로 가보면,
workspace가 생성된 것을 볼 수 있다.
기본적으로 Execution Mode가 Remote로 세팅되어 있는데, 이건 terraform plan, apply 시 실행도 TFC에서 하겠다는 의미이다. 로컬에서 실행하고 싶으면, Local 옵션을 선택 후 save하면된다. (실습에서는 AWS Credential이 로컬에 저장되어 있으므로 Local로 바꿔서 실습하도록 하자.)
Remote로 세팅 시 TFC에서 배포된 resouce들과 output 정보를 확인 할 수 있는 기능도 존재한다.
이제 jerry 디렉토리에서 다시 init 과 plan을 해보자.
#
cd ..
cd terraform-aws-collaboration-jerry
git pull
# plan 결과 어떻게 되나요?
terraform init
terraform plan -var=prefix=dev
# State 파일이 동기화 되어있으므로 변동사항 없음!
TFC에서 관리되는 state 파일을 참조하여, 변경사항이 없는 것을 확인할 수 있다.
jerry 모듈에서 아래 내용대로 수정하고, apply를 해준다.
resource "null_resource" "configure-cat-app" {
depends_on = [aws_eip_association.hashicat]
triggers = {
build_number = timestamp()
}
#
terraform apply -var=prefix=dev
...
Enter a value: <대기>
위와 같은 대기 상태에서, TFC 페이지를 확인해보면,
state가 locked 되어있는 것을 확인할 수 있다. 그럼 tom 디렉토리에서 작업을 하면 어떨까?
state 파일에 lock이 걸려서 작업을 할 수 없다고 나온다. TFC를 통해 state file에 대한 locking 기능을 확인한 것이다.
jerry 디렉토리에서 yes를 input하고, 작업이 완료되면, TFC에서도 state에 대한 lock이 풀리게 된다.
terraform destroy -auto-approve -var=prefix=dev