如何使模块依赖于Terraform中的另一个模块

时间:2020-07-27 06:37:44

标签: amazon-web-services terraform

我有2个模块,一个模块创建RDS集群,另一个模块创建EC2实例。我在主文件中调用了这两个模块:

module "instance" {
  source = "../instance"
  rds_endpoint    = module.databases.rds_cluster_endpoint

}

module "databases" {
  source      = "../databases"
}

在“实例”模块中,我有一个空资源,该资源基本上可以获取dump.sql文件,并尝试将mysql数据导入RDS群集。问题是由于某种原因,空资源会在RDS实例完成之前运行(当然会失败,因为端点尚未准备好)。我以为,通过在具有集群端点的“数据库”模块中定义输出将创建隐式依赖关系,因此我期望数据库模块首先完成,因为我在实例模块中引用了它,但这似乎没有就是这种情况。
显然,模块的显式depends_on是在terraform 0.13中实现的,但它是在beta中,因此,我们不能仅将整个基础架构移至0.13。还有其他方法吗?

3 个答案:

答案 0 :(得分:1)

我使用类似的模式在模块之间创建依赖关系,并且效果很好。不确定为什么在这种情况下不起作用可能是由于资源为空。您可以尝试从s3导入sql文件。参见文档here

resource "aws_db_instance" "db" {
  s3_import {
    source_engine         = "mysql"
    source_engine_version = "5.6"
    bucket_name           = "mybucket"
    bucket_prefix         = "backups"
    ingestion_role        = "arn:aws:iam::1234567890:role/role-xtrabackup-rds-restore"
  }
}

答案 1 :(得分:1)

您正在使用对rds_endpoint的引用为变量module.databases.rds_cluster_endpoint分配一个值,该引用声明了从“实例”中的variable "rds_endpoint"output "rds_cluster_endpoint"的依赖性在“数据库”模块中。

由于传递依赖的影响,这意味着“实例”模块中引用var.rds_endpoint的所有内容都将有效地依赖于“数据库”模块中output "rds_cluster_endpoint"块所依赖的所有内容。相反,对var.rds_endpoint的依赖 意味着完全取决于output "rds_cluster_endpoint"的依赖;除非您声明它为true,否则“数据库”模块中的其他所有内容都不会依赖。

请注意,模块本身不是依赖项节点:每个输入变量和输出值都是单独的依赖项节点,它允许Terraform通过开始操作来优化其工作。在模块中,因为 所依赖的特定输入变量已准备就绪,而不是等到所有 输入变量准备就绪。但是,这确实意味着您需要牢记每个输出值所依赖的内容以及模块中每个资源所依赖的输入变量。

如果您的配置中有表示hidden dependencies的对象-也就是说,即使没有基于引用的关系也需要特定的顺序-您可以在其中使用depends_on参数output "rds_cluster_endpoint"块或最终依赖于它的资源(或在某些情况下,两者都有!)向图添加其他依赖关系。

由于您没有共享两个模块本身的配置,因此无法显示具体示例,但这是在输出块中使用depends_on来引用{ {1}}表达式自然不依赖于:

value

我在这里使用output "rds_cluster_endpoint" { value = aws_db_instance.db.endpoint # The instance role must also be active before # this instance can be used, to avoid # authorization errors. depends_on = [aws_db_instance_role_association.main] } 对象只是因为这是“隐藏依赖项”的典型示例:由于这些对象的设计,Terraform默认将角色关联理解为取决于实例,而不是实例而不是相反(因为必须先创建实例),但是如果此数据库实例的下游用户希望能够使用S3集成,则分配的角色关联是此模块提供的功能的重要组成部分因此,任何依赖aws_db_instance_role_association的对象也应依赖于角色关联。您可能有一个不同于模型的隐藏依赖关系,而不是这个模型,但是将应用相同的模式。

另一方面,要确保“实例”模块中依赖RDS实例的所有内容都依赖于输出所依赖的相同对象。由于“实例”模块中需要RDS实例的对象通常已将rds_cluster_endpoint引用为其配置的一部分,因此出现此问题的频率降低。但是,在因某些原因而并非如此的异常情况下,您可以从必须等待实例准备好但在某些情况下不引用var.rds_endpoint的任何资源中添加对变量的显式依赖关系。原因:

var.rds_endpoint

即使Terraform 0.13确实具有模块级别的resource "null_resource" "example" { # if the arguments of this resource don't # already make use of var.rds_endpoint but # yet this resource must still wait until # the RDS instance is ready for some reason, # you can mark that explicitly: depends_on = [var.rds_endpoint] } ,还是最好在更高的细节层次上对依赖关系进行建模,就像我在上面所显示的那样,因为这样您的模块可以更容易使用(取决于特定输出是获得正确顺序所需要的全部),Terraform将能够更好地优化应用该模块所需的操作。


如果您已经声明了所有必要的依赖项,包括任何隐藏的依赖项,则问题可能出在Terraform和AWS提供程序能够看到的范围之外,不幸的是,这会使事情变得更难调试。

例如,depends_on的{​​{1}}属性包含一个DNS主机名,该主机名是在创建实例的过程中建立的,并且该DNS记录对于立即运行Terraform的计算机可能不可见创建实例后。

不幸的是,涉及AWS IAM的任何更改通常也需要花费几分钟,才能在所有AWS API端点上可见,因此,如果您使用IAM功能对数据库进行身份验证或对其他系统(例如S3)进行身份验证,则此操作可能会导致错误,因为在大多数情况下,AWS无法确定何时在所有地区的所有服务中完全应用了IAM更改。

如果您遇到这些问题之一,那么很遗憾,Terraform中的额外依赖关系不足以解决这个问题。例如,您可能需要更改正在运行的任何脚本以供应数据库,以使其对尚未完全准备好的数据库具有弹性,并在完全失败之前重试合理的次数。

AWS提供程序中的几种资源类型已经进行了这种轮询以解决AWS API的设计问题,但是,如果您正在AWS提供程序本身之外执行操作(例如,在预配程序运行的脚本中)不幸的是,您必须自己承担起这一责任,接受云计算平台是复杂的分布式系统,因此,它们通常要到API端点成功返回后的一段时间才能变得完全一致。

答案 2 :(得分:0)

在解决问题时,我不会对其进行标记,但这确实解决了我的问题: 当我对aws_rds_cluster有依赖关系时,集群将完成配置,但是aws_rds_cluster_instance尚未完成配置。我也通过依赖实例来解决此问题:

module "instance" {
  source = "../instance"
  rds_endpoint    = module.databases.rds_cluster_endpoint
  # This will make the instance module depend on the instance, 
  # which was the one that was not ready yet
  rds_instance_arn    = module.databases.rds_instance_arn
}