Terraform으로 Google Cloud의 네트워크, VM 머신 유형, 디스크 설정을 코드로 관리할 수 있다. Terraform은 구성 파일과 현재 리소스 상태를 비교해 생성·변경·삭제 계획을 작성하고, 승인된 계획을 클라우드 API에 적용한다.
이 글에서는 서울 리전에 VPC 하나, 서브넷 하나, VM 한 대를 정의한다. 샘플을 내려받아 프로젝트 ID를 입력한 뒤 생성 계획과 적용 결과를 확인하는 순서로 진행한다.
Terraform 개요와 프로비저닝 흐름#
Terraform은 인프라를 코드로 정의하고 관리하는 IaC(Infrastructure as Code) 도구다. HCL(HashiCorp Configuration Language) 기반의 선언형 구성으로 리소스와 속성을 정의한다. 예를 들어 VM의 머신 유형을 e2-small, 배치 존을 asia-northeast3-a로 지정한다. Terraform은 이 구성에 맞춰 리소스를 프로비저닝한다. 프로비저닝은 VM·네트워크 등 필요한 인프라 리소스를 생성하고 구성하는 작업이다.
Terraform CLI는 provider라는 플러그인을 통해 클라우드 API와 통신한다. 이번 실습에서는 Google provider를 사용한다. AWS나 Azure에도 각각의 provider가 있으며, 리소스 종류와 설정 문법은 provider마다 다르다.
코드를 Git에 보관하면 어떤 설정을 변경했는지 기록할 수 있고, 같은 구성을 다른 프로젝트에 적용할 때도 참고할 수 있다. 실제 변경은 파일 저장만으로 실행되지 않는다. plan으로 변경 계획을 검토한 뒤 apply로 적용한다.
1. 실습 아키텍처와 리소스 구성#
| 항목 | 설정 |
|---|---|
| 프로젝트 | 사용자가 준비한 기존 프로젝트 |
| VPC | tf-lab-vpc, 커스텀 모드 |
| 서브넷 | tf-lab-subnet, 서울 asia-northeast3, 10.20.0.0/24 |
| VM | tf-lab-vm, asia-northeast3-a, e2-small |
| 부팅 디스크 | Debian 12, Standard Persistent Disk 20GB |
| 네트워크 접속 | 내부 IP만 할당, 인바운드 허용 방화벽 규칙 없음 |
목표는 인프라 생성과 변경 계획 확인이다. SSH 접속이나 웹 서비스 공개는 이 실습에 포함하지 않는다. 공인 IP를 할당하지 않으므로 인터넷에서 VM에 직접 접속할 수 없고, 인터넷 접속이 필요한 패키지 설치에도 별도 네트워크 구성이 필요하다.
VM과 디스크에는 요금이 발생한다. 서울 리전의 무료 VM 실습으로 생각하지 말고, 확인 후 마지막 단계에서 삭제한다.
2. CLI 설치와 Google Cloud 인증 구성#
WSL의 Ubuntu 등 로컬 Linux 환경을 기준으로 진행한다. Terraform CLI와 Google Cloud CLI가 필요하다. 각각 Terraform 공식 설치 안내와 Google Cloud CLI 설치 안내에 따라 설치한 뒤 버전을 확인한다.
terraform version
gcloud version예제 구성 기준은 Terraform CLI 1.16.2와 Google provider 7.46.2다. 샘플에는 CLI 1.6 이상, 2.0 미만과 Google provider 7.x의 버전 제약 조건을 지정했다. CLI와 provider는 별도 프로그램이며 버전도 따로 관리한다. 실제 선택한 provider 버전은 terraform init이 생성하는 .terraform.lock.hcl에 기록된다.
결제가 연결된 테스트 프로젝트를 준비하고, 아래 YOUR_PROJECT_ID를 본인의 프로젝트 ID로 바꾼다.
gcloud init
gcloud config set project YOUR_PROJECT_ID
gcloud services enable compute.googleapis.com --project=YOUR_PROJECT_ID
gcloud auth application-default login
gcloud auth application-default set-quota-project YOUR_PROJECT_IDgcloud CLI 로그인과 Terraform이 사용하는 ADC(Application Default Credentials) 인증은 구분된다. 로컬 환경에서는 gcloud auth application-default login으로 ADC를 준비한다. 브라우저에서 프로젝트에 접근할 수 있는 계정으로 로그인한다. Google Cloud Terraform 인증 안내
API 활성화에는 Service Usage Admin 등의 권한이 필요하다. 리소스 생성에는 Compute Network Admin, Compute Instance Admin (v1) 등 해당 리소스를 관리할 권한이 필요하고, quota project 사용에는 serviceusage.services.use 권한이 필요하다. 조직에서 관리하는 프로젝트라면 담당자에게 필요한 범위의 권한을 요청한다. 인증 성공 자체가 리소스 생성 권한까지 보장하지는 않는다.
3. Terraform 구성 파일 준비#
압축파일에는 다음 파일만 들어 있다. 실제 프로젝트 ID, 인증 파일, Terraform state는 포함하지 않았다.
terraform-gcp-vpc-vm/
main.tf
variables.tf
outputs.tf
terraform.tfvars.example
.gitignore
README.md.gitignore는 Terraform 실행에 필요한 파일은 아니다. 이 디렉터리를 Git으로 관리할 때 state, 계획 파일, 개인별 설정이 함께 올라가지 않도록 포함했다.
압축을 풀고 해당 디렉터리에서 작업한다.
cd terraform-gcp-vpc-vm
cp terraform.tfvars.example terraform.tfvarsterraform.tfvars를 편집해 프로젝트 ID를 설정한다.
project_id = "YOUR_PROJECT_ID"4. Terraform 구성 블록과 리소스 의존성#
구성 파일과 블록별 역할#
Terraform은 같은 디렉터리의 .tf 파일들을 하나의 모듈 구성으로 로드한다. 파일명이나 파일 내 선언 순서가 리소스 생성 순서를 결정하지는 않는다. main.tf, variables.tf, outputs.tf는 역할을 구분하기 위한 관례적인 이름이다. 반면 terraform.tfvars는 변수 값을 자동으로 로드하는 파일명이다. Terraform 파일 구성
| 블록 | 구성 역할 |
|---|---|
terraform | CLI 버전과 사용할 provider의 이름·버전 범위 지정 |
provider "google" | 대상 프로젝트와 기본 리전·존 지정 |
resource | VPC, 서브넷, VM의 이름과 속성 정의 |
variable | 외부에서 받을 입력값 선언 |
locals | 구성 내부에서 재사용할 값 정의 |
output | 생성한 리소스에서 확인할 값 지정 |
main.tf 앞부분은 다음과 같다. 아래 코드는 다운로드 샘플의 일부이므로, 샘플에 같은 블록을 다시 추가할 필요는 없다.
terraform {
required_version = ">= 1.6, < 2.0"
required_providers {
google = {
source = "hashicorp/google"
version = "~> 7.0"
}
}
}
locals {
name_prefix = "tf-lab"
region = "asia-northeast3"
zone = "asia-northeast3-a"
}
provider "google" {
project = var.project_id
region = local.region
zone = local.zone
}required_providers는 사용할 플러그인을 지정하고, provider 블록은 그 플러그인으로 접근할 환경을 설정한다. ~> 7.0은 Google provider의 7.x 버전을 허용하고 8.0 이상은 제외한다.
variable: 입력 변수 선언과 값 할당#
입력 변수의 선언, 값 할당, 참조 관계는 다음과 같다.
variables.tf project_id 입력값을 string 타입으로 선언
↓
terraform.tfvars project_id에 본인 프로젝트 ID 지정
↓
main.tf var.project_id를 provider의 project에 전달variables.tf에는 입력값을 선언한다.
variable "project_id" {
description = "Existing Google Cloud project ID"
type = string
}앞에서 작성한 terraform.tfvars의 값이 var.project_id로 참조된다. 프로젝트를 바꿔 실습할 때 코드에 적힌 프로젝트 ID를 여러 군데 수정하지 않고 이 입력값을 지정하면 된다. 단, 기존 state가 있는 디렉터리에서 프로젝트 ID만 바꾸면 리소스 교체가 계획될 수 있다. 다른 프로젝트의 별도 실습은 새로운 작업 디렉터리에서 시작한다.
locals: 공통 설정값 정의와 참조#
locals에는 반복해서 사용할 이름 접두사, 리전, 존을 정의했다. 선언할 때는 locals이고, 값을 참조할 때는 local.name_prefix처럼 단수형을 쓴다.
resource "google_compute_network" "lab" {
name = "${local.name_prefix}-vpc"
auto_create_subnetworks = false
}name_prefix가 tf-lab이므로 GCP에 생성할 VPC 이름은 tf-lab-vpc다. 같은 접두사를 서브넷과 VM에도 사용한다. variable은 외부에서 받는 입력값이고, locals는 구성 내부에서 이름을 붙여 사용하는 값이다. 환경마다 바꿔 입력해야 하는 리전이라면 local.region 대신 입력 변수로 설계할 수도 있다. locals 사용법
resource: 리소스 정의와 속성 참조#
위 블록에서 google_compute_network는 리소스 유형이고 lab은 Terraform 코드 안에서 쓰는 참조 이름이다. 실제 GCP VPC 이름은 블록 안의 name 값으로 정한다.
서브넷에서는 VPC의 ID를 참조한다.
resource "google_compute_subnetwork" "lab" {
name = "${local.name_prefix}-subnet"
ip_cidr_range = "10.20.0.0/24"
region = local.region
network = google_compute_network.lab.id
}google_compute_network.lab.id는 VPC 리소스의 id 속성이다. Terraform은 이 참조로 VPC를 먼저 만들고 그 VPC에 서브넷을 생성해야 한다는 의존성을 파악한다. 파일에 적힌 순서보다 리소스 사이의 참조 관계가 생성 순서를 결정한다.
VM은 다음과 같이 정의한다.
resource "google_compute_instance" "lab" {
name = "${local.name_prefix}-vm"
machine_type = "e2-small"
zone = local.zone
boot_disk {
initialize_params {
image = "debian-cloud/debian-12"
size = 20
type = "pd-standard"
}
}
network_interface {
subnetwork = google_compute_subnetwork.lab.id
}
}machine_type은 VM 사양, boot_disk는 부팅 디스크, network_interface는 연결할 네트워크를 지정한다. 위 설정은 Debian 12 이미지로 20GB HDD 기반 디스크를 만들고, 앞에서 정의한 서브넷에 VM을 연결한다.
공인 IP를 할당하는 access_config 블록을 생략했으므로 내부 IP만 부여된다. VM 이름은 tf-lab-vm이고, Terraform 코드에서 참조할 주소는 google_compute_instance.lab이다. Compute Instance 리소스 문서
output: 리소스 속성 출력#
outputs.tf에는 VM 이름과 내부 IP를 정의했다. 예를 들어 VM 이름은 다음과 같이 출력한다.
output "vm_name" {
value = google_compute_instance.lab.name
}vm_name은 출력 항목 이름이고, value는 해당 VM 리소스에서 가져올 값이다. 적용 후 terraform output으로 확인할 수 있다.
5. 초기화·구성 검증·변경 계획 확인#
terraform init
terraform fmt
terraform validate
terraform plan -out=lab.tfplan| 명령 | 역할 |
|---|---|
init | provider 설치와 작업 디렉터리 초기화 |
fmt | 구성 파일 코드 포맷 정리 |
validate | 설정 문법과 내부 참조 검사 |
plan | 현재 리소스와 설정을 비교해 변경 계획 작성 |
validate가 성공해도 IAM 권한, 프로젝트 할당량, 조직 정책까지 검증된 것은 아니다. 실제 API 호출 과정에서 해당 조건에 따른 오류가 발생할 수 있다.
처음 실행한다면 VPC·서브넷·VM 생성이 계획에 나타나는지 확인한다. +는 생성, ~는 수정, -는 삭제를 뜻하며 교체는 생성과 삭제가 함께 표시된다. 의도하지 않은 삭제나 교체가 있다면 적용 전에 설정을 확인한다.
이 샘플의 VM과 부팅 디스크는 하나의 VM 리소스 블록에 정의되어 있다. 따라서 GCP 콘솔에 보이는 객체 수와 Terraform 계획에 표시되는 리소스 수가 항상 같지는 않다.
6. 변경 계획 적용과 리소스 확인#
저장된 계획이 의도한 VPC·서브넷·VM 생성인지 먼저 확인한다. 아래 명령은 별도의 yes 확인 없이 해당 계획을 적용한다.
terraform apply lab.tfplan
terraform output적용이 성공하면 vm_name과 internal_ip 출력값을 확인한다. Google Cloud 콘솔의 VPC 네트워크와 VM 인스턴스 화면에서도 앞에서 지정한 이름과 서울 리전을 확인한다.
그다음 같은 디렉터리에서 다시 계획을 확인한다.
terraform plan설정과 실제 리소스가 일치한다면 추가 변경이 없다는 결과가 나와야 한다. 이것이 확인되면 동일한 구성으로 다시 실행했을 때 매번 VM을 새로 생성하는 방식이 아니라는 점을 직접 확인할 수 있다.
7. Terraform state와 의존성 잠금 파일 관리#
Terraform은 state에 자신이 관리하는 리소스와 실제 클라우드 리소스의 대응 관계를 기록한다. 이번 예제에서는 로컬 terraform.tfstate에 저장한다.
| 파일 | 관리 방법 |
|---|---|
.tf | 인프라 코드로 Git에서 관리 |
.terraform.lock.hcl | provider 버전과 체크섬을 기록하므로 Git에서 관리 |
.terraform/ | 다운로드한 provider 등 작업용 파일, Git에서 제외 |
terraform.tfstate, 백업 파일 | 리소스 정보와 민감한 값이 들어갈 수 있으므로 공개 금지 |
*.tfplan | 구성과 민감한 값이 포함될 수 있으므로 공개 금지 |
terraform.tfvars | 샘플에서는 Git에서 제외하고 예시 파일만 공유 |
state 파일을 삭제해도 실제 GCP 리소스는 삭제되지 않는다. 오히려 Terraform이 기존 리소스를 추적할 정보를 잃게 된다. 실습 리소스 정리가 끝날 때까지 작업 디렉터리와 state를 보관한다. Terraform state의 목적
여러 사람이 함께 관리할 때는 GCS 같은 원격 backend에 state를 저장하는 구성을 검토할 수 있다. 첫 실습에서는 로컬 state로 리소스 생성과 삭제 과정을 먼저 확인한다.
8. 삭제 계획 확인과 리소스 정리#
작업했던 디렉터리에서 삭제 계획을 만들고 내용을 확인한다.
terraform plan -destroy -out=destroy.tfplan삭제 대상이 이 실습에서 만든 VM·서브넷·VPC인지 확인한다. 다음 명령은 별도의 yes 확인 없이 삭제를 실행한다.
terraform apply destroy.tfplan삭제가 끝나면 콘솔에서 VM과 부팅 디스크가 제거됐는지도 확인한다. 기존 프로젝트와 결제 계정은 이 샘플의 관리 대상이 아니므로 삭제하지 않는다.
실습을 마치면 .tf 파일에 정의한 VPC·서브넷·VM을 생성하고, 같은 state를 사용해 삭제하는 과정을 확인할 수 있다. 이후에는 필요한 설정을 입력 변수로 바꾸고, 반복되는 리소스 구성을 모듈로 분리해 확장할 수 있다.