Best practice per la gestione delle dipendenze

Questo documento fornisce consigli per esprimere le dipendenze tra le risorse nella configurazione di Terraform.

Prediligi le dipendenze implicite rispetto alle dipendenze esplicite

Le dipendenze delle risorse si verificano quando una risorsa dipende dall'esistenza di altre risorse. Terraform deve essere in grado di comprendere queste dipendenze per garantire che le risorse vengano create nell'ordine corretto. Ad esempio, se la risorsa A ha una dipendenza dalla risorsa B, che viene creata prima della risorsa A.

Le dipendenze di configurazione di Terraform possono essere stabilite dichiarazioni di dipendenza implicite ed esplicite. Le dipendenze implicite vengono dichiarate riferimenti alle espressioni, mentre le dipendenze esplicite sono specificate mediante depends_on . L'argomento depends_on specifica che Terraform deve completare tutte le azioni sugli oggetti da cui dipende una risorsa o un modulo, prima e procedere con l'oggetto dipendente.

Sebbene entrambi gli approcci garantiscano un ordine corretto delle operazioni, le dipendenze implicite spesso portano a una maggiore efficienza nella pianificazione di aggiornamenti e sostituzione delle risorse. Questo perché Terraform può monitorare in modo intelligente i campi specifici coinvolti in una dipendenza implicita, evitare potenzialmente modifiche alla risorsa dipendente se quei campi specifici a rimanere inalterate all'interno della dipendenza.

Rispetto alle dipendenze implicite, quelle esplicite comunicano meno informazioni specifiche. Ciò significa che Terraform può formulare piani più conservativi per la creazione, l'aggiornamento e la sostituzione delle risorse solo in assenza di conoscenza dei particolari attributi che costituiscono la dipendenza. In pratica, questo influisce sulla sequenza in cui le risorse vengono create Terraform e come Terraform determina se le risorse richiedono aggiornamenti sostituzioni.

Ti consigliamo di utilizzare dipendenze esplicite con il metaargomento depends_on solo come ultima risorsa quando una dipendenza tra due risorse è nascosta non possono essere espresse tramite dipendenze implicite.

Nell'esempio seguente, i servizi di progetto richiesti devono essere abilitati prima creando un set di dati BigQuery. Questa dipendenza è dichiarata esplicitamente:

Sconsigliato:

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
}

L'esempio seguente sostituisce la dipendenza esplicita con una dipendenza implicita facendo riferimento all'argomento project_id come output project_id attributo della risorsa project_services:

Consigliato:

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
}

L'utilizzo delle dipendenze implicite consente dichiarazioni precise delle dipendenze, ad esempio la specifica delle informazioni esatte da raccogliere da un oggetto a monte. In questo modo si riduce anche la necessità di apportare modifiche in più posizioni, il che a sua volta riduce il rischio di errori.

Riferimento per gli attributi di output delle risorse dipendenti

Quando crei dipendenze implicite facendo riferimento ai valori upstream assicurati di fare riferimento solo agli attributi di output, in particolare valori non ancora noti. Questo assicura che Terraform attenda la creazione delle risorse upstream prima di eseguire il provisioning della risorsa attuale.

Nell'esempio seguente, la risorsa google_storage_bucket_object fa riferimento l'argomento name della risorsa google_storage_bucket. Gli argomenti hanno valori noti durante la fase di pianificazione di Terraform. Ciò significa che quando Terraform crea la risorsa google_storage_bucket_object, non attende la creazione della risorsa google_storage_bucket perché il riferimento a un argomento noto (il nome del bucket) non crea una dipendenza implicita tra google_storage_bucket_object e google_storage_bucket. Questo sconfigge lo scopo della dichiarazione di dipendenza implicita tra le due risorse.

Non consigliato:

# 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
}

La risorsa google_storage_bucket_object deve invece fare riferimento all'attributo output id della risorsa google_storage_bucket_object. Dal id è un attributo di output, il suo valore viene impostato solo dopo la creazione del la risorsa è stata eseguita. Pertanto, Terraform attenderà il completamento della creazione della risorsa google_storage_bucket_object prima di iniziare la creazione della risorsa google_storage_bucket_object.

Consigliato:

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

A volte non è presente un attributo di output evidente a cui fare riferimento. Ad esempio: considera l'esempio seguente in cui module_a prende il nome della risorsa generata come input. All'interno di module_a, il nome del file viene utilizzato per leggerlo. Se lo esegui così com'è, verrà generata un'eccezione no such file or directory, causata dal tentativo di Terraform di leggere il file durante la fase di pianificazione, quando il file non è ancora stato creato. In questo caso, dell'attributo output della risorsa local_file rivela che non ci sono campi evidenti che puoi usare al posto dell'input del nome file .

Sconsigliato:

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
}

Puoi risolvere il problema introducendo una dipendenza esplicita. Come best practice, assicurati di aggiungere un commento sul motivo per cui è necessaria la dipendenza esplicita:

Consigliato:

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
}

Passaggi successivi