안녕하세요. 이 글은 테라폼 스터디에서 공부한 state를 정리했습니다.
영상: https://youtu.be/E2n3bZrzpKE
1. state란?
테라폼은 대상에 배포한 결과를 state로 관리합니다. 또한, 테라폼 실행 작업(생성/수정/삭제) 결정에 중요한 연할을 합니다. 예를 들어 state가 없으면 테라폼은 리소스 생성 작업을 실행합니다.
2. state 업데이트는 언제 될까?
state는 테라폼이 실행된 후 생성됩니다. terraform CLI에서는 terraform apply를 실행한 후 state가 생성됩니다. 이미 state가 있다면 업데이트됩니다. state 업데이트 과정을 terraform refresh라고 부릅니다.
3. state 관리
3.1 state 포맷
state는 JSON 포맷입니다.
3.2 state 관리방법
테라폼 도구마다 state를 관리하는 방법이 다릅니다. 테라폼 CLI는 state를 tfstate파일에 저장합니다.
3.3 예제
예제코드는 github에 공개되어 있습니다.
git clone https://github.com/sungwook-practice/t101-study.git example
cd example/state/step2_vpc
예제코드는 vpc를 생성합니다. vpc cidr를 테라폼 변수로 입력 받습니다. 저는 terraform.tfvars로 변수 값을 초기화 했습니다.
테라폼을 초기화 합니다.
terraform init
terraform apply를 실행하여 vpc를 생성합니다.
terraform apply
테라폼 실행 후 파일목록을 확인하면, terraform.tfstate파일이 있습니다. 파일 내용에는 json포맷인 state가 있습니다. state에는 생성한 vpc정보(예: vpc arn 등)가 있습니다.
cat terraform.tfstate
4. state 조회
4.1 조회 명령어
terraform state list/show 명령어로 state를 조회할 수 있습니다. 이 명령어는 크기가 큰 state를 확인할 때 유용합니다. 리소스가 많아질수록 state크기도 커집니다.
4.2 예제
이전 챕터(3.3) 예제를 사용합니다.
terraform apply명령어를 실행하고 terraform.tfstate파일이 생성되었는지 확인합니다.
terraform apply
ls terraform.tfstate
state파일에는 테라폼이 생성한 vpc정보가 있습니다. 테라폼이 관리하는 리소스 갯수만큼 state가 생성되고 name(block label)로 구분합니다.
state 목록은 json필드를 찾아보거나 terraform state show명령어를 사용하면 됩니다.
terraform state list
state 값은 terraform state show로 확인할 수 있습니다. state show명령어는 json필드 값과 동일합니다.
terraform state show aws_vpc.main
5. state 버전
state는 serial라는 필드로 버전을 관리합니다. state가 업데이트될 때마다 serial이 증가합니다.
cat terraform.tfstate
6. state의 테라폼 작업 영향도
6.1 영향도
테라폼은 state와 대상 현재 상황을 비교하여 어떤 작업(생성/수정/삭제)을 할지 수행합니다. state와 대상 비교 과정을 terraform refresh라고 합니다.
terraform refresh는 비교 과정 말고도 상태를 업데이트할 때 사용됩니다. 테라폼 실행 전에 refresh가 실행되면 비교를 하고, 테라폼 실행 후에 refresh가 실행되면 state를 업데이트합니다. 아래 예제는 terraform destroy를 실행하기 전 state와 대상을 비교합니다.
6.2. 예제
테스트 예제는 s3버킷과 vpc코드를 사용합니다. 예제는 state가 있을 때와 없을 때 어떻게 동작하는지 테스트합니다. 또한, 리소스가 유일해야하는 s3버킷과 유일하지 않아도 되는 vpc가 어떻게 테라폼이 실행되는지 비교합니다.
6.2.1 첫번째 예제
첫번째 예제는 state와 리소스가 없는 상태에서 테라폼 코드를 실행합니다. 예제코드는 버킷을 생성합니다.
예제코드는 github에 공개되어 있습니다.
git clone https://github.com/sungwook-practice/t101-study.git example
cd example/state/step1_bucket
버킷 이름은 변수로 입력받습니다. 저는 tfvars파일로 변수 값을 초기화 했습니다. 예제를 실행할 때 꼭 버킷 이름을 변경해주세요.
cat terraform.tfstate
테라폼을 초기화 합니다.
terraform init
terraform apply를 실행하면 버킷을 생성하는 메세지가 출력됩니다. state와 aws에 버킷이 없기 때문에 테라폼은 버킷 생성 작업을 합니다.
terraform apply
생성한 버킷 정보는 state로 관리되고 terraform.tfstate파일에 저장됩니다. 예를 들어 생성한 버킷 arn이 state에 있습니다.
cat terraform.tfstate
6.2.2 두번째 예제
두 번째 예제는 state는 없지만 리소스가 있을 때 테라폼을 실행합니다.
첫번째 예제를 실행 한 후, tfstate파일 확장자를 tmp로 변경합니다. tfstate파일이 없기 때문에 테라폼은 state파일이 없다고 판단합니다.
mv terraform.tfstate terraform.tfstate.tmp
terraform apply명령어를 실행하면 어떤 결과가 나올까요? state가 없기 때문에 테라폼은 버킷을 생성하려고 합니다.
terraform apply
하지만 첫 번째 예제에서 버킷을 생성했으므로 버킷 이름 중복 오류가 발생합니다. 그러므로 테라폼 실행도 실패합니다.
6.2.3 세번째 예제
세 번째 예제는 state가 있고 리소스가 있을 때 테라폼을 실행합니다.
두번째 예제에서 확장자를 변경한 state파일을 원복합니다.
mv terraform.tfstate.tmp terraform.tfstate
terraform apply명령어를 실행하면 아무 변화가 없습니다. state에는 버킷이 있고 aws도 이미 버킷(첫 번째 예제에서 생성)이 있기 때문에, 테라폼은 아무런 동작을 안 했습니다.
terraform apply
6.2.4 네번째 예제
네 번째 예제는 두 번째 예제 상황을 반례를 든 예제입니다. state가 없고 리소스가 있는 상황에서 테라폼을 실행하면, 테라폼 에러가 발생 안되는 상황이 있습니다. aws vpc처럼 전 세계 유일하지 않는 리소스는 에러가 발생하지 않고 리소스를 생성합니다.
실습으로 상황을 재현해볼까요? 예제코드는 github에 공개되어 있습니다.
git clone https://github.com/sungwook-practice/t101-study.git example
cd example/state/step2_vpc
네 번째 예제코드는 vpc를 생성합니다. vpc cidr를 테라폼 변수로 입력 받습니다. 저는 terraform.tfvars로 변수 값을 초기화 했습니다.
테라폼을 초기화 합니다.
terraform init
terraform apply를 실행하여 vpc를 생성합니다.
terraform apply
테라폼 코드 실행 후 생성한 vpc정보가 있는 state파일이 생성됩니다.
ls -l terraform.tfstate
state파일 확장자를 변경하여 state가 없는 것처럼 상황을 만듭니다. 현재 두번째 예제처럼 state파일은 없고 리소스가 있는 상황을 만들었습니다.
mv terraform.tfstate terraform.tfstate.tmp
두번째 예제와 상황은 같지만 테라폼 실행결과는 다릅니다. terraform apply를 실행하면 테라폼이 정상적으로 실행되고 vpc가 생성됩니다. 그리고 생성한 vpc정보가 state파일에 저장됩니다. vpc는 버킷과 다르게 이름이 유일하지 않기 때문에, 테라폼 생성 작업이 정상적으로 실행되었습니다.
terraform apply
7. terraform import
terraform import 명령어는 이미 존재하는 대상 리소스를 state로 만들어줍니다. 테라폼으로 생성하지 않는 대상을 테라폼으로 관리하고 싶을 때 사용합니다.
terraform import를 사용하기 위해서 테라폼 코드와 대상에 리소스가 존재해야 합니다. terraform import명령어를 실행하면 대상 리소스를 테라폼 코드에 매핑 시켜 state를 업데이트 합니다.
사용방법은 아래와 같습니다.
terraform import block_type.block_name {대상 리소스 식별값}
아래 예제는 aws vpc_id를 리소스 식별값으로 사용하여 terraform import를 사용했습니다.
8. state 백엔드
state를 저장하는 곳을 백엔드(backend)라고 합니다. 디폴트로 테라폼을 실행한 로컬에 파일로 저장합니다. 로컬이 아니라 원격에 state를 저장하는 것을 remote state라고 합니다.
remote state는 여러 사람과 협업할 때 꼭 설정해야 합니다. 앞서 예제에서 살펴본 것처럼 state에 따라 테라폼 실행 결과가 달라집니다.
이 예제에서는 remote state를 s3에 저장합니다.
8.1 S3생성
테라폼 코드는 github에 공개되어 있습니다.
git clone https://github.com/sungwook-practice/t101-study.git example
cd example/state/step3_remote_backend/s3_backend
main.tf에 s3 버킷과 버킷버전 설정을 하는 테라폼 코드가 있습니다. 버전 설정을 한 이유는 누군가 실수로 remote state를 삭제하는 것을 방지하기 위해서입니다.
resource "aws_s3_bucket" "main" {
bucket = var.bucket_name
tags = {
Name = "terraform test"
}
}
resource "aws_s3_bucket_versioning" "main" {
bucket = aws_s3_bucket.main.id
versioning_configuration {
status = "Enabled"
}
}
버킷 이름은 변수로 입력받습니다. 저는 tfvars파일로 변수 값을 초기화 했습니다. 예제를 실행할 때 꼭 버킷 이름을 변경해주세요.
cat terraform.tfstate
테라폼 코드를 실행하여 버킷을 생성합니다.
terraform init && terraform apply
생성된 버킷은 versioning이 활성화되어 있습니다.
8.2 backend 설정
생성한 s3에 state가 저장되도록 테라폼 코드에 backend를 설정해야 합니다.
테라폼 코드는 github에 공개되어 있습니다. 예제코드는 aws vpc를 생성합니다
git clone https://github.com/sungwook-practice/t101-study.git example
cd example/state/step3_remote_backend/vpc
terraform block에서 backend설정을 할 수 있습니다. 예제코드에서 provider.tf에 terraform block이 있습니다. backend block에는 버킷이름과 버킷경로, 리전을 설정합니다. 예제코드에서는 챕터 8.1에서 생성한 버킷을 사용했습니다.
# provider.tf
terraform {
...이하 생략
backend "s3" {
bucket = "hello-tf102-remote-backend"
key = "terraform/state-test/terraform.tfstate"
region = "ap-northeast-2"
}
}
테라폼을 초기화 과정에서 s3와 잘 연결되는지 확인합니다.
terraform init
곧이어 terraform apply를 실행합니다.
terraform apply
terraform apply이후에 업데이트된 state는 s3에 저장됩니다. s3경로는 테라폼 코드 backend에 설정한 경로와 일치합니다.
8.3 locking
여러 사람과 remote_state를 안전하게 관리하려면 locking이 필요합니다. locking이란 동시에 state를 업데이트 할 수 없도록 잠그는 기능입니다. 한 사람이 state를 업데이트하기 전 locking을 하면, 다른 사람이 state를 업데이트할 때 locking이 해제되기전까지 대기합니다.
locking 설정은 backend마다 다릅니다. s3는 locking을 지원하지 않아 DynamoDB를 사용합니다. DynamoDB는 key/value유형 managed DB입니다.
이전 실습에서 생성한 s3에 locking기능을 추가해보겠습니다. 먼저 DynamoDB table을 생성해야 합니다. 예제코드는 github에 공개되어 있습니다.
git clone https://github.com/sungwook-practice/t101-study.git example
cd example/state/step3_remote_backend/dynamodb
main.tf에 DynamoDB table이름과 key설정이 있습니다.
resource "aws_dynamodb_table" "terraform_state_lock" {
name = "terraform-lock" # table이름
hash_key = "LockID" # key 이름
billing_mode = "PAY_PER_REQUEST"
attribute {
name = "LockID"
type = "S" # key 타입
}
}
테라폼을 실행하여 DynamoDB table을 생성합니다.
terraform apply
aws콘솔에서 생성한 DynamoDB table을 볼 수 있습니다.
state locking을 하기 위해, 이전 실습 backend설정에 DynamoDB를 추가해야 합니다.
terraform {
...이하생략
backend "s3" {
bucket = "hello-tf102-remote-backend"
key = "terraform/state-test/terraform.tfstate"
region = "ap-northeast-2"
dynamodb_table = "terraform-lock" # 추가된 코드
}
}
backend설정이 달라졌으므로 terraform init을 해야 합니다.
terraform init -migrate-state
이제 s3에 있는 remote_state를 업데이트 하기 전 locking을 통과해야 합니다. vpc이름을 수정해보고 terraform apply을 실행해보세요. 그리고 동시에 DynamoDB table 필드를 관찰하면 locking필드가 생겼다가 없어집니다.
'연재 시리즈' 카테고리의 다른 글
S3 공개(public) 설정 - 버킷 policy 설정편 (1) | 2023.09.02 |
---|---|
S3 공개(public) 설정 - ACL 설정편 (0) | 2023.09.02 |
테라폼 t102 스터디 - 프로비저너(provisioner) (0) | 2023.07.22 |
테라폼 t102 스터디 - dynamic block (0) | 2023.07.15 |
테라폼으로 EKS만들기 프로젝트 4-3편 - VPC 입력변수 설정 (0) | 2023.07.09 |