Iac

Terraform | Terraform State

no-easy-ray 2022. 1. 23. 21:38

테라폼은 인프라가 변경될 때마다 형상을 tfstate파일에 기록함으로써 현재 생성되어 있는 인프라 형상을 관리합니다.

따라서 테라폼으로 인프라를 생성하면 현재 디렉터리에 terraform.tfstate라는 파일이 생성되는 것을 확인할 수 있습니다.

 

terraform backend

로컬에서 state파일을 사용할 경우 다른 개발자와 tfstate파일을 공유하기에는 번거로움이 있습니다.

이러한 문제를 해결하고자 테라폼에서는 backend라는 기능을 제공합니다.

 

terraform backend라는 것은 생성되는 tfstate파일을 AWS의 S3, kubernetes 등 따로 저장되도록 하여

여러 사용자들에게 공유할 수 있도록 하는 것입니다.

 

AWS를 사용하고 있기 때문에 terraform backend로 S3를 사용하는 예제를 작성해보도록 하겠습니다.

 

먼저 terraform backend 될 S3버킷을 생성합니다.

# s3.tf
resource "aws_s3_bucket" "terraform_state" {
    bucket = "bob-terraform-state-bucket"
    acl    = "private"

    # 코드의 이력을 관리하기 위해 활성화 합니다.
    versioning {
        enabled = true
    }

    # 서버 측 암호화를 활성화 합니다.(S3에 저장된 파일이 암호화 됩니다.)
    server_side_encryption_configuration {
        rule {
            apply_server_side_encryption_by_default {
                sse_algorithm = "AES256"
            }
        }
    }
    
    # s3에 파일이 존재 하더라도 강제로 지우도록 합니다.
    force_destroy = true

    tags = {
        Name        = "state bucket"
    }
}

 

terraform init
terraform apply

 

버킷을 생성하게 되면 현재 경로에 terraform.tfstate파일이 존재하는 것을 확인할 수 있습니다.

 

이제 terraform backend로 S3를 지정하여 terraform.tfstate을 만들어둔 S3버킷으로 관리될 수 있도록 합니다. 

# main.tf
provider "aws" {
  region = "ap-northeast-2"

  default_tags {
    tags = {
      Terraform = "true"
    }
  }
}

terraform {
    backend "s3" {
      bucket = "bob-terraform-state-bucket"
      key    = "terraform.tfstate"
      region = "ap-northeast-2"
    }
}

 

terraform init을 하게되면 local에 있던 terraform.tfstate파일의 내용이 사라지고 만들어둔 S3에 해당 tfstate파일이 들어가 있는 것을 확인할 수 있습니다.

 

하지만 이렇 게 공유된 tfstate을 여러 사용자가 동시에 사용한다고 했을 때 문제가 발생할 수 있습니다.

예를 들어 두 명의 개발자가 서로 다르게 인프라를 변경을 한다면 변경된 내용을 tfstate에 지정하게 되는데 분명 충돌이 일어날 것입니다.

 

따라서 terraform에는 잠금(lock) 기능을 제공합니다.

잠금 기능이란 한 명이 apply를 통해서 tfstate를 변경하는 작업을 진행 중이라면 다른 개발자는 apply를 진행할 수 없는 상태를 말합니다.

 

잠금 기능을 이용하기 위해서는 AWS의 DynamoDB가 필요합니다.

# dynamodb.tf
resource "aws_dynamodb_table" "terraform_locks" {
    name           = "bob-terraform-locks"
    billing_mode   = "PAY_PER_REQUEST"
    hash_key       = "LockID"

    attribute {
        name = "LockID"
        type = "S"
    }
}

위와 같이 DynamoDB를 작성 후 apply를 통해 생성합니다.

 

추가적으로 해당 S3에서 tfstate를 사용하기 위해서는 IAM계정에 다음 2가지의 권한이 필요합니다.

이후 main.tf에 설정된 terraform backend설정을 변경합니다

# main.tf
...
terraform {
    backend "s3" {
      bucket = "bob-terraform-state-bucket"
      key    = "terraform.state"
      region = "ap-northeast-2"
	  
      # dynamodb추가
      dynamodb_table = "bob-terraform-locks"
      encrypt = true
    }
}

설정을 변경한 후 terraform init -migrate-state을 이용하여 init을 하게 되면 앞으로 변경되는 state에 대해서 적용이 되는 걸 확인할 수 있습니다.

 

terraform workspace

마지막으로 하나의 프로젝트에서 하나의 tfstate가 아닌 각각의 tfstate를 사용하고 싶을 경우 테라폼에서 제공하는 workspace기능을 사용할 수 있습니다.

 

명령어

현재 사용중인 workspace를 조회합니다.

terraform workspace show

생성되어있는 모든 workspace를 조회합니다.

terraform workspace list

새로운 workspace를 생성합니다.

# prod라는 workspace를 생성합니다.
terraform workspace new prod

만들어진 workspace를 선택합니다.

terraform workspace select prod

 

workspace를 생성할 경우 위에서 생성된 내용이 아닌 완전히 새로운 tfstate인 것을 확인할 수 있습니다.

 

간단한 예시로 다음과 같이 사용할 수 있습니다.

# Prod환경에서와 test환경에서 인스턴스 타입을 다르게 사용하는 예시
resource "aws_instance" "web" {
  ami           = data.aws_ami.ubuntu.id
  instance_type = terraform.workspace == "prod" ? "m5.large" : "t2.micro"
...
}

 

마무리

테라폼을 사용하면서 state파일을 관리하는 방법들에 대해서 정리해보았습니다.

 

실행한 예제를 삭제하기 위해서는 다음과같이 terraform backend를 지정한 것을 local로 돌린 후 삭제를 해야 에러 없이 삭제를 진행할 수 있습니다.

# main.tf
provider "aws" {
  region = var.region

  default_tags {
    tags = {
      Terraform = "true"
    }
  }
}

# terraform {
#     backend "s3" {
#       bucket = "bob-terraform-state-bucket"
#       key    = "terraform.state"
#       region = "ap-northeast-2"

#       dynamodb_table = "bob-terraform-locks"
#       encrypt = true
#     }
# }

terraform backend를 지정한 부분을 주석, 삭제 후 init를 진행하여 tfstate를 local에서 관리되도록 변경합니다.

terraform init -migrate-state

모든 리소스를 삭제합니다.

terraform destroy

감사합니다.