

本文属于机器翻译版本。若本译文内容与英语原文存在差异，则一律以英文原文为准。

# 了解 Terraform 数据源
<a name="data-sources"></a>

部署堆栈通常依赖来自先前现有资源的数据。大多数 IaC 工具都有一种方法可以导入由其他流程创建的资源。这些导入的资源通常是只读的（尽管 [IAM 角色](https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_iam.IRole.html#attachwbrinlinewbrpolicypolicy)是一个明显的例外），用于访问堆栈中资源所需的数据。 AWS CloudFormation 允许导入资源，但是通过查看. 可以更好地解释这个想法 AWS Cloud Development Kit (AWS CDK)。

可 AWS CDK 帮助开发人员使用现有的编程语言生成 CloudFormation模板。 AWS CDK 操作的最终结果是在中导入资源 CloudFormation。但是，与使用的语法可以更 AWS CDK 轻松地与 Terraform 进行比较。以下是使用导入资源的示例 AWS CDK。

```
const importedBucket: IBucket = Bucket.fromBucketAttributes(
    scope,
    "imported-bucket",
    {
        bucketName: "My_S3_Bucket"
    }
);
```

导入的资源通常是通过在用于创建相同类型的新资源的同一个类上调用静态方法来创建的。调用`new Bucket(...`将创建新资源，调用`Bucket.fromBucketAttributes(...`导入现有资源。您可以将存储桶属性的子集传递到函数中，这样他们 AWS CDK 就可以找到正确的存储桶。但是，另一个区别是，创建新存储桶会返回该`Bucket`类的完整实例，其中包含所有可用的属性和方法。导入资源会返回`IBucket`，该类型仅包含`Bucket`必须具备的属性。尽管您可以从外部堆栈导入资源，但使用该资源的选项是有限的。

在 Terraform 中，使用[数据](https://developer.hashicorp.com/terraform/language/data-sources)源可以实现类似的目标。大多数定义的 Terraform 资源旁边都有附带的数据源。以下是 Terraform S3 存储桶资源及其相应数据源的示例。

```
# S3 Bucket resource:
resource "aws_s3_bucket" "My_S3_Bucket" {
  bucket = "My_S3_Bucket"
}

# S3 Bucket data source:
data "aws_s3_bucket" "My_S3_Bucket" {
  bucket = "My_S3_Bucket"
}
```

这两项之间的唯一区别是名称前缀。如数据源的[文档](https://registry.terraform.io/providers/hashicorp/aws/latest/docs/data-sources/s3_bucket)所示，可以传递给数据源的参数少于资源。这是因为资源使用这些参数来声明新 S3 存储桶的所有属性，而数据源只需要足够的信息来唯一地识别和导入现有资源的数据。

Terraform 资源和数据源的语法相似可能很方便，但也可能存在问题。对于新手 Terraform 开发者来说，在配置中不小心使用了数据源而不是资源是很常见的。Terraform 数据源始终是只读的。您可以使用它们代替相应的资源进行读取操作（例如向其他资源提供 ID 名称）。但是，你不能将它们用于写入操作，这会从根本上改变底层资源的某些方面。因此，您可以将 Terraform 数据源视为底层资源的克隆版本。

与之前的 AWS CDK iBucket 示例类似，数据源对于只读场景非常有用。如果您需要从现有资源获取数据，但不需要在堆栈中维护该资源，请使用数据源。这方面的一个很好的例子是，当你创建使用账户默认 VPC 的 Amazon EC2 实例时。由于该 VPC 已经存在，因此您只需提取其数据即可。以下代码示例展示了如何使用数据来识别目标 VPC。

```
data "aws_vpc" "default" {
  default = true
}

resource "aws_instance" "instance1" {
  ami           = "ami-123456"
  instance_type = "t2.micro"
  subnet_id     = data.aws_vpc.default.main_route_table_id
}
```