Terraformのoutputとは何か

Terraformには`output`というものがあります。
ただ、Terraformでは簡単な構成で構築するくらいしかしたことがない私は、今まで`output`を使わなくてもいけていたので、どういう時に`output`を使えば良いのかよく分かっていませんでした。

そこで今回Terraformのoutputについて調べてまとめてみました。

:::note warn
Terraformは初心者なので、間違っていることなどがあったらコメントいただけると嬉しいです。
:::

## Output について

https://www.terraform.io/language/values/outputs

Terraformのドキュメントを見るとユースケースとして以下の3点が挙げられています。

- A child module can use outputs to expose a subset of its resource attributes to a parent module.
- A root module can use outputs to print certain values in the CLI output after running `terraform apply`.
- When using remote state, root module outputs can be accessed by other configurations via a `terraform_remote_state` data source.

## 1. `terraform apply`を実行後にCLIにプリントされる

一番最初に思い浮かぶのはこれかと思います。
ルートモジュールでoutputをすると、outputで宣言した値が出力されます。

[Learn](https://learn.hashicorp.com/tutorials/terraform/outputs?in=terraform/configuration-language)のサンプルを一部引用すると、

```tf
output "vpc_id" {
  description = "ID of project VPC"
  value       = aws_vpc.vpc.id
}
```

のように宣言しておくと、

```bash
$ terraform apply

...(略)

Apply complete! Resources: 0 added, 0 changed, 0 destroyed.

Outputs:

vpc_id = "vpc-004c2d1ba7394b3d6"
```

のようにapply後に分かる値についても出力することができます。

ただ、これだけだとそうなんだ？くらいにしか思っていなかったのですが、`terraform output`コマンドを使うことで、自動化などの利用の幅が広がりそうということが分かりました。

### `terraform output`

上記の例でoutputに指定したものは以下のように出力することができます。

```bash
$ terraform output -json
{
  "vpc_id": {
    "sensitive": false,
    "type": "string",
    "value": "vpc-004c2d1ba7394b3d6"
  }
}
```

そして個別の値も取得することができるので、apply後にその値を使ってオペレーションを自動化したい時に使えそうです。

```bash
$ terraform output vpc_id
vpc-004c2d1ba7394b3d6
```

## 2. 子モジュールの属性を親モジュールに公開できる

`module`は構成を論理コンポーネントに整理するだけでなく、カプセル化をすることができます。

これによって、あるmoduleで作られたresourceの出力値は、ルートモジュール以外のモジュールでは直接参照することができません。

そのため、子モジュールのresourceの出力値を他のmoduleで参照したい場合は、子モジュールで`output`を定義して、ルートモジュールが別のmoduleを呼び出す時にvariableとして渡すという使い道があります。

例えば`network`というモジュールの`vpc_id`を、別のmoduleで使いたい場合、使いたいanotherモジュールでは以下のようにvariableを定義します。

```tf:modules/another/variables.tf
variable "vpc_id" {}
```

そして先程のように出力するモジュールにて`vpc_id`を出力したあと、以下のようにルートモジュールでanother_moduleにoutputした値をvariableとして渡してあげることで、

```tf
module "another_module" {
  source = "./modules/another"
  vpc_id = module.network.vpc_id
}
```

anotherモジュールのresourceで以下のように使うことができるようになります。

```tf:modules/another/main.tf
resource "..." "..." {
  vpc_id = var.vpc_id
}
```

## 3. `terraform_remote_state`を使うことで他の構成からアクセスできる

`terraform_remote_state`データソースについてのドキュメントはこちらです。

https://www.terraform.io/language/state/remote-state-data

`terraform_remote_state`を使うことで、ルートモジュールで出力した値を、別のTerraformプロジェクトから読み込むことができるようです。

あるTerraformプロジェクトで以下のようにstateのbackendをS3に設定していて、そのルートモジュールで何らかの値をoutputしていた場合、[^1]

[^1]: https://www.terraform.io/language/settings/backends/s3 の例を参考

```tf:プロジェクトA
terraform {
  backend "s3" {
    bucket = "mybucket"
    key    = "network/terraform.tfstate"
    region = "us-east-1"
  }
}
```

呼び出しをしたい別のプロジェクトから対象のS3にアクセスできる権限を付与した上で、以下のようなデータソースを設定することで、

```tf:プロジェクトB
data "terraform_remote_state" "network" {
  backend = "s3"
  config = {
    bucket = "mybucket"
    key    = "network/terraform.tfstate"
    region = "us-east-1"
  }
}
```

プロジェクトAでoutputをした出力をプロジェクトBのリソースで参照することができるようです。

```tf:プロジェクトB
resource "..." "..." {
  vpc_id = data.terraform_remote_state.network.vpc_id
}
```

## まとめ

Terraformのoutputのユースケースとしては主に以下の3点があります。

1. `terraform apply`を実行後にCLIにプリントする
2. 子モジュールの属性を親モジュールに公開する
3. `terraform_remote_state`を使い、他の構成からアクセスする

Terraformで管理しているリソースが増え、適切にコンポーネント分割、stateの分割をしようとした時に必要になってきそうなので、知ることができてよかったです。

もし誤りや他のユースケース等がありましたらご教示いただけるととても嬉しいです。

## 参考

- [Output Values - Configuration Language | Terraform by HashiCorp](https://www.terraform.io/language/values/outputs)
- [Output Data from Terraform | Terraform - HashiCorp Learn](https://learn.hashicorp.com/tutorials/terraform/outputs)
- [Backend Type: s3 | Terraform by HashiCorp](https://www.terraform.io/language/settings/backends/s3)