Praktik terbaik tentang pengelolaan dependensi

Dokumen ini memberikan rekomendasi untuk menyatakan dependensi antara resource dalam konfigurasi Terraform Anda.

Memilih dependensi implisit daripada dependensi eksplisit

Dependensi resource muncul saat satu resource bergantung pada keberadaan resource lain. Terraform harus dapat memahami dependensi ini untuk memastikan resource dibuat dalam urutan yang benar. Misalnya, jika resource A memiliki dependensi pada resource B, resource B akan dibuat sebelum resource A.

Dependensi konfigurasi Terraform dapat dibuat melalui deklarasi dependensi implisit dan eksplisit. Dependensi implisit dideklarasikan melalui referensi ekspresi, sedangkan dependensi eksplisit ditentukan menggunakan argumen meta depends_on. Argumen depends_on menentukan bahwa Terraform harus menyelesaikan semua tindakan pada objek yang menjadi dependensi resource atau modul, sebelum melanjutkan dengan objek dependen.

Meskipun kedua pendekatan tersebut memastikan urutan operasi yang benar, dependensi implisit sering kali menghasilkan efisiensi yang lebih tinggi dalam merencanakan update dan penggantian resource. Hal ini karena Terraform dapat melacak kolom tertentu yang terlibat dalam dependensi implisit secara cerdas, yang berpotensi menghindari perubahan pada resource dependen jika kolom tertentu tersebut tetap tidak diubah dalam dependensi.

Dibandingkan dengan dependensi implisit, dependensi eksplisit menyampaikan informasi yang kurang spesifik. Artinya, Terraform hanya dapat merumuskan rencana yang lebih konservatif untuk pembuatan, pembaruan, dan penggantian resource jika tidak memiliki pengetahuan tentang atribut tertentu yang membentuk dependensi. Dalam praktiknya, hal ini memengaruhi urutan pembuatan resource oleh Terraform dan cara Terraform menentukan apakah resource memerlukan update atau penggantian.

Sebaiknya gunakan dependensi eksplisit dengan argumen meta depends_on hanya sebagai upaya terakhir saat dependensi antara dua resource disembunyikan dan tidak dapat dinyatakan melalui dependensi implisit.

Dalam contoh berikut, layanan project yang diperlukan harus diaktifkan sebelum membuat set data BigQuery. Dependensi ini dideklarasikan secara eksplisit:

Tidak direkomendasikan:

module "project_services" {
  source  = "terraform-google-modules/project-factory/google//modules/project_services"
  version = "~> 14.4"

  project_id = var.project_id
  activate_apis = [
    "bigquery.googleapis.com",
    "bigquerystorage.googleapis.com",
  ]
}

module "bigquery" {
  source       = "terraform-google-modules/bigquery/google"
  version      = "~> 5.4"

  dataset_id   = "demo_dataset"
  dataset_name = "demo_dataset"
  project_id   = var.project_id
  depends_on = [module.project_services] # <- explicit dependency
}

Contoh berikut mengganti dependensi eksplisit dengan dependensi implisit dengan mereferensikan argumen project_id sebagai atribut output project_id dari resource project_services:

Direkomendasikan:

module "bigquery" {
  source       = "terraform-google-modules/bigquery/google"
  version      = "~> 5.4"

  dataset_id   = "demo_dataset"
  dataset_name = "demo_dataset"
  project_id   = module.project_services.project_id # <- implicit dependency
}

Penggunaan dependensi implisit memungkinkan deklarasi dependensi yang tepat, seperti menentukan informasi yang tepat yang perlu dikumpulkan dari objek upstream. Hal ini juga mengurangi kebutuhan untuk melakukan perubahan di beberapa tempat, yang pada akhirnya mengurangi risiko error.

Mereferensikan atribut output dari resource dependen

Saat Anda membuat dependensi implisit dengan mereferensikan nilai dari resource upstream, pastikan untuk hanya mereferensikan atribut output, terutama nilai yang belum diketahui. Tindakan ini akan memastikan bahwa Terraform menunggu resource upstream dibuat sebelum menyediakan resource saat ini.

Dalam contoh berikut, resource google_storage_bucket_object mereferensikan argumen nama resource google_storage_bucket. Argumen memiliki nilai yang diketahui selama fase rencana Terraform. Artinya, saat membuat resource google_storage_bucket_object, Terraform tidak menunggu resource google_storage_bucket dibuat karena mereferensikan argumen yang diketahui (nama bucket) tidak membuat dependensi implisit antara google_storage_bucket_object dan google_storage_bucket. Hal ini akan mengacaukan tujuan deklarasi dependensi implisit antara kedua resource.

Tidak direkomendasikan:

# Cloud Storage bucket
resource "google_storage_bucket" "bucket" {
  name = "demo-bucket"
  location = "US"
}

resource "google_storage_bucket_object" "bucket_object" {
  name   = "demo-object"
  source = "./test.txt"
  bucket = google_storage_bucket.bucket.name # name is an input argument
}

Sebagai gantinya, resource google_storage_bucket_object harus mereferensikan atribut output id dari resource google_storage_bucket_object. Karena kolom id adalah atribut output, nilainya hanya ditetapkan setelah pembuatan resource-nya dieksekusi. Oleh karena itu, Terraform akan menunggu pembuatan resource google_storage_bucket_object selesai sebelum memulai pembuatan resource google_storage_bucket_object.

Direkomendasikan:

resource "google_storage_bucket_object" "bucket_object" {
  name   = "demo-object"
  source = "./test.txt"
  bucket = google_storage_bucket.bucket.id # id is an output attribute
}

Terkadang tidak ada atribut output yang jelas untuk dirujuk. Misalnya, pertimbangkan contoh berikut dengan module_a mengambil nama file yang dihasilkan sebagai input. Di dalam module_a, nama file digunakan untuk membaca file. Jika menjalankan kode ini apa adanya, Anda akan mendapatkan pengecualian no such file or directory, yang disebabkan oleh Terraform yang mencoba membaca file selama fase perencanaannya, saat file belum dibuat. Dalam hal ini, pemeriksaan atribut output resource local_file mengungkapkan bahwa tidak ada kolom yang jelas yang dapat Anda gunakan sebagai pengganti argumen input nama file.

Tidak direkomendasikan:

resource "local_file" "generated_file" {
 filename = "./generated_file.text"
 content = templatefile("./template.tftpl", {
   project_id = var.project_id
 })
}

module "module_a" {
 source = "./modules/module-a"
 root_config_file_path = local_file.generated_file.filename
}

Anda dapat mengatasi masalah ini dengan memperkenalkan dependensi eksplisit. Sebagai praktik terbaik, pastikan untuk menambahkan komentar tentang alasan dependensi eksplisit diperlukan:

Direkomendasikan:

module "module_a" {
 source = "./modules/module-a"
 root_config_file_path = local_file.generated_file.filename
 depends_on = [local_file.generated_file] # waiting for generated_file to be created
}

Langkah berikutnya