Terraformで環境変数を使用する

# はじめに
[前回](https://qiita.com/dingtianhongjie/items/485c8abf7b3af9529f69)TerraformでOCIのVCNを作成しましたが、各変数をtfファイルに直接設定しました。
ただ、IaCの基本としては環境変数は別ファイルで管理すべきだと思いますので、今回はこの方法を確認します。
作成するリソースは前回と同じVCNです。

# Terraformの設定

## 変数の宣言
以下の`variables.tf`を作成し、各値が変数であることを宣言します。
任意でデフォルト値を設定したり、descriptionを記載することもできます。

ファイル名は自由ですが、`variables.tf`とするのが一般的のようです。

```variables.tf
## provider
variable "tenancy_ocid" {
  type = string
}
variable "user_ocid" {
  type = string
}
variable "private_key_path" {
  type = string
}
variable "fingerprint" {
  type = string
}
variable "region" {
  type = string
}

## vcn-module
variable "compartment_id" {
  type = string
}
variable "create_internet_gateway" {
  type = bool
  default = true
}
variable "create_nat_gateway" {
  type = bool
  default = true
}
variable "create_service_gateway" {
  type = bool
  default = true
}
variable "vcn_name" {
  type = string
}
```

## 変数の設定
以下の`terraform.tfvars`に各変数を設定します。
ファイル名が`terraform.tfvars`の場合は、Terraform実行時にファイルの内容が読み込まれます。
なお、Internet Gatewayなどはデフォルト`True`にしていますので、設定していません。

```terraform.tfvars
tenancy_ocid = "ocid1.tenancy.oc1..aaaaaaaa3mxxxxxxxxxxxxxxxxxxxca"
user_ocid = "ocid1.user.oc1..aaaaaaaxxxxxxxxxxxxxxxxfa"
private_key_path = "/home/xxx/.oci/xxxxxxxxxxxxxx.pem"
fingerprint = "3d:68:a5:f1:d5:36:xxxxxxxxxxxxxxxxxxxx"
region = "ap-xxxxxxxx-1"

compartment_id = "ocid1.compartment.oc1..aaaaaaaamxxxxxxxxxxxxxxxxxxxxxx5a"
vcn_name = "tf-vcn"
```

## 設定ファイルの編集
各設定ファイルの変数を`var.<variables.tfで宣言した変数名>`に書き換えます。

```provider.tf
provider "oci" {
  tenancy_ocid = var.tenancy_ocid
  user_ocid = var.user_ocid
  private_key_path = var.private_key_path
  fingerprint = var.fingerprint
  region = var.region
}

terraform {
  required_providers {
    oci = {
      source  = "oracle/oci"
    }
  }
}
```

```vcn-module.tf
module "vcn" {
  source  = "oracle-terraform-modules/vcn/oci"
  version = "3.5.5"
  # insert the 1 required variable here

  compartment_id = var.compartment_id

  # Optional Inputs
  create_internet_gateway = var.create_internet_gateway
  create_nat_gateway = var.create_nat_gateway
  create_service_gateway = var.create_service_gateway
  region = var.region
  vcn_name = var.vcn_name
}
```

全部で以下のファイルがあります。

```
$ ls -l
total 40
-rw-rw-r--. 1 opc opc   683 Nov  6 04:47 outputs.tf
-rw-rw-r--. 1 opc opc   265 Nov  6 05:30 provider.tf
-rw-rw-r--. 1 opc opc   450 Nov  6 05:26 terraform.tfvars
-rw-rw-r--. 1 opc opc   530 Nov  6 05:31 variables.tf
-rw-rw-r--. 1 opc opc   387 Nov  6 05:31 vcn-module.tf
```

https://github.com/dingtianhongjie/terraform/tree/main/tf-vcn-variable

# Terraformの実行

`terraform init/plan/apply`してVCNが作成されることを確認します。
（前回と同じなので割愛）

# 変数の指定
構成は同じだけど変数が違うこともあると思います。
この場合は、`terraform plan/apply`の時に`-var-file=`オプションでtfvarsファイルを指定できます。

今回は開発環境と本番環境を想定して`vcn_name`だけを変更した二つのファイルを用意しました。

```dev/dev.tfvars 
tenancy_ocid = "ocid1.tenancy.oc1..aaaaaaaa3mxxxxxxxxxxxxxxxxxxxca"
user_ocid = "ocid1.user.oc1..aaaaaaaxxxxxxxxxxxxxxxxfa"
private_key_path = "/home/xxx/.oci/xxxxxxxxxxxxxx.pem"
fingerprint = "3d:68:a5:f1:d5:36:xxxxxxxxxxxxxxxxxxxx"
region = "ap-xxxxxxxx-1"

compartment_id = "ocid1.compartment.oc1..aaaaaaaamxxxxxxxxxxxxxxxxxxxxxx5a"
vcn_name = "tf-vcn-dev"
```

```prod/prod.tfvars 
tenancy_ocid = "ocid1.tenancy.oc1..aaaaaaaa3mxxxxxxxxxxxxxxxxxxxca"
user_ocid = "ocid1.user.oc1..aaaaaaaxxxxxxxxxxxxxxxxfa"
private_key_path = "/home/xxx/.oci/xxxxxxxxxxxxxx.pem"
fingerprint = "3d:68:a5:f1:d5:36:xxxxxxxxxxxxxxxxxxxx"
region = "ap-xxxxxxxx-1"

compartment_id = "ocid1.compartment.oc1..aaaaaaaamxxxxxxxxxxxxxxxxxxxxxx5a"
vcn_name = "tf-vcn-prod"
```

init/planします。

```
$ terraform init
・・・
$ terraform plan -var-file=dev/dev.tfvars
・・・
  # module.vcn.oci_core_vcn.vcn will be created
・・・
      + display_name                     = "tf-vcn-dev"
```

VCN名が`dev/dev.tfvars`ファイルで指定した値になっていることが確認できます。
続いて、applyします。

```
$ terraform apply -var-file=dev/dev.tfvars
・・・
      + display_name                     = "tf-vcn-dev"
・・・
Apply complete! Resources: 8 added, 0 changed, 0 destroyed.
・・・
```

ただ、この状態で本番環境のVCNを作ろうとすると、作成ではなく変更になります。
これはTerraformの状態を保存するStateファイルがtfファイルと同じディレクトリに作られるからですね。

```
$ terraform plan -var-file=prod/prod.tfvars
・・・
Terraform will perform the following actions:

  # module.vcn.oci_core_vcn.vcn will be updated in-place
  ~ resource "oci_core_vcn" "vcn" {
      ~ display_name             = "tf-vcn-dev" -> "tf-vcn-prod"
        id                       = "ocid1.vcn.oc1.ap-sydney-1.amaaaaaassl65iqadp2hm26fetqiws7nbhnvmqglcdb6ko7x265rkufhbyqa"
        # (16 unchanged attributes hidden)
    }

Plan: 0 to add, 1 to change, 0 to destroy.
```

このような場合はtfファイルも分けておかないといけないようです。
検索してみるとディレクトリ構造の例がいくつか出てきますので、それらを参考に設計しないといけないですね。