Terraform 0.12로 업그레이드하는 방법
환경을 Terraform 0.12로 업데이트하는 것은 마음이 약한 사람을 위한 것이 아니지만 이 방법을 사용하면 덜 고통스러울 것입니다.
Terraform을 시작할 때 Terraform 버전 0.11을 사용했습니다. 일부 독자들이 지적했듯이 이 버전에는 몇 가지 중요한 기능이 부족하므로 이 기사에서는 Terraform을 더욱 기능이 풍부한 버전 0.12로 업데이트하는 방법을 설명하겠습니다.
검증된 기술을 계속 사용하려는 대규모 조직과 완고한 사용자를 포함하여 많은 사람들이 여전히 Terraform 0.11을 사용하고 있다는 사실에 놀랄 수도 있습니다. Terraform 0.11에서 0.12로 변환하는 것은 매우 복잡할 수 있습니다. 새로운 기능을 활용하고 싶지만 업데이트할 준비가 되지 않았다고 생각하는 경우 이 문서를 참조하면 변환을 더 쉽게 할 수 있습니다.
이 기사에서는 "시작하기" 기사의 코드와 tfenv 도구를 사용하여 동일한 머신에서 다양한 버전의 Terraform을 사용할 수 있습니다. 또한 여러분이 두 가지 버전의 Terraform(사용 중인 버전과 마이그레이션하려는 버전)과 일반적인 terraform 명령 사용 방법에 익숙하다고 가정하겠습니다.
버전 12에 필요한 코드 변경
버전 0.12에서는 작동하지 않는 일부 기능은 Terraform 버전 0.11에서 작동합니다. 다음은 이전 기사에서 사용한 코드의 예입니다.
resource "kubernetes_namespace" "1-minikube-namespace" {
metadata {
name = "my-first-terraform-namespace"
}
}한 독자가 지적했듯이 이 코드 블록은 최신 Terraform 작동 방식 변경으로 인해 버전 0.12에서 작동하지 않습니다. 이것은 간단한 예인데 좀 더 복잡해집니다. 다음은 프로덕션 환경에서 얼마나 많은 사항을 변경해야 하는지에 대한 몇 가지 예입니다.
새로운 Terraform에는 약간 다른 구문과 구조가 필요합니다. 우선 vars.tf 파일을 추가하세요.
variable "namespace" {
type = "string"
default = "helloworld"
}
variable "cluster" {
type = "string"
default = "minikube"
}그런 다음 main.tf 파일의 일부를 변경하여 새 vars.tf 파일을 통합합니다. Kubernetes 공급자는 이제 다음과 같습니다.
provider "kubernetes" {
config_context_cluster = "${var.cluster}"
}수정된 네임스페이스 리소스는 다음과 같습니다.
resource "kubernetes_namespace" "1-minikube-namespace" {
metadata {
name = "${var.namespace}"
}
}마지막으로 변경된 Helm 공급자는 다음과 같습니다.
provider "helm" {
kubernetes {
config_context_cluster = "${var.cluster}"
}
}조심하세요! 이러한 작은 변경 사항은 버전 간 전환 시 중요합니다.
변환 전 배포
계속 진행하기 전에 올바른 버전의 Terraform을 사용하도록 tfenv를 설정하세요.
jess@Athena:~/terraform_doc$ tfenv list
0.12.29
0.11.15-oci
jess@Athena:~/terraform_doc$ tfenv use 0.11.15-oci
Switching default version to v0.11.15-oci
Switching completed
jess@Athena:~/terraform_doc$ terraform --version
Terraform v0.11.15-oci
+ provider.helm v1.2.2
+ provider.kubernetes v1.11.2
Your version of Terraform is out of date! The latest version
is 0.xx.y. You can update by downloading from www.terraform.io/downloads.html(나처럼) 이전 Terraform 기사의 코드를 사용한 후 Terraform으로 다른 작업을 수행한 경우 모든 것을 재배포해야 합니다. 새롭고 깨끗한 클러스터를 시작하여 이 Terraform 배포를 위한 Minikube 클러스터를 설정합니다.
$ minikube delete
? Deleting "minikube" in kvm2 ...
? Removed all traces of the "minikube" cluster.
jess@Athena:~/terraform_doc$ minikube start
? minikube v1.14.0 on Ubuntu 18.04클러스터가 설정된 후 수정된 Terraform 코드를 배포할 수 있습니다. init 명령으로 시작합니다.
$ terraform init
Initializing provider plugins...
The following providers do not have any version constraints in configuration,
so the latest version was installed.
To prevent automatic upgrades to new major versions that may contain breaking
changes, it is recommended to add version = "..." constraints to the
corresponding provider blocks in configuration, with the constraint strings
suggested below.
* provider.helm: version = "~> 1.2"
* provider.kubernetes: version = "~> 1.11"
Terraform has been successfully initialized!
You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work. [...]다음으로 계획을 실행하세요.
$ terraform plan
Refreshing Terraform state in-memory prior to plan...
helm_release.local: Refreshing state... (ID: buildachart)
kubernetes_namespace.1-minikube-namespace: Refreshing state... (ID: my-first-terraform-namespace) [...]
Terraform will perform the following actions:
+ helm_release.local
id: <computed>
atomic: "false"
chart: "./buildachart"
cleanup_on_fail: "false"
create_namespace: "false"
dependency_update: "false"
disable_crd_hooks: "false"
disable_openapi_validation: "false"
[...]
+ kubernetes_namespace.1-minikube-namespace
id: <computed>
metadata.#: "1"
[...]
Note: You didn't specify an "-out" parameter to save this plan, so Terraform
can't guarantee that exactly these actions will be performed if
"terraform apply" is subsequently run.마지막으로 Terraform을 적용합니다.
$ terraform apply --auto-approve
helm_release.local: Refreshing state... (ID: buildachart)
kubernetes_namespace.1-minikube-namespace: Refreshing state... (ID: my-first-terraform-namespace)
kubernetes_namespace.1-minikube-namespace: Creating...
metadata.#: "" => "1"
metadata.0.generation: "" => "<computed>"
[...]
helm_release.local: Creating...
atomic: "" => "false"
chart: "" => "./buildachart"
cleanup_on_fail: "" => "false"
create_namespace: "" => "false"
[...]
version: "" => "0.1.0"
wait: "" => "true"
kubernetes_namespace.1-minikube-namespace: Creation complete after 1s (ID: helloworld)
helm_release.local: Still creating... (10s elapsed)
helm_release.local: Creation complete after 13s (ID: buildachart)
Apply complete! Resources: 2 added, 0 changed, 0 destroyed.
이제 Terraform 상태의 로컬 백업이 생겼습니다.
$ ls -lrt
drwxr-xr-x 6 jess jess 4096 May 16 14:15 buildachart
-rw-r--r-- 1 jess jess 363 Oct 24 13:06 main.tf
-rw-rw-r-- 1 jess jess 132 Oct 24 13:17 vars.tf
-rw-rw-r-- 1 jess jess 3897 Oct 24 13:20 terraform.tfstate.backup
-rw-rw-r-- 1 jess jess 3821 Oct 24 13:21 terraform.tfstateTerraform 0.11에서 0.12로 변환
Terraform 0.11을 사용하여 모든 것이 배포되면 새 프로덕션 클러스터에 있는 내용을 손상시키지 않고 변환 프로세스를 진행해야 합니다. 먼저 tfenv를 사용하여 Terraform 버전을 0.12로 변경합니다.
$ tfenv list
0.12.29
* 0.11.15-oci (set by /home/jess/.tfenv/version)
jess@Athena:~/terraform_doc$ tfenv use 0.12.29
Switching default version to v0.12.29
Switching completed
jess@Athena:~/terraform_doc$ terraform --version
Terraform v0.12.29
+ provider.helm v1.2.2
+ provider.kubernetes v1.11.2이제 Terraform 0.12를 사용하고 있으므로 변환할 준비가 되었습니다. 다행히 Terraform 명령 목록의 다음 코드 조각에 표시된 것처럼 Terraform에는 이를 위한 내장 명령이 있습니다.
All other commands:
0.12upgrade Rewrites pre-0.12 module source code for v0.12upgrade 명령을 테스트하여 무엇이 다시 작성되는지 확인한 다음 yes를 입력하여 업그레이드를 수행하십시오.
$ terraform 0.12upgrade
This command will rewrite the configuration files in the given directory so
that they use the new syntax features from Terraform v0.12, and will identify
any constructs that may need to be adjusted for correct operation with
Terraform v0.12.
[...]
Would you like to upgrade the module in the current directory?
Only 'yes' will be accepted to confirm.
Enter a value: yes
-----------------------------------------------------------------------------
Upgrade complete!
The configuration files were upgraded successfully. Use your version control
system to review the proposed changes, make any necessary adjustments, and
then commit.잘 된 것 같습니다. 일부 내용을 다시 작성했을 수도 있지만 Terraform 파일로 변경해야 하는 모든 내용을 설명하지는 않습니다. 그러나 파일 내에 메모를 작성하는 데는 훌륭한 역할을 합니다. vars.tf 파일에 대한 변경 사항은 다음과 같습니다.
variable "namespace" {
type = string
default = "helloworld"
}
variable "cluster" {
type = string
default = "minikube"
}type은 단어 string 주위의 따옴표를 제거하도록 변경되었습니다(Terraform 파일의 인용은 시간이 지남에 따라 변경되었습니다). 다음으로 main.tf 파일을 살펴보세요.
provider "kubernetes" {
config_context_cluster = var.cluster
}
# TF-UPGRADE-TODO: In Terraform v0.11 and earlier, it was possible to begin a
# resource name with a number, but it is no longer possible in Terraform v0.12.
#
# Rename the resource and run `terraform state mv` to apply the rename in the
# state. Detailed information on the `state move` command can be found in the
# documentation online: https://www.terraform.io/docs/commands/state/mv.html
resource "kubernetes_namespace" "1-minikube-namespace" {
metadata {
name = var.namespace
}
}
provider "helm" {
kubernetes {
config_context_cluster = var.cluster
}
}
resource "helm_release" "local" {
name = "buildachart"
chart = "./buildachart"
}여기서도 따옴표가 변경되었으며 변수는 더 이상 $ {} 문자로 묶이지 않습니다. 가장 큰 섹션은 버전 0.12에서 허용되기 위해 리소스 이름을 변경해야 하는 사항을 보여주기 위해 코드에 변환 명령이 배치된 큰 TODO 메모입니다. 더 나아가 이 문제를 해결하는 방법과 실행해야 하는 명령에 대해 설명합니다. 다른 주요 변경 사항은 새로운 versions.tf 파일과 새로운 백업 파일입니다.
$ ls -lrt
drwxr-xr-x 6 jess jess 4096 May 16 14:15 buildachart
-rw-rw-r-- 1 jess jess 3897 Oct 24 13:20 terraform.tfstate.backup
-rw-r--r-- 1 jess jess 46 Oct 24 13:28 versions.tf
-rw-rw-r-- 1 jess jess 140 Oct 24 13:55 vars.tf
-rw-r--r-- 1 jess jess 369 Oct 24 13:56 main.tf
-rw-rw-r-- 1 jess jess 3821 Oct 24 13:56 terraform.tfstate.1603562212.backup
-rw-rw-r-- 1 jess jess 3827 Oct 24 13:56 terraform.tfstate프로덕션 클러스터를 업데이트하려면 이 버전에 더 적합한 다른 이름으로 시작하세요.
resource "kubernetes_namespace" "upgrade-minikube-namespace" {
metadata {
name = var.namespace
}
}거친 가장자리 다듬기
변경 후에는 terraform state mv 명령을 실행해야 합니다(대형 TODO 참고에서 참조). 하지만 먼저 state list를 실행하여 작업 중인 항목을 확인하세요.
$ terraform state list
helm_release.local
Kubernetes_namespace.1-minikube-namespace네임스페이스는 여전히 1-minikube-namespace 상태로 설정되어 있으며, 이것이 이동해야 하는 상태입니다. 새 리소스 이름과 기존 리소스 이름이 있는지 확인한 다음 terraform state mv 명령을 실행하면 됩니다. 하지만 그 전에 tfenv를 사용하여 0.11로 다시 전환하여 이러한 변경을 수행해야 합니다. 이는 Terraform 0.11을 사용하여 배포되었고 0.12는 (TODO에 명시된 대로) 리소스 이름 시작 부분의 숫자를 인식하지 못하기 때문입니다. 리소스 이름 변경을 제외하고 Terraform 업그레이드에서 수행한 모든 코드 변경 사항을 되돌려야 합니다.
main.tf
provider "kubernetes" {
config_context_cluster = "${var.cluster}"
}
resource "kubernetes_namespace" "upgrade-minikube-namespace" {
metadata {
name = "${var.namespace}"
}
}
provider "helm" {
kubernetes {
config_context_cluster = "${var.cluster}"
}
}
resource "helm_release" "local" {
name = "buildachart"
chart = "./buildachart"
}Vars.tf
variable "namespace" {
type = "string"
default = "helloworld"
}
variable "cluster" {
type = "string"
default = "minikube"
}변경 사항이 다시 적용되면 tfenv를 버전 0.11로 다시 전환하고 state mv 명령을 실행합니다.
$ tfenv use 0.11.15-oci
Switching default version to v0.11.15-oci
Switching completed
jess@Athena:~/terraform_doc$ terraform state mv 'kubernetes_namespace.1-minikube-namespace' 'kubernetes_namespace.upgrade-minikube-namespace'
Moved kubernetes_namespace.1-minikube-namespace to kubernetes_namespace.upgrade-minikube-namespace최종 단계
이 작업이 완료된 후 tfenv를 버전 0.12로 다시 변경한 다음 versions.tf 파일을 제거하여 변환이 완료되었는지 확인하세요. 이 파일을 제거하지 않으면 다음과 같은 오류 메시지가 표시됩니다.
$ terraform 0.12upgrade
Error: Module already upgraded
on versions.tf line 3, in terraform:
3: required_version = ">= 0.12"
The module in directory . has a version constraint that suggests it has
already been upgraded for v0.12. If this is incorrect, either remove this
constraint or override this heuristic with the -force argument. Upgrading a
module that was already upgraded may change the meaning of that module.파일을 제거하고 다음 명령을 실행하십시오.
$ terraform 0.12upgrade
This command will rewrite the configuration files in the given directory so
that they use the new syntax features from Terraform v0.12, and will identify
any constructs that may need to be adjusted for correct operation with
Terraform v0.12. [...]
Would you like to upgrade the module in the current directory?
Enter a value: yes
-----------------------------------------------------------------------------
Upgrade complete!다른 배포로 변환 테스트
init, plan 및 apply 명령을 다시 실행하여 새 변환을 테스트하세요(이 스니펫에서는 출력 부분을 생략했습니다).
$ terraform init
Initializing the backend...
Initializing provider plugins...
[...]
Terraform has been successfully initialized!
$ terraform plan
Refreshing Terraform state in-memory prior to plan...
The refreshed state will be used to calculate this plan, but will not be
persisted to local or remote state storage.
helm_release.local: Refreshing state... [id=buildachart]
kubernetes_namespace.upgrade-minikube-namespace: Refreshing state... [id=helloworld]
------------------------------------------------------------------------
No changes. Infrastructure is up-to-date
$ terraform apply
helm_release.local: Refreshing state... [id=buildachart]
kubernetes_namespace.upgrade-minikube-namespace: Refreshing state... [id=helloworld]
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.여기서 볼 수 있듯이 일단 모든 것이 사전 구성되고 변환 중에 상태가 이동 및 재적용되면 인프라가 제자리에 있기 때문에 다른 변경 사항은 발생하지 않습니다.
마지막 생각들
특히 라이브 프로덕션 환경에서는 코드 및 애플리케이션 업그레이드가 어렵습니다. 이는 Terraform 0.11에서 0.12로 변환할 때 매우 그렇습니다. 저는 이 작업을 대규모로 수행했으며 2주에 걸친 광범위한 계획이 필요했습니다.
프로덕션 환경에서 이 작업을 수행하려면 다음을 확인하세요.
- 앞에 숫자가 붙은 리소스나 모듈을 제거하는 것부터 시작하세요.
- 업그레이드를 실행하기 전에 상태를 이동하십시오.
- 안전을 위해 업그레이드된 Terraform 파일을 포크된 저장소에 보관하세요.
이 글이 여러분이 저보다 더 빠르고 쉽게 앞으로 나아가는 데 도움이 되기를 바랍니다.