Terraform 使用所需的_提供程序和提供程序块进行地形形成

Terraform 使用所需的_提供程序和提供程序块进行地形形成,terraform,Terraform,我正在阅读一本terraform指南,其中作者正在使用docker\u图像和docker\u容器资源构建一个docker设置 在示例代码中,main.tf文件包括所需的提供程序和提供程序块,如下所示: terraform { required_providers { docker = { source = "kreuzwerker/docker" } } } provider "docker" {} 为什么两者都需要

我正在阅读一本
terraform
指南,其中作者正在使用
docker\u图像
docker\u容器
资源构建一个docker设置

在示例代码中,
main.tf
文件包括所需的
提供程序
提供程序
块,如下所示:

terraform {
  required_providers {
    docker = {
      source = "kreuzwerker/docker"
    }
  }
}

provider "docker" {}
为什么两者都需要

难道
terraform
不应该仅仅通过这一行就能够理解对
docker
提供商的需求吗

provider "docker" {}

需要提供
源代码
,因为它不是“官方”HashiCorp提供商之一。提供商注册表中可能有多个名为“docker”的提供商,因此需要提供
源代码
,以便准确地告诉Terraform下载哪个提供商。

考虑Terraform提供商时,需要考虑两个相关概念:提供商本身和提供商的配置

作为类比,这里的提供者
kreuzwerker/docker
有点像从另一个库导入的类,它的本地名称为
docker
。我将使用伪JavaScript语法使其更加具体:

var docker = require("kreuzwerker/docker");
然而,到目前为止,我们所拥有的只是类本身。为了使用它,我们需要创建一个它的实例,用Terraform的方言称之为“配置”。同样,使用伪JavaScript语法:

var dockerInstance = new docker({});
Terraform在这里的语法显然没有这个伪JavaScript表单那么明确,但我们可以通过向配置中添加第二个提供程序实例来使区别更加明显,在Terraform中,我们通过为其分配一个配置“别名”来做到这一点:

这类似于在我们的伪JavaScript示例中创建提供者“类”的第二个实例:

var dockerInstance2 = new docker({
  host: 'ssh://user@remote-host:22'
});
显示区别的另一个变体是当模块从其调用模块继承提供程序配置时。在这种情况下,调用模块就好像是在隐式地将提供者配置(实例)传递到模块中,但是子模块仍然需要导入提供者“类”,以便Terraform可以看到我们所说的
Kreuzzwerker/docker
,而不是任何其他名为“docker”的提供者

Terraform有一些自动的“魔法”行为,试图使简单的情况变得隐含,但不幸的是,这是以当事情变得更复杂时,更难理解发生了什么为代价的。提供程序和提供程序配置是一个特别困难的例子,因为提供者已经使用Terraform语言很长一段时间了,而该语言的当前版本正试图与简单用途保持广泛的向后兼容,同时仍然允许使用更新的功能,例如可以从多个名称空间安装第三方提供者

这里特别令人困惑的假设是,如果不声明特定的提供者Terraform将创建一个隐式的
required\u providers
声明,假设您指的是
hashicorp/
命名空间中的提供者,这使得
required\u providers
似乎只针对第三方提供者。事实上,这主要是一种向后兼容机制,因此我建议始终写出
必需的\u提供者
条目,即使是
hashicorp/
命名空间中的提供者,这样经验较少的读者就不必知道这种特殊的向后兼容行为。但在您的情况下,您使用的提供程序无论如何都位于第三方名称空间中,因此
required\u providers
条目是必需的

var dockerInstance2 = new docker({
  host: 'ssh://user@remote-host:22'
});