Best practice per lo stile e la struttura generali

Questo documento fornisce suggerimenti su struttura e stile di base per le configurazioni Terraform. Questi suggerimenti si applicano ai moduli Terraform riutilizzabili e alle configurazioni root.

Questa guida non è un'introduzione a Terraform. Per un'introduzione all'utilizzo di Terraform con Google Cloud, consulta la guida introduttiva a Terraform.

Seguire una struttura di moduli standard

  • I moduli Terraform devono seguire la struttura del modulo standard.
  • Inizia ogni modulo con un file main.tf, in cui si trovano le risorse per impostazione predefinita.
  • In ogni modulo, includi un file README.md in formato Markdown. Nel file README.md, includi la documentazione di base sul modulo.
  • Inserisci gli esempi in una cartella examples/, con una sottodirectory separata per ogni esempio. Per ogni esempio, includi un file README.md dettagliato.
  • Crea raggruppamenti logici di risorse con i rispettivi file e nomi descrittivi, ad esempio network.tf, instances.tf o loadbalancer.tf.
    • Evita di assegnare a ogni risorsa il proprio file. Raggruppa le risorse in base allo scopo condiviso. Ad esempio, combina google_dns_managed_zone e google_dns_record_set in dns.tf.
  • Nella directory root del modulo, includi solo Terraform (*.tf) e i file di metadati del repository (come README.md e CHANGELOG.md).
  • Inserisci eventuale documentazione aggiuntiva in una sottodirectory docs/.

Adotta una convenzione di denominazione

  • Assegna a tutti gli oggetti di configurazione un nome con trattini bassi per delimitare più parole. Questa prassi garantisce la coerenza con la convenzione di denominazione per i tipi di risorse, i tipi di origine dati e altri valori predefiniti. Questa convenzione non si applica agli argomenti di nome.

    Consigliato:

    resource "google_compute_instance" "web_server" {
      name = "web-server"
    }
    

    Sconsigliato:

    resource "google_compute_instance" "web-server" {
      name = "web-server"
    }
    
  • Per semplificare i riferimenti a una risorsa che è l'unica nel suo tipo (ad esempio, un singolo bilanciatore del carico per un intero modulo), denomina la risorsa main.

    • Occorre un lavoro mentale aggiuntivo per ricordare some_google_resource.my_special_resource.id rispetto a some_google_resource.main.id.
  • Per differenziare le risorse dello stesso tipo tra loro (ad esempio, primary e secondary), fornisci nomi significativi per le risorse.

  • Rendi i nomi delle risorse singolari.

  • Non ripetere il tipo di risorsa nel nome della risorsa. Ad esempio:

    Consigliato:

    resource "google_compute_global_address" "main" { ... }
    

    Sconsigliato:

    resource "google_compute_global_address" "main_global_address" { … }
    

Utilizza le variabili con attenzione

  • Dichiara tutte le variabili in variables.tf.
  • Assegna alle variabili nomi descrittivi pertinenti al loro utilizzo o alla loro finalità:
    • Gli input, le variabili locali e gli output che rappresentano valori numerici, ad esempio dimensioni del disco o dimensioni della RAM, devono essere denominati con unità (ad esempio ram_size_gb). Le API Google Cloud non hanno unità standard, quindi denominare le variabili con unità rende chiara l'unità di input prevista per i gestori della configurazione.
    • Per le unità di archiviazione, utilizza i prefissi delle unità binarie (potenze di 1024): kibi, mebi, gibi. Per tutte le altre unità di misura, utilizza prefissi di unità decimali (potenze pari a 1000): kilo, mega, giga. Questo utilizzo corrisponde all'utilizzo all'interno di Google Cloud.
    • Per semplificare la logica condizionale, assegna nomi positivi alle variabili booleane, ad esempio enable_external_access.
  • Le variabili devono avere descrizioni. Le descrizioni sono incluse automaticamente nella documentazione generata automaticamente di un modulo pubblicato. Le descrizioni aggiungono ulteriore contesto per i nuovi sviluppatori, che i nomi descrittivi non sono in grado di fornire.
  • Assegna i tipi definiti per le variabili.
  • Se opportuno, fornisci valori predefiniti:
    • Per le variabili che hanno valori indipendenti dall'ambiente (come le dimensioni del disco), fornisci valori predefiniti.
    • Per le variabili che hanno valori specifici dell'ambiente (ad esempio project_id), non fornire valori predefiniti. In questo modo, il modulo chiamante deve fornire valori significativi.
  • Utilizza valori predefiniti vuoti per le variabili (come stringhe o elenchi vuoti) solo quando lasciare la variabile vuota è una preferenza valida che le API sottostanti non rifiutano.
  • Sii prudente nell'uso delle variabili. Parametrizza solo i valori che devono variare per ogni istanza o ambiente. Nel decidere se esporre una variabile, assicurati di avere un caso d'uso concreto per modificarla. Se c'è solo una piccola possibilità che una variabile sia necessaria, non esporla.
    • L'aggiunta di una variabile con un valore predefinito è compatibile con le versioni precedenti.
    • La rimozione di una variabile non è compatibile con le versioni precedenti.
    • Nei casi in cui un valore letterale viene riutilizzato in più posizioni, puoi utilizzare un valore locale senza esporlo come variabile.

Esponi gli output

  • Organizza tutti gli output in un file outputs.tf.
  • Fornisci descrizioni significative per tutti gli output.
  • Descrizioni degli output del documento nel file README.md. Genera automaticamente descrizioni al momento del commit con strumenti come terraform-docs.
  • Restituisce tutti i valori utili a cui i moduli principali potrebbero dover fare riferimento o che potrebbero dover condividere. Mostra tutti gli output che potrebbero potenzialmente essere consumati, soprattutto per i moduli open source o molto usati.
  • Non passare gli output direttamente tramite le variabili di input, perché così facendo impedisci che vengano aggiunti correttamente al grafico delle dipendenze. Per garantire la creazione delle dipendenze implicite, assicurati che gli output degli attributi di riferimento dalle risorse Anziché fare riferimento direttamente a una variabile di input per un'istanza, passa l'attributo come mostrato qui:

    Consigliato:

    output "name" {
      description = "Name of instance"
      value       = google_compute_instance.main.name
    }
    

    Sconsigliato:

    output "name" {
      description = "Name of instance"
      value       = var.name
    }
    

Utilizza le origini dati

  • Inserisci le origini dati accanto alle risorse che le fanno riferimento. Ad esempio, se stai recuperando un'immagine da utilizzare per avviare un'istanza, posizionala accanto all'istanza anziché raccogliere risorse dati nel proprio file.
  • Se il numero di origini dati aumenta, valuta la possibilità di spostarle in un file data.tf dedicato.
  • Per recuperare i dati relativi all'ambiente attuale, utilizza l'interpolazione di variabili o risorse.

Limitare l'utilizzo di script personalizzati

  • Utilizza gli script solo quando necessario. Lo stato delle risorse create tramite gli script non viene preso in considerazione o gestito da Terraform.
    • Se possibile, evita script personalizzati. Usale solo quando le risorse Terraform non supportano il comportamento desiderato.
    • Gli script personalizzati utilizzati devono avere un motivo chiaro e documentato per l'esistenza e, idealmente, di un piano di ritiro.
  • Terraform può chiamare script personalizzati tramite provisioner, incluso il provisioner local-exec.
  • Inserisci gli script personalizzati richiamati da Terraform in una directory scripts/.

Includi script di supporto in una directory separata

  • Organizza gli script helper che non vengono chiamati da Terraform in una directory helpers/.
  • Script helper per i documenti nel file README.md con spiegazioni e chiamate di esempio.
  • Se gli script helper accettano argomenti, fornisci il controllo degli argomenti e l'output --help.

Colloca i file statici in una directory separata

  • I file statici a cui Terraform fa riferimento ma che non esegue (ad esempio gli script di avvio caricati sulle istanze di Compute Engine) devono essere organizzati in una directory files/.
  • Inserisci qui il lungo documento in file esterni, separati da un apposito documento. Puoi farvi riferimento con la funzione file().
  • Per i file letti mediante la funzione templatefile di Terraform, utilizza l'estensione del file .tftpl.
    • I modelli devono essere posizionati in una directory templates/.

Protezione delle risorse stateful

Per le risorse stateful, ad esempio i database, assicurati che sia abilitata la protezione da eliminazione. Ad esempio:

resource "google_sql_database_instance" "main" {
  name = "primary-instance"
  settings {
    tier = "D0"
  }

  lifecycle {
    prevent_destroy = true
  }
}

Usare la formattazione integrata

Tutti i file Terraform devono essere conformi agli standard di terraform fmt.

Limitare la complessità delle espressioni

  • Limita la complessità delle singole espressioni interpolate. Se sono necessarie molte funzioni in una singola espressione, valuta la possibilità di suddividerla in più espressioni utilizzando valori locali.
  • Non avere mai più di un'operazione ternaria in una singola riga. Utilizza invece più valori locali per creare la logica.

Utilizza count per i valori condizionali

Per creare un'istanza di una risorsa in modo condizionale, utilizza il meta argomento count. Ad esempio:

variable "readers" {
  description = "..."
  type        = list
  default     = []
}

resource "resource_type" "reference_name" {
  // Do not create this resource if the list of readers is empty.
  count = length(var.readers) == 0 ? 0 : 1
  ...
}

Presta attenzione quando utilizzi le variabili specificate dall'utente per impostare la variabile count per le risorse. Se per una variabile di questo tipo (come project_id) viene fornito un attributo di risorsa e la risorsa non esiste ancora, Terraform non può generare un piano. Terraform segnala invece l'errore value of count cannot be computed. In questi casi, utilizza una variabile enable_x separata per calcolare la logica condizionale.

Usa for_each per le risorse iterate

Se vuoi creare più copie di una risorsa in base a una risorsa di input, utilizza il meta-argomento for_each.

Pubblica moduli in un registro

Passaggi successivi