Terraform은 Hashicorp사에서 제공하는 IaC(Infrastructure as Code) 구현을 위한 인프라 배포 도구입니다.
현재 우리는 Terraform의 인프라 정의 코드를 사용해 다양한 환경에서 VM Instance, Disk, Storage 등의 인프라 리소스를 코드로써 배포할 수 있게 되었습니다.
이는 Google Cloud Platform 환경도 마찬가지인데요.
Terraform은 코드를 GCP의 API와 상호작용 가능하게 해주는 Plugin인 Google Provider를 공식적으로 제공하고 있기 때문에 Google Cloud Platform의 인프라 또한 코드로 배포할 수 있습니다.
GCP에서 Terraform을 통해 배포할 수 있는 인프라 리소스의 대표는 VM 서비스인 Compute Engine이존재합니다.
하지만 Compute Instance는 현재 API의 한계로 Terraform을 통해 배포할시 Boot Disk의 구성을 변경하면 Instance를 삭제 후 재생성하는 Replace가 일어나게 되는데요.
본래 GCP에서는 웹 콘솔, CLI 등 기존 방법을 이용했다면 재생성 없이 Update만으로 Boot disk 구성 변경이 가능했기 때문에 이같은 동작은 Compute Instance 원래의 기능을 온전히 이용하지 못하게 합니다.
이번 포스팅 시간에는 Google Cloud Platform에서 Terraform으로 Replace없는 VM Instance의 Boot Disk 구성 방법을 알아보겠습니다.
1. Terraform으로 Compute Engine의 Boot disk를 구성할 시 발생하는 문제점
위에서 기술했듯이 현재 Terraform으로 Compute Engine 인스턴스의 Boot Disk 설정을 변경하게 되면(ex : 용량 확장) 디스크의 용량 확장만 일어나는 Update 동작이 아닌, 인스턴스 째로 재생성을 하는 Replace 동작이 일어나게 됩니다.
하지만 Google Cloud Platform에서 Boot disk 역할을 하는 Persistent Disk는 디스크의 재생성 및 다운타임 없이 용량 확장을 지원하고 있는데요.
이는 Terraform을 사용하면 다운타임없는 용량 확장이라는 강력한 기능을 사용하지 못한다는 것이기 때문에, Compute Engine 인스턴스에서 원활한 서비스 제공이 어렵다는 이슈가 존재합니다.
먼저 Google Cloud에서 제공하는 방법을 통해 Compute Engine 인스턴스 Boot disk의 용량 확장을 수행할 시 어떤 동작을 하는지 살펴보겠습니다.
1-1. Google Cloud 웹 콘솔에서 디스크 사이즈 확장 시 동작
현재 제 Google Cloud 프로젝트에는 테스트를 위한 Compute Engine 인스턴스를 하나 생성해놓은 상태입니다.
해당 인스턴스는 Boot Disk로 Public Image로 제공되는 Debian 11 OS를 사용했으며, 10GB 사이즈로 구성한 상태입니다.
인스턴스와 함께 Boot Disk로 사용되는 Persistent Disk가 하나 생성된 것을 확인할 수 있습니다. 인스턴스 생성 시에 설정한 것처럼 Debian 11 OS에 10GB 사이즈 구성을 가진 디스크입니다.
이러한 상황에서 인스턴스의 데이터 사용량이 늘어 10GB의 디스크 사이즈로는 부족한 상황에 처했다는 시나리오를 가정하겠습니다.
부족한 디스크 사이즈를 충당하기 위해, 새 디스크를 하나 더 붙이는 대신 Google Cloud는 기존 디스크의 다운타임 없는 확장 기능을 사용할 수 있습니다.
생성한 디스크의 Edit 페이지로 진입하면 위와 같이 디스크의 사이즈를 변경할 수 있도록 Property를 제공하고 있습니다.
디스크 용량의 확장을 위해 위와 같이 사이즈를 50으로 변경한 뒤 설정을 저장하겠습니다.
설정을 저장하면 곧바로 인스턴스의 Boot Disk 사이즈가 변경된 것을 확인할 수 있습니다. 이 과정에서 인스턴스는 다운 상태로 진입하지 않았습니다.
인스턴스로 SSH접속한 뒤 df 명령어로 현재 파티션의 상태를 확인하면, Root Partition이 9.7G, 대략 10G의 용량을 보유하고 있음을 알 수 있습니다.
이어서 lsblk 명령어로 디스크의 용량을 확인하면 현재 Boot Disk의 총 용량은 50G로 다운타임 없이 디스크 용량의 증가가 이루어진 것을 확인할 수 있습니다.
확장된 50GB를 Root Partition에 할당하기 위해 parted 명령어를 통해 파티션을 재할당해줍니다.
이후 resize2fs 명령어로 Root Partition의 파일시스템을 확장하면 49G, 대략 50GB의 용량을 사용할 수 있게 됩니다.
지금까지가 Google Cloud에서 제공하는 방법으로 Boot DIsk 사이즈의 확장을 수행한 과정입니다.
보시다시피 디스크의 확장이 일어나는 동안은 인스턴스의 다운타임이 발생하지 않았으며, 인스턴스의 재생성 또한 수행되지 않았습니다.
이 같은 동작을 이용해 인스턴스의 수행성을 보장하면서 디스크 용량의 확장을 이용할 수 있습니다.
1-2. Terraform을 이용한 디스크 확장 시 동작
Terraform을 이용해 인스턴스를 생성하고자 한다면 공식적으로 제공하는 Google Provider를 통해 Compute Engine 인스턴스를 생성할 수 있습니다.
아래 Terraform 코드로 웹 콘솔에서 생성한 것과 동일한 Compute Engine 인스턴스를 생성할 수 있습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
resource "google_compute_instance" "default" {
project = "PROJECT_ID" # Replace this with your project ID in quotes
zone = "asia-northeast3-a"
name = "disk-test-instance"
machine_type = "e2-medium"
boot_disk {
initialize_params {
image = "debian-cloud/debian-10"
size = 10
}
}
network_interface {
subnetwork = "default"
subnetwork_project = "PROJECT_ID"
}
can_ip_forward = true
}
terraform {
required_version = ">= 0.13"
required_providers {
google = {
source = "hashicorp/google"
version = ">= 3.53, < 5.0"
}
}
|
cs |
위 코드를 기반으로 "terraform plan" 명령어를 입력해 변경될 Google Cloud 리소스 상태를 확인해보겠습니다.
"terraform plan" 명령어 실행 시, Google Cloud 인프라에 Compute Engine 인스턴스가 하나 생성되며, 인스턴스에 Boot Disk가 추가될 것임을 확인할 수 있습니다.
이후 "terraform apply" 명령어를 실행해 실제 인프라에 변경 사항을 적용합니다.
웹 콘솔에서 실제 Compute Engine 인스턴스가 하나 생성되어 있는 것을 확인할 수 있습니다.
인스턴스의 Boot Disk 또한 Terraform 코드에서 지정한 debian-10 OS와 10GB 용량으로 생성되어 있는 것을 확인할 수 있습니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
|
resource "google_compute_instance" "default" {
project = "PROJECT_ID" # Replace this with your project ID in quotes
zone = "asia-northeast3-a"
name = "disk-test-instance"
machine_type = "e2-medium"
boot_disk {
initialize_params {
image = "debian-cloud/debian-10"
size = 50 # Disk Size Increase
}
}
network_interface {
subnetwork = "default"
subnetwork_project = "PROJECT_ID"
}
can_ip_forward = true
}
terraform {
required_version = ">= 0.13"
required_providers {
google = {
source = "hashicorp/google"
version = ">= 3.53, < 5.0"
}
}
|
cs |
이제 웹 콘솔과 동일한 시나리오로 Boot Disk의 사이즈를 확장해보겠습니다.
Terraform 코드에서 google_compute_instance 리소스의 "boot_disk.initialize_params.size" attribute를 10에서 50으로 변경합니다.
변경된 코드를 기반으로 "terraform plan" 명령어를 실행하면 위와 같이 Compute Engine 인스턴스 리소스가 replaced, 즉 삭제 후 재생성될 것임을 알려줍니다.
명세를 살펴보면 replace를 유발하는 원인이 코드를 변경한 "boot_disk.initialize_params.size" attribute에 있음을 알 수 있습니다.
"terraform apply" 명령어로 실제 리소스에 명세를 반영하면 위와 같이 인스턴스 삭제 작업이 일어나고 이후 다시 재생성되는 것을 확인할 수 있습니다. 인스턴스가 삭제된다는 것은 즉 다운타임이 발생한다는 것입니다.
즉 terraform을 통한 Boot Disk 사이즈 변경 작업은 기존 Google Cloud에서 지원하는 작업과 달리 인스턴스를 삭제 후 재생성하기 때문에 다운타임없는 변경을 수행하지 않습니다.
2. Terraform으로 Compute Engine의 Boot disk를 구성할 시 Replace가 발생하는 원인
위에서 Terraform을 이용한 인스턴스 Boot Disk 변경 작업은 Replace를 수행해 다운타임을 유발한다는 것을 확인했습니다.
그렇다면 왜 기존 Google Cloud에서 수행하는 작업과 달리 Terraform에서 수행하는 작업은 인스턴스의 Replace를 유발할까요?
Terraform Google Provider 깃헙 이슈 페이지에 동일한 의문을 가진 글이 있어 가져왔습니다.
https://github.com/hashicorp/terraform-provider-google/issues/6087
이슈에 달린 코멘트들의 내용을 종합해보면 인스턴스의 Disk size 변경시 Replace가 일어나는 원인은 다음과 같습니다.
1. Boot Disk의 사이즈는 google_compute_instance 리소스의 "initialize_params" attribute에 속해있으며, Boot disk의 생성 시 가지게 될 속성을 결정한다.
2. "initialize_params"는 Boot disk의 생성 시 가지게 될 속성을 결정하기 때문에 이를 변경하면 Boot disk를 재생성하는 동작을 수행한다.
3. Boot Disk의 재생성은 인스턴스의 재생성을 유발하기 때문에 인스턴스의 Replace 작업이 유발되어 다운타임이 발생한다.
4. 웹 콘솔에서 수행할 수 있는 다운타임 없는 Boot disk 사이즈 변경 작업은 Compute Engine API가 아닌 Disk API이기 때문에 Compute Engine API만을 Call하는 google_compute_instance 리소스는 근원적으로 다운타임 없는 사이즈 변경이 불가능하다.
정리하자면 우리가 원하는 다운타임 없는 Boot Disk 사이즈 변경은 Disk API를 통해서만 가능하고, 인스턴스를 관할하는 Compute Engine API는 initialize_params을 통해 Boot DIsk 생성 시 속성만을 지정할 수 있기 때문에 Replace 작업이 일어나는 것입니다.
3. Terraform으로 Downtime없이 Compute Engine의 Boot disk 사이즈 변경 방법
위에서 확인할 수 있듯이, 현재 Terraform의 기본적인 동작으로는 인스턴스 Boot Disk의 사이즈 변경을 다운타임 없이 수행할 수 없습니다.
하지만 이를 해결하기 위한 방법이 존재합니다.
문제의 근본적인 원인은 Compute Engine API를 통해 Boot disk 속성을 변경하는 것과 Disk API를 통해 Boot disk 속성을 변경하는 것이 분리되어 있고, Disk API를 통해서만 Replace없는 사이즈 변경이 가능하다는 것이기 때문에,
VM 인스턴스 생성과 Boot Disk 생성을 분리해 각각 Compute Engine API와 Disk API가 작업을 관할할 수 있도록 하는 것입니다.
아래는 이 문제를 해결한 Compute Engine VM 인스턴스 모듈의 Instance 생성 부분 코드입니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
resource "google_compute_instance" "instance" {
...
###########
## Disks ##
###########
boot_disk {
auto_delete = var.boot_disk.auto_delete
device_name = var.boot_disk.device_name
source = var.boot_disk.source_type == "EXISTING" ? var.boot_disk.source : google_compute_disk.boot_disk.0.name
}
...
|
cs |
위 코드와 기존 코드의 차이점은 boot_disk의 "initialize_params" Attribue를 통해 Boot Disk를 생성하지 않는다는 것입니다.
"initialize_params" Attribute는 Boot Disk의 생성에 관련된 속성이므로 디스크 사이즈와 같은 값 변경 시 Replace 작업을 수행합니다.
이같은 동작을 방지하기 위해 "initialize_params"를 통한 Boot Disk 생성 대신, 별개의 Disk를 새로 생성해 이를 Boot Disk로 사용하는 방법을 택했습니다.
"boot_disk.source" Attribute는 "boot_disk.source_type" 변수에 EXISTING 값이 할당되어 있으면 기존에 존재했던 Disk를, 그 외의 값이 할당되어 있으면(ex: IMAGE) 지정한 이미지, 스냅샷를 이용해 새로운 Disk를 생성한 뒤 Boot Disk로 사용하도록 되어 있습니다.
아래는 같은 모듈의 Disk 생성을 담당하는 부분 코드입니다.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
resource "google_compute_disk" "boot_disk" { ## Boot disk only can attach zonal persistent disk
count = var.create_template ? 0 : (var.boot_disk.source_type == "SNAPSHOT" || var.boot_disk.source_type == "IMAGE") ? 1 : 0
project = var.project_id
zone = var.zone
name = "disk-boot-${var.project_id}-${var.instance_name}" # "disk-boot" prefix for boot disk, "disk-" for attached disk
size = var.boot_disk.size
type = var.boot_disk.type
image = var.boot_disk.image
snapshot = try(var.boot_disk.source, null)
labels = try(var.boot_disk.labels, null)
dynamic "disk_encryption_key" {
for_each = var.boot_disk.disk_encryption_key_raw != null || var.boot_disk.kms_key_self_link != null ? [""] : []
content {
raw_key = try(var.boot_disk.disk_encryption_key_raw, null)
kms_key_self_link = try(var.boot_disk.kms_key_self_link, null)
}
}
}
|
cs |
위 코드에서 google_compute_disk 리소스는 "boot_disk_source_type" 변수에 EXISTING이 아닌 값, 즉 SNAPSHOT이나 IMAGE가 할당되었을 경우 새 Disk를 생성합니다.
이 리소스에서 Boot Disk로 사용할 Disk의 사이즈 또한 지정할 수 있습니다.
google_compute_disk 리소스는 Disk API를 사용하기 때문에 이 리소스를 통해서 사이즈를 변경할 경우, 웹 콘솔에서 수행했던 것과 같은 다운타임 없는 사이즈 변경이 가능해집니다.
이렇게 Compute Engine API와 Disk API를 사용하는 리소스를 분리함으로써 다운타임 없는 디스크 사이즈 변경 작업을 구현할 수 있었습니다.
이제 이 모듈을 사용해서 Compute Engine 인스턴스의 Boot Disk 사이즈 변경 작업을 수행했을 시 원하는 결과가 나올지 확인해보겠습니다.
terraform.tfvars에 변수에 할당할 값을 입력합니다. Boot Disk의 사이즈를 10으로 설정합니다.
"terraform plan" 명령어로 수행될 작업을 확인했을 시, 위와 같이 Compute Engine 인스턴스 하나와 Disk 하나가 별개로 생성되는 것을 확인할 수 있습니다.
이는 기존에는 Compute Engine 인스턴스 리소스의 일부분으로 Boot Disk가 생성되는 것과는 다른 동작입니다.
"terraform apply" 명령어로 리소스를 생성한 뒤, 생성된 인스턴스를 확인해보면 10GB 용량의 Boot Disk가 구성되어 있는 것을 확인할 수 있습니다.
이제 Boot Disk의 사이즈 확장을 위해 size 값을 10에서 50으로 늘려 코드를 적용해보겠습니다.
"terraform plan"으로 적용될 명세를 확인해보니 이번에는 Terraform이 인스턴스의 Replace 없이 디스크 사이즈의 변경만 Update할 것임을 알 수 있습니다.
코드를 적용하면 Terraform은 디스크 사이즈의 Update 작업만을 수행했기 때문에 인스턴스가 재생성되지 않은채로 Boot Disk의 사이즈가 50GB로 확장된 것을 확인할 수 있습니다.
이는 모듈이 Compute Engine API가 아닌 Disk API를 통해 디스크 사이즈의 확장 작업을 수행해 인스턴스에게 이 작업의 영향을 끼치지 않았기 때문에 가능한 동작입니다.
이렇게 Compute Engine 인스턴스의 Boot DIsk를 다운타임 없이 확장할 수 있습니다.
이 구성의 중요한 점은 Boot Disk를 Compute Engine API의 작업으로 생성하는 것이 아니라, Disk API로 생성하는 것입니다.
4. 마무리
지금까지 Terraform을 통해 인스턴스의 Boot Disk 사이즈 확장을 다운타임없이 수행하는 방법에 대해 알아봤습니다.
우리는 기존 Terraform을 이용해 Boot Disk를 구성할 시 사이즈의 변경이 Replace를 유발하는 것은 Compute Engine API의 Initialize_params 속성의 한계라는 것을 확인했습니다.
그리고 이를 극복하기 위해 인스턴스와 디스크를 별개로 생성해 Disk API로 사이즈를 변경하는 것으로 인스턴스의 재생성을 회피할 수 있다는 것도 확인했습니다.
이 글을 보시는 모든 분들이 Terraform으로 Google Cloud 인프라를 구성할때 도움을 받을 수 있기를 바랍니다.
'Devops' 카테고리의 다른 글
컨테이너 빌드 도구 선택을 위한 특성 및 성능 비교 (Kaniko, Buildah, Buildkit) (5) | 2023.03.26 |
---|---|
Tekton 사용해보기 (5) Tekton에 Human Approval 기능을 추가해보자 (0) | 2023.03.18 |
Tekton 사용해보기 (4) GCP Terraform 인프라를 Validation하는 파이프라인 구축하기 (0) | 2022.12.31 |
Tekton 사용해보기 (3) Tekton Dashboard에 OIDC를 기반으로 RBAC 적용하기 (0) | 2022.11.13 |
Tekton 사용해보기 (2) Tekton으로 인프라를 자동 배포하는 Terraform Pipeline을 만들어보자 (2) | 2022.11.06 |