En este documento, se proporcionan recomendaciones para expresar dependencias entre los recursos de tu configuración de Terraform.
Favorecer las dependencias implícitas sobre las explícitas
Las dependencias de recursos surgen cuando un recurso depende de la existencia de otros recursos. Terraform debe poder comprender estas dependencias para garantizar que los recursos se creen en el orden correcto. Por ejemplo, si el recurso A tiene una dependencia del recurso B, el recurso B se crea antes que el A.
Las dependencias de configuración de Terraform se pueden establecer mediante declaraciones de dependencias implícitas y explícitas.
Las dependencias implícitas se declaran a través de referencias de expresión, mientras que las dependencias explícitas se especifican mediante el metaargumento depends_on
. El argumento depends_on
especifica que Terraform debe completar todas las acciones en los objetos de los que depende un recurso o un módulo, antes de continuar con el objeto dependiente.
Si bien ambos enfoques garantizan un orden correcto de las operaciones, las dependencias implícitas a menudo conducen a una mayor eficiencia en la planificación de actualizaciones y reemplazo de recursos. Esto se debe a que Terraform puede realizar un seguimiento inteligente de los campos específicos involucrados en una dependencia implícita, lo que puede evitar cambios en el recurso dependiente si esos campos específicos no se modifican dentro de la dependencia.
En comparación con las dependencias implícitas, las dependencias explícitas transmiten información menos específica. Esto significa que Terraform solo puede formular planes más conservadores para la creación, actualización y reemplazo de recursos en la falta de conocimiento de los atributos particulares que constituyen la dependencia. En la práctica, esto afecta la secuencia en la que Terraform crea los recursos y cómo Terraform determina si los recursos requieren actualizaciones o reemplazos.
Recomendamos usar dependencias explícitas con el metaargumento depends_on
solo como el último recurso cuando una dependencia entre dos recursos está oculta y no se puede expresar a través de dependencias implícitas.
En el siguiente ejemplo, los servicios del proyecto necesarios deben estar habilitados antes de crear un conjunto de datos de BigQuery. Esta dependencia se declara de forma explícita:
No se recomienda:
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
}
En el siguiente ejemplo, se reemplaza la dependencia explícita por una dependencia implícita mediante la referencia al argumento project_id
como el atributo de salida project_id
del recurso project_services
:
Recomendado:
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
}
El uso de dependencias implícitas permite declaraciones precisas de dependencias, como especificar la información exacta que se debe recopilar de un objeto ascendente. Esto también reduce la necesidad de realizar cambios en varios lugares, lo que, a su vez, reduce el riesgo de errores.
Haz referencia a los atributos de salida de los recursos dependientes
Cuando crees dependencias implícitas mediante la referencia a valores de recursos ascendentes, asegúrate de hacer referencia solo a atributos de salida, en particular valores que aún no se conocen. Esto garantizará que Terraform esperará a que se creen los recursos ascendentes antes de aprovisionar el recurso actual.
En el siguiente ejemplo, el recurso google_storage_bucket_object
hace referencia al argumento de nombre del recurso google_storage_bucket
. Los argumentos tienen valores conocidos durante la fase de planificación de Terraform. Esto significa que cuando Terraform crea el recurso google_storage_bucket_object
, no espera a que se cree el recurso google_storage_bucket
porque no hace referencia a un argumento conocido (el nombre del bucket) crea una dependencia implícita entre google_storage_bucket_object
y google_storage_bucket
. Esto elimina el propósito de la declaración de dependencia implícita entre los dos recursos.
No se recomienda:
# 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
}
En su lugar, el recurso google_storage_bucket_object
debe hacer referencia al atributo de salida id
del recurso google_storage_bucket_object
. Dado que el campo id
es un atributo de salida, su valor solo se establece después de que se ejecuta la creación de su recurso. Por lo tanto, Terraform esperará a que se complete la creación del recurso google_storage_bucket_object
antes de comenzar la creación del recurso google_storage_bucket_object
.
Recomendado:
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 veces, no hay un atributo de salida obvio para hacer referencia. Por ejemplo, considera el siguiente ejemplo, en el que module_a
toma el nombre del archivo generado como entrada. Dentro de module_a
, el nombre del archivo se usa para leer el archivo. Si ejecutas este código tal como está, obtendrás una excepción no such file or directory
, que se produce cuando Terraform intenta leer el archivo durante su fase de planificación, en el momento en el que el archivo se realiza. aún no se han creado. En este caso, un examen del atributo de salida del recurso local_file
revela que no hay campos obvios que puedas usar en lugar del argumento de entrada del nombre de archivo.
No se recomienda:
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
}
Para solucionar este problema, ingresa una dependencia explícita. Como práctica recomendada, asegúrate de agregar un comentario sobre por qué se necesita la dependencia explícita:
Recomendado:
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
}
¿Qué sigue?
- Obtén más información sobre las prácticas recomendadas para la comunicación entre configuraciones.
- Obtén más información sobre las prácticas recomendadas para trabajar con recursos de Google Cloud.