Anti-Pattern Datasource #
Data source adalah fitur yang kuat tapi mudah disalahgunakan. Penggunaan yang tidak tepat menghasilkan konfigurasi yang rapuh — plan yang gagal karena resource yang dicari tidak ditemukan, coupling antar workspace yang terlalu ketat, atau konfigurasi yang diam-diam berubah perilakunya karena data source mengembalikan hasil yang berbeda. Artikel ini mengompilasi anti-pattern yang paling sering ditemukan dalam konfigurasi Terraform di production.
Anti-Pattern 1: Filter yang Tidak Spesifik #
Data source yang bisa mengembalikan lebih dari satu hasil adalah bom waktu — ia berjalan baik hari ini, tapi gagal begitu ada resource baru yang cocok dengan filter yang sama.
# ANTI-PATTERN: Filter berdasarkan state saja — terlalu lebar
data "aws_instance" "app_server" {
filter {
name = "instance-state-name"
values = ["running"]
}
# Di environment dev mungkin hanya ada 1 instance running
# Di production ada 10 — ERROR: Your query returned more than one result
}
# ANTI-PATTERN: Tidak ada filter sama sekali
data "aws_vpc" "main" {
# Tidak ada filter atau ID — Terraform akan error jika ada lebih dari 1 VPC
}
# BENAR: Filter yang cukup spesifik untuk mengembalikan tepat 1 hasil
data "aws_instance" "app_server" {
filter {
name = "tag:Name"
values = ["app-server-production"]
}
filter {
name = "tag:Environment"
values = [var.environment]
}
filter {
name = "instance-state-name"
values = ["running"]
}
}
Anti-Pattern 2: Data Source sebagai Pengganti Import #
Data source hanya membaca resource — ia tidak membuat Terraform “mengelola” resource tersebut. Menggunakan data source sebagai cara untuk “menggunakan” resource yang seharusnya diimport adalah kesalahpahaman yang umum.
# ANTI-PATTERN: Menggunakan data source untuk resource yang ingin dikelola
# Tim mengelola VPC secara manual dan ingin Terraform ikut mengelola
# tagnya, security group-nya, dll. Tapi mereka menggunakan data source:
data "aws_vpc" "main" {
id = "vpc-0abcdef1234567890"
}
# Lalu mencoba "update" VPC via resource yang berbeda:
resource "aws_vpc_ipv4_cidr_block_association" "secondary" {
vpc_id = data.aws_vpc.main.id # Referensi ke VPC via data source
cidr_block = "10.1.0.0/16"
}
# Masalah: Terraform tidak mengelola VPC itu sendiri
# Jika VPC dihapus secara manual, plan akan error
# Tags, DNS settings, dll. tidak bisa dikelola via data source
# BENAR: Import VPC ke Terraform state dan kelola sebagai resource
# terraform import aws_vpc.main vpc-0abcdef1234567890
resource "aws_vpc" "main" {
cidr_block = "10.0.0.0/16"
# Sekarang Terraform mengelola VPC ini sepenuhnya
}
Anti-Pattern 3: Overuse terraform_remote_state #
terraform_remote_state menciptakan coupling langsung antara dua workspace — perubahan di workspace sumber bisa memecah workspace yang membacanya.
# ANTI-PATTERN: Setiap workspace membaca state dari banyak workspace lain
# workspace "app" membaca dari 5 workspace berbeda
data "terraform_remote_state" "networking" { ... }
data "terraform_remote_state" "security" { ... }
data "terraform_remote_state" "dns" { ... }
data "terraform_remote_state" "certificates" { ... }
data "terraform_remote_state" "iam" { ... }
# Masalah:
# - "app" workspace tidak bisa dijalankan jika salah satu dari 5 workspace ini
# belum pernah di-apply (state tidak ada)
# - Setiap perubahan output di workspace manapun bisa memecah "app"
# - Sulit di-test secara terisolasi
# BENAR: Gunakan variable input untuk decoupling
# Workspace app menerima nilai yang dibutuhkan via variable
variable "vpc_id" {
description = "ID VPC dari workspace networking"
type = string
}
variable "private_subnet_ids" {
description = "List ID private subnet dari workspace networking"
type = list(string)
}
# Nilai dioper eksplisit saat apply — tidak ada dependency pada state workspace lain
# terraform apply -var="vpc_id=vpc-abc" -var-file="networking-outputs.tfvars"
Anti-Pattern 4: Data Source untuk Nilai yang Seharusnya Variable #
Menggunakan data source untuk mendapatkan nilai yang sebenarnya bisa dioper sebagai variable membuat konfigurasi bergantung pada kondisi cloud yang mungkin berubah.
# ANTI-PATTERN: Query VPC untuk mendapatkan CIDR, lalu gunakan untuk kalkulasi
data "aws_vpc" "main" {
id = var.vpc_id
}
# Kalkulasi subnet CIDR dari VPC CIDR yang di-query
resource "aws_subnet" "app" {
cidr_block = cidrsubnet(data.aws_vpc.main.cidr_block, 8, 1)
# Masalah: jika CIDR block VPC berubah, kalkulasi subnet juga berubah
# Perubahan yang tidak terduga pada VPC bisa menyebabkan subnet di-replace
}
# BENAR: Oper nilai yang dibutuhkan sebagai variable eksplisit
variable "vpc_cidr" {
description = "CIDR block VPC"
type = string
}
resource "aws_subnet" "app" {
cidr_block = cidrsubnet(var.vpc_cidr, 8, 1)
# Nilai eksplisit — hanya berubah jika variable berubah
}
Anti-Pattern 5: Data Source Tanpa Error Handling #
Data source yang tidak menemukan resource akan error saat plan. Tanpa penanganan yang tepat, ini bisa memblokir seluruh pipeline.
# ANTI-PATTERN: Data source yang mungkin tidak ada di semua environment
data "aws_route53_zone" "main" {
name = "myapp.com"
# Di environment dev mungkin tidak ada hosted zone ini
# → Plan di dev selalu error
}
# BENAR: Gunakan count atau conditional untuk data source yang mungkin tidak ada
variable "create_dns_records" {
type = bool
default = false
}
data "aws_route53_zone" "main" {
count = var.create_dns_records ? 1 : 0
name = "myapp.com"
}
resource "aws_route53_record" "app" {
count = var.create_dns_records ? 1 : 0
zone_id = data.aws_route53_zone.main[0].zone_id
name = "app.myapp.com"
type = "A"
# ...
}
Anti-Pattern 6: Data Source yang Query Resource Sendiri #
Beberapa developer menggunakan data source untuk membaca resource yang ada di konfigurasi yang sama. Ini tidak perlu — referensi langsung lebih bersih dan lebih efisien.
# ANTI-PATTERN: Data source untuk membaca resource di konfigurasi yang sama
resource "aws_security_group" "web" {
name = "web-sg"
vpc_id = aws_vpc.main.id
}
# Tidak perlu data source untuk baca security group yang baru dibuat!
data "aws_security_group" "web" {
name = "web-sg"
vpc_id = aws_vpc.main.id
depends_on = [aws_security_group.web] # ✗ Berputar-putar
}
resource "aws_instance" "web" {
vpc_security_group_ids = [data.aws_security_group.web.id] # ✗ Tidak perlu
}
# BENAR: Referensi langsung ke resource
resource "aws_instance" "web" {
vpc_security_group_ids = [aws_security_group.web.id] # ✓ Langsung dan bersih
}
Ringkasan #
- Filter harus cukup spesifik untuk selalu mengembalikan tepat satu hasil — filter yang ambigu berjalan di dev tapi bisa error di production.
- Data source bukan pengganti import — jika ingin Terraform mengelola resource, import ke state. Data source hanya membaca, tidak mengelola.
- Batasi penggunaan
terraform_remote_state— coupling yang berlebihan antar workspace membuat konfigurasi sulit dijalankan secara terisolasi. Pertimbangkan variable input sebagai alternatif.- Jangan query via data source untuk nilai yang bisa dioper sebagai variable — variable membuat dependency lebih eksplisit dan konfigurasi lebih mudah diprediksi.
- Gunakan
countuntuk data source yang mungkin tidak ada di semua environment — mencegah plan gagal hanya karena resource tidak ada di environment tertentu.- Referensi langsung ke resource dalam konfigurasi yang sama — tidak perlu data source untuk membaca resource yang ada di konfigurasi yang sama.