✏️ 테라폼의 기본 문법을 숙지한다!
✏️ 간결하고 정리된 코드를 작성할 수 있는 팁을 익힌다!
테라폼을 사용하여 GCP 클라우드 내 VPC 와 서브넷을 생성해보자!
// main.tf
resource "google_compute_network" "vpc_network" {
project = "my-project-id"
name = "my-vpc"
auto_create_subnetworks = false
mtu = 1460
}
resource "google_compute_subnetwork" "subnetwork-ipv6" {
name = "ipv6-test-subnetwork"
ip_cidr_range = "10.0.0.0/22"
region = "us-west-2"
network = google_compute_network.vpc_network.id
}
테라폼 내 모든 리소스는 아래와 같은 구조로 되어 있다. 다만 각 리소스당 정의해야하는 arguments 는 서로 다를 수 있다.
<type> <resource type> <resource name> {
# arguments...
}
<resource type> <resource name> 은 파일 내에서 unique 한 값을 가져야 한다.resource name 은 사용자가 정할 수 있는 값이지만, resource type 은 클라우드 제공자가 정한 값을 사용해야한다. 
리소스 내에서 다른 리소스의 이름 또는 속성을 참고해야하는 경우 <resource_type>.<resource_name>.<argument_name> 을 사용하여 참조할 수 있다.
// main.tf
resource "google_compute_network" "vpc_network" {
project = "my-project-id"
name = "my-vpc"
auto_create_subnetworks = false
mtu = 1460
}
resource "google_compute_subnetwork" "subnetwork-ipv6" {
name = "ipv6-test-subnetwork"
ip_cidr_range = "10.0.0.0/22"
region = "us-west-2"
network = google_compute_network.vpc_network.id
}
위 파일을 통해 리소스 생성 시, "my-vpc" 라는 이름을 가진 GCP VPC 에 "ipv6-test-subnetwork" 라는 이름의 서브넷을 생성할 수 있다.
Meta arguments 를 사용하여 여러 리소스를 생성하거나 특정 리소스의 설정값을 만들 수 있다.
count : count 에 입력된 값 만큼 리소스를 생성한다.
for_each : map 또는 문자열 세트(set) 를 참고하여 여러 리소스를 생성한다.
depends_on : 의존성을 명시적으로 표기할 때 사용한다.
lifecycle : 리소스의 라이프사이클을 관리할 때 사용한다. 예를 들어, 사내 법규로 인해 삭제하면 안되는 리소스의 제거를 사전 방지 하거나 리소스 삭제가 이루어지기 전 새로운 리소스를 생성하여 대체하고 기존 리소스를 삭제할 수 있도록 한다.
provider : 기본값으로 설정된 클라우드 제공자가 아닌 다른 클라우드 제공자를 적용해야 할 때 사용한다.
다음과 같이 똑같은 설정값을 가진 리소스를 여러개 생성해야하는 경우 count meta argument 를 사용하여 코드의 반복을 줄일 수 있다. 😄
원본코드
resource "google_compute_instance" "dev_VM1" {
name = "dev_VM1"
// etc...
}
resource "google_compute_instance" "dev_VM2" {
name = "dev_VM2"
// etc...
}
resource "google_compute_instance" "dev_VM3" {
name = "dev_VM3"
// etc...
}
수정된 코드
💡 count.index 는 0 부터 시작하며 1 씩 증가한다.
resource "google_compute_instance" "Dev_VM" {
count = 3
name = "dev_VM${count.index + 1}"
}
완전히 똑같은 리소스를 여러 개 생성해야하는 경우 count 로 충분할 수 있지만 몇몇 값이 달라야하는 경우 for_each 를 사용하는 것이 적절하다.
원본코드
resource "google_compute_instance" "VM1" {
name = "dev-us-central1-a"
location = "us-central1-a"
}
resource "google_compute_instance" "VM2" {
name = "dev-us-central1-b"
location = "us-central1-b"
}
resource "google_compute_instance" "VM3" {
name = "dev-us-central1-c"
location = "us-central1-c"
}
수정된 코드
resource "google_compute_instance" "dev_VM" {
for_each = toset(["us-central1-a", "us-central1-b", "us-central1-c"])
name = "dev-${each.value}"
zone = each.value
}
⛄ 우와 편하다
테라폼으로 리소스를 생성하다보면 리소스들이 어떻게 연결되어 있는지 의존성은 어떻게 형성 되어 있는지 시각적으로 확인하고 싶을 때가 있다. 이 때 Dependency graph 이 큰 도움이 될 것이다.
테라폼은 리소스 구성 계획을 생성하고 state 를 재구성하기 위해 Dependency graph 를 그린다. 이는 테라폼이 변수, 아웃풋 및 클라우드 제공자를 정의 할 수 있도록 도울 뿐만 아니라 어떤 연산자를 먼저 수행 해야하는지 알 수 있도록 한다. 또 여러 연산자가 병렬적으로 수행되었을 때 안전한 경우 병렬로 리소스를 생성한다.
의존성에는 크게 두 가지 종류가 있다.
Implicit dependency
Explicit dependency
👉 이 경우 depends_on 을 사용하여 두 리소스 간의 의존성을 명시적으로 설정 할 수 있다.
Implicit dependency
resource "google_compute_instance" "my_instance" {
network = google_compute_network.my_network.name // [1]
access_config {
}
}
resource "google_compute_network" "my_network" {
name = "my_network"
}
이 경우 테라폼이 [1]를 통해 두 리소스 사이에 Implicit dependency 가 있음을 알 수 있다.

이 파일에 대하여 terraform apply 실행 시 아래와 같이 VPC 가 먼저 생성되고 이후 instance 가 생성되는 것을 볼 수 있다. 테라폼이 리소스를 생성하는 순서는 다음과 같다.
state 에 VPC 에 대한 속성 정보를 저장한다. Explicit dependency
server VM 과 client VM 이 있다고 가정하자. client VM 은 server VM 이 성공적으로 생성 된 후에만 생성되어야 한다. 이 경우 depends_on meta arguments 를 통하여 두 리소스 간의 의존성을 표기하고 리소스 생성 순서를 정의 해줄 수 있다.
resource "google_compute_instance" "client" {
// etc
depends_on = [ google_compute_instance.server ]
}
resource "google_compute_instance" "server" {
// etc
}
💡 테라폼 코드 상의 리소스 생성 순서와 실제 리소스 생성 순서는 상이하다. 따라서, 리소스 생성 순서를 고려하여 코드를 작성할 필요 없다. 나와 우리 팀이 보기에 가장 적절한 순서대로 코드를 작성하자.