본문 바로가기

DevOps

[Terraform] terraform state mv 명령어 알아보기 및 활용법

반응형

Terraform은 tfstate 파일 기반으로 동작한다.

 

1. main.tf에 정의된 인프라스트럭쳐

2. tfstate 파일에 정의된 인프라스트럭쳐

 

위 2가지를 대조한 뒤, terraform plan 명령어를 수행하면 tfstate에 정의된 인프라스트럭쳐main.tf에 정의한 인프라스트럭쳐를 맞추려고 한다.

 

예를 들어, 예전에 Terraform 코드로 생성한 IAM User가 아래와 같이 존재한다고 가정해보자.

 

resource "aws_iam_user" "user1" {
  name = "user1"
}

resource "aws_iam_user" "user2" {
  name = "user2"
}

 

IAM User : user1, user2가 존재할 것이다.

 

이 상태에서 user1, user2를 유지하되 count 함수를 사용하고 싶다고 가정해보자.

 

variable "users" {
  description = "Create IAM Users"
  type        = list
  default     = ["user1", "user2"]
}

resource "aws_iam_user" "users" {
  count   = length(var.users)
  name    = element(var.users, count.index) 
}

 

IAM User : user1, user2를 정의하는 코드지만, 테라폼은 위 둘을 다른 코드로 인식한다.

 

왜냐하면 aws_iam_user.user1, aws_iam_user.user2와 aws_iam_user.users는 테라폼에게 엄연히 다른 리소스이기 때문이다.

 

즉, 의미적으로 똑같은데 terraform plan을 하게 되면 기존 리소스를 destroy하고 apply를 수행하게 된다.

 

=> terraform state mv를 통해 해결할 수 있음

=> 테라폼 코드를 리팩터링 할 때 많이 사용하게 된다.


terraform state mv [options] SOURCE DESTINATION

 

Ref : https://www.terraform.io/cli/commands/state/mv

 

=> 대상 주소에 지정된 주소와 일치하는 항목을 이동한다.

=> 간단한 자원 이름 변경, 항목을 모듈로 이동하거나 모듈 전체로 이동하는데 사용할 수 있다.

=> 또한 완전하 새로운 상태로 이동할 수 있으므로 하나의 구성을 여러 개의 개별 관리형 Terraform 구성으로 리팩터링 하는 데에도 사용할 수 있다.

Example

1. 자원 이름 바꾸기

$ terraform state mv aws_instance.foo aws_instance.bar

 

2. 자원을 모듈로 이동

$ terraform state mv aws_instance.foo module.web

 

3. 모듈을 모듈로 이동

$ terraform state mv module.foo module.parent.module.foo

 

4. 모듈을 다른 상태로 이동

$ terraform state mv -state-out=other.tfstate \
    module.web module.web

사용 Case

 

[1] 배경 : 기존에 사용하던 resource 파일을 다음과 같이 리팩터링 하고자 함

 

별도의 resource 2개 만들지 말고, for_each 함수를 사용하여 리팩터링

 

 

[2] 조치 방안

➜  common git:(dev) ✗ terraform state mv 'aws_route53_record.www_cname_pingping95_shop' 'aws_route53_record.cname_pingping95_shop[0]'
Move "aws_route53_record.www_cname_pingping95_shop" to "aws_route53_record.cname_pingping95_shop[0]"
Successfully moved 1 object(s).


➜  common git:(dev) ✗ terraform state mv 'aws_route53_record.test_cname_pingping95_shop' 'aws_route53_record.cname_pingping95_shop[1]'
Move "aws_route53_record.test_cname_pingping95_shop" to "aws_route53_record.cname_pingping95_shop[1]"
Successfully moved 1 object(s).


➜  common git:(dev) ✗ terraform state list
aws_acm_certificate.pingping2_shop
aws_acm_certificate.pingping2_shop-virginia
aws_acm_certificate_validation.pingping2_shop_validation
aws_acm_certificate_validation.pingping2_shop_validation-virginia
aws_route53_record.cname_pingping95_shop[0]
aws_route53_record.cname_pingping95_shop[1]
aws_route53_record.pingping2_shop_acm_cname["pingping2.shop"]
aws_route53_record.pingping2_shop_acm_cname["www.pingping2.shop"]
aws_route53_record.pingping2_shop_acm_cname-virginia["pingping2.shop"]
aws_route53_record.pingping2_shop_acm_cname-virginia["test.pingping2.shop"]
aws_route53_zone.pingping2_shop
aws_s3_account_public_access_block.ftstate
aws_s3_bucket.tfstate





# 다시 (실수로 [0], [1] 이런 식으로 변경하였음)

➜  common git:(dev) ✗ terraform state mv 'aws_route53_record.cname_pingping95_shop[0]' 'aws_route53_record.cname_pingping95_shop["www"]'
Move "aws_route53_record.cname_pingping95_shop[0]" to "aws_route53_record.cname_pingping95_shop[\"www\"]"
Successfully moved 1 object(s).

➜  common git:(dev) ✗ terraform state mv 'aws_route53_record.cname_pingping95_shop[1]' 'aws_route53_record.cname_pingping95_shop["test"]'
Move "aws_route53_record.cname_pingping95_shop[1]" to "aws_route53_record.cname_pingping95_shop[\"test\"]"
Successfully moved 1 object(s).

➜  common git:(dev) ✗ terraform state list                                                                                                
aws_acm_certificate.pingping2_shop
aws_acm_certificate.pingping2_shop-virginia
aws_acm_certificate_validation.pingping2_shop_validation
aws_acm_certificate_validation.pingping2_shop_validation-virginia
aws_route53_record.cname_pingping95_shop["test"]
aws_route53_record.cname_pingping95_shop["www"]
aws_route53_record.pingping2_shop_acm_cname["pingping2.shop"]
aws_route53_record.pingping2_shop_acm_cname["www.pingping2.shop"]
aws_route53_record.pingping2_shop_acm_cname-virginia["pingping2.shop"]     
aws_route53_record.pingping2_shop_acm_cname-virginia["test.pingping2.shop"]
aws_route53_zone.pingping2_shop
aws_s3_account_public_access_block.ftstate
aws_s3_bucket.tfstate

 

 

[3] 확인

형상이 정상적으로 변경되었으며, 별도의 리소스 교체(Destory → Apply) 없이 변경을 완료

 

 

 

 

반응형