본 포스트는 2024년 Google Study Jam을 공부하면서 개인적으로 내용을 정리한 포스트 입니다.
Infrastructure as Code with Terraform - Task 1. Build infrastructure
다음 명령어들로 Terraform을 위한 기본 세팅을 한다.
touch main.tf
# main.tf code
terraform {
required_providers {
google = {
source = "hashicorp/google"
version = "3.5.0"
}
}
}
provider "google" {
project = "PROJECT ID"
region = "REGION"
zone = "ZONE"
}
resource "google_compute_network" "vpc_network" {
name = "terraform-network"
}
terraform {} 블록은 Terraform이 어떤 제공업체를 Terraform Registry에서 다운로드해야 하는지를 알기 위해 필요하다.
위의 구성에서 Google 제공업체의 소스는 hashicorp/google로 정의되어 있으며, 이는registry.terraform.io/hashicorp/google의 약식 표현이다.
이 블록을 통해 Terraform은 필요한 모듈과 리소스를 올바르게 가져올 수 있다.
required_providers 블록에서 각 제공업체에 버전을 지정할 수도 있다. 버전 인자는 선택 사항이지만 권장된다. 이는 제공업체를 특정 버전이나 버전 범위로 제한하여, 잠재적으로 파괴적인 변경 사항이 포함된 새로운 제공업체가 다운로드되는 것을 방지하는 데 사용된다. 버전이 지정되지 않으면, Terraform은 초기화 시 가장 최신의 제공업체를 자동으로 다운로드한다.
자세한 내용은 HashiCorp Terraform 웹사이트의 제공업체 요구(Provider Requirements) 사항을 참조.
Provider 블록은 특정 Provider를 구성하는데 사용된다. Provider는 리소스를 생성하고 관리하는 역할을 한다. 여러 Provider의 리소스를 관리하는 Terraform 구성에서는 여러 개의 Provider 블록을 정의할 수 있습니다. 이를 통해 다양한 Provider의 리소스를 효율적으로 관리할 수 있다.
Terraform을 초기화하고 적용한다.
terraform init
terraform apply
VPC network에서 terraform-network가 생성되었는지 확인한다.
현재 상태를 검사한다.
terraform show
Infrastructure as Code with Terraform - Task 2. Change infrastructure
인프라를 수정하기 위해 main.tf를 코드를 수정한다.
resource "google_compute_instance" "vm_instance" {
name = "terraform-instance"
machine_type = "e2-micro"
boot_disk {
initialize_params {
image = "debian-cloud/debian-11"
}
}
network_interface {
network = google_compute_network.vpc_network.name
access_config {
}
}
}
수정된 Terraform code를 적용한다.
terraform apply
리소스 수정을 위해 Terraform Code의 resource 블록을 수정하고 적용한다.
# main.tf
resource "google_compute_instance" "vm_instance" {
name = "terraform-instance"
machine_type = "e2-micro"
tags = ["web", "dev"]
# ...
}
# bash
terraform apply
Destructive Changes는 기존 리소스를 변경하는 것으로 변경할 수 없는 변경이다. 이 경우는 클라우드 공급자가 구성에 설명된 방식으로 업데이트를 지원하지 않기 때문에 직접 변경해야 한다.
boot_disk 블록을 변경한다.
# main.tf
boot_disk {
initialize_params {
image = "cos-cloud/cos-stable"
}
}
# bash
terraform apply
접두사 -/+는 Terraform이 리소스를 업데이트하는 대신 파괴하고 재생성할 것임을 의미한다.
일부 속성은 인플레이스에서 업데이트할 수 있지만(이는 ~ 접두사로 표시됨), 인스턴스의 부팅 디스크 이미지를 변경하는 것은 해당 인스턴스를 재생성해야 한다.
Terraform과 Google Cloud 제공업체가 이러한 세부 사항을 처리하며, 실행 계획은 Terraform이 수행할 작업을 명확하게 보여준다.
또한 실행 계획은 디스크 이미지 변경이 인스턴스를 교체해야 하는 이유임을 보여준다.
이 정보를 활용하여 일부 상황에서는 파괴/생성 업데이트를 피할 수 있도록 변경 사항을 조정할 수 있다.
Terraform은 실행 계획을 진행하기 전에 승인을 요청한다.
계획된 단계를 실행하려면 "yes"라고 답하면 된다. 실행 계획에 따라 Terraform은 기존 인스턴스를 먼저 파괴한 다음 그 자리에서 새 인스턴스를 생성했다.
terraform show 명령을 다시 사용하여 이 인스턴스와 관련된 새로운 값을 확인할 수 있다.
terraform destroy를 통해 리소스를 제거할 수 있다. 이는 terraform apply와 유사하게 동작하고 모든 리소스가 구성에서 모두 제거된 것처럼 동작한다.
terraform destroy
apply와 마찬가지로 yes를 입력해야 진행된다.
terraform apply와 마찬가지로, Terraform은 리소스를 파괴하는 순서를 결정한다. Google Cloud에서는 VPC Network 내에 리소스가 남아 있는 경우 해당 네트워크를 삭제할 수 없으므로, Terraform은 인스턴스가 파괴된 후에 네트워크를 삭제한다. 작업을 수행할 때 Terraform은 의존성 그래프를 생성하여 올바른 작업 순서를 결정한다. 여러 리소스가 있는 복잡한 경우에는, Terraform이 안전할 때 작업을 병렬로 수행한다.
Infrastructure as Code with Terraform - Task 3. Create resource dependencies
리소스를 다시 생성한다.
terraform apply
main.tf를 수정해서 VM instance에 static IP를 추가한다.
resource "google_compute_address" "vm_static_ip" {
name = "terraform-static-ip"
}
실행 계획을 확인한다.
terraform plan
main.tf의 network_inferface를 업데이트한다.
network_interface {
network = google_compute_network.vpc_network.self_link
access_config {
nat_ip = google_compute_address.vm_static_ip.address
}
}
access_config {} 블록은 여러 개의 선택적 인자를 가질 수 있으며, 이 경우 nat_ip를 정적 IP 주소로 설정하게 된다. Terraform이 이 구성을 읽을 때 다음과 같은 작업을 수행한다:
- vm_static_ip가 vm_instance보다 먼저 생성되도록 보장한다.
- vm_static_ip의 속성을 상태(state)에 저장한다.
- nat_ip를 vm_static_ip.address 속성의 값으로 설정한다.
이 과정을 통해 Terraform은 리소스 간의 의존성을 관리하고 올바른 설정을 적용한다.
실행 계획을 다시 확인하고 저장한다.
terraform plan -out static_ip
저장한 실행 계획을 적용한다.
terraform apply "static_ip"
main.tf에 다음을 추가하여 버킷에 대한 명시적 종속성이 있는 Cloud Storage 버킷과 인스턴스를 추가한다.
# New resource for the storage bucket our application will use.
resource "google_storage_bucket" "example_bucket" {
name = "<UNIQUE-BUCKET-NAME>"
location = "US"
website {
main_page_suffix = "index.html"
not_found_page = "404.html"
}
}
# Create a new instance that uses the bucket
resource "google_compute_instance" "another_instance" {
# Tells Terraform that this VM instance must be created only after the
# storage bucket has been created.
depends_on = [google_storage_bucket.example_bucket]
name = "terraform-instance-2"
machine_type = "e2-micro"
boot_disk {
initialize_params {
image = "cos-cloud/cos-stable"
}
}
network_interface {
network = google_compute_network.vpc_network.self_link
access_config {
}
}
}
Terraform의 실행 계획을 확인하고 적용한다.
terraform plan
terraform apply
Infrastructure as Code with Terraform - Task 4. Provision infrastructure
Google Cloud에서는 고객이 자신만의 맞춤 운영 체제 이미지를 관리할 수 있다. 이는 Terraform으로 프로비저닝하는 인스턴스가 필요에 맞게 사전 구성되도록 보장하는 좋은 방법이다. Packer는 이를 위한 완벽한 도구로, Google Cloud용 빌더를 포함하고 있다. Packer를 사용하면 원하는 소프트웨어와 설정을 포함한 이미지를 쉽게 생성할 수 있다.
terraform 파일에 provisioner를 정의하는 리소스 블록을 추가한다.
resource "google_compute_instance" "vm_instance" {
name = "terraform-instance"
machine_type = "e2-micro"
tags = ["web", "dev"]
provisioner "local-exec" {
command = "echo ${google_compute_instance.vm_instance.name}: ${google_compute_instance.vm_instance.network_interface[0].access_config[0].nat_ip} >> ip_address.txt"
}
# ...
}
Terraform은 여러가지 provisioner를 지원하지만 여기서는 local-exec를 사용했다.
Terraform을 적용한다.
terraform apply
"Terraform found nothing to do"의 경우 로컬 머신에 ip_address.txt 파일이 없을 것이다.
Terraform은 프로비저너를 다른 인자와 다르게 처리한다. 프로비저너는 리소스가 생성될 때만 실행되지만, 프로비저너를 추가한다고 해서 해당 리소스를 파괴하고 재생성해야 하는 것은 아니다. 즉, 프로비저너는 리소스의 상태에 영향을 주지 않고, 리소스 생성 시에만 특정 작업을 수행하게 된다.
instance를 재생성
terraform taint google_compute_instance.vm_instance
tainted resource는 다음 apply시 삭제되고 재생성된다.
Terraform을 적용한다.
terraform apply
ip_address.txt 파일을 확인하여 제대로 되었는지 확인한다.
Failed provisioners and tainted resources
- 리소스가 성공적으로 생성되었지만 프로비저닝 단계에서 실패하면, Terraform은 오류를 발생시키고 해당 리소스를 오염된(tainted) 것으로 표시한다. 오염된 리소스는 여전히 존재하지만, 프로비저닝이 실패했기 때문에 안전하게 사용할 수 없습니다.
- 다음 실행 계획을 생성할 때, Terraform은 오염된 리소스를 제거하고 새 리소스를 생성하여 다시 프로비저닝을 시도한다.
Destroy provisioners
- 파괴 작업 중에만 실행되는 프로비저너를 정의할 수도 있다. 이러한 프로비저너는 시스템 정리, 데이터 추출 등을 수행하는 데 유용하다.
- 많은 리소스에 대해 가능한 경우 내장된 정리 메커니즘(예: 초기화 스크립트)을 사용하는 것이 권장되지만, 필요할 경우 프로비저너를 사용할 수 있다.
- 이 실습에서는 파괴 프로비저너의 예시는 보여주지 않습니다. 파괴 프로비저너를 사용해야 하는 경우, 프로비저너 문서를 참조.