僕がTerraformをできるようになるまで

こんにちは。TIGの伊藤太斉です。
年末、いろいろ振り返るきっかけになりますが、私の今のキャリアから切っても切り離せないTerraformについて振り返ることにしてみました。
フューチャーに入社して以来、ずっとInfrastructure as Code（IaC）に関わってきて、特にTerraformはどの案件であっても常に触り続けてきました。今ではまっさらなところから1からTerraformを書いたり、運用する上で極力変更を減らすためのコード設計などを考えられるようになってきました。
しかし、入った当初はもちろん「Terraformとは？」であったので、そのギャップを埋めるために日々やっていたことを思い出しながら書きます。これからTerraformを書く人のハードルが少しでも下がれば幸いです。

## 触り始めたころ
私はフューチャーに入社して、参画した案件のクラウドリソースは全部Terraformでやっていると聞き、徐々に覚えていくことになりました。この時、外部の勉強会で少しTerraformは触ったくらいで、基本的には初学者といっても全く問題ないくらいです。
初めてTerraformでやっていたことは、コードのシンタックスの書き換えでした。例えば以下のような変更です。

```terraform
resource "google_compute_subnetwork" "subnet" {
  name          = "test-subnetwork"
  ip_cidr_range = "10.2.0.0/16"
  region        = "us-central1"
  network       = "${google_compute_network.custom-test.id}" # この書き換え
}

resource "google_compute_network" "network" {
  name                    = "test-network"
  auto_create_subnetworks = false
}
```

上記のサンプルにコメントを入れましたが、文字列に混ぜず、純粋に他リソースのパラメーターを取得するにも波カッコを利用した取得をしていましたが、これを全て以下の書き換えをしました。

```terraform
network       = "${google_compute_network.custom-test.id}"
↓
network       =　　google_compute_network.custom-test.id
```
書くならより新しい方へ、という気持ちでこの書き換えをして、1つの基盤を作っていました。
この経験を足がかりにして、Terraformの動きや書き方などを学んでいきました。

## 運用しやすいコード設計を考えた
次に体験として、私はSREとして顧客のクラウド環境のPoCから運用改善を行っていました。
PoCについてはTerraformがあまり関わる部分ではないので、ここでは割愛しますが、定型運用の設計を行うときにはTerraformをどう書けばオペミスを防ぐことができるか、を考えてコードを書くようになりました。
例えばGCPではCloud Armorという、ロードバランサの前段に設置するサービスがあります。当時扱っていたのは社内サービスだったので、定期的にセーフリストとして拠点のIPを追加する運用が発生します。
このとき、利用するコードは以下ですが、ブロックを拠点ごとに追加して、リソースのコードに直接変更を入れる運用は直感的ではないです。

```terraform
resource "google_compute_security_policy" "policy" {
  name = "my-policy"

  rule {
    action   = "allow"
    priority = 100
    match {
      versioned_expr = "SRC_IPS_V1"
      config {
        src_ip_ranges = ["192.168.0.0/28", "192.168.1.0/28"]
      }
    }
    description = "from Osaka Office"
  }

  rule {
    action   = "allow"
    priority = 101
    match {
      versioned_expr = "SRC_IPS_V1"
      config {
        src_ip_ranges = ["192.168.2.0/28", "192.168.3.0/28"]
      }
    }
    description = "from Sendai Office"
  }

  rule {
    action   = "deny(403)"
    ...
  }
}
```
こんなときにTerraformのFunctionは便利でdynamicを利用します。

```terraform
resource "google_compute_security_policy" "policy" {
  name = "my-policy"

  dynamic "rule" {
    for_each length(local.safe_ip_list)
    content {
      action   = "allow"
      priority = 100 + index(local.safe_ip_list, each.value)

      match {
        versioned_expr = "SRC_IPS_V1"
        config {
          src_ip_ranges = each.value[0]
        }
      }
    }

  rule {
    action   = "deny(403)"
    ...
  }
}

locals {
  safe_ip_list = [
    "xx.xx.xx.xx/u",
    "xx.xx.xx.xx/u",
    "xx.xx.xx.xx/u",
    ....
  ]
}
```
このような形で変数だけでリソースを制御する形にすることで運用としてかなり簡素にできたのではと思っています。

## AWSを構築した経験
GCPを利用していた案件のあとはAWSの案件に参画しました。この案件では1から構築を行っていたので、TerraformやAnsibleのディレクトリ設計から実装まで取り組みました。この案件では将来的に顧客がインフラコードを利用することになるので、

- シンプルなディレクトリ設計
- 必要以上にFunctionを利用しない

など、初めて見た人でもできるだけわかりやすいコード作りを心がけました。
ここはサンプルもないですが、将来的に誰が読むのかを考えてコードを書いていました。

## Modulesを使った経験
ある種、Terraformerとしての集大成だと振り返ってみれば思えることでした。
本記事で触れている内容では特に運用面を考えてひたすらTerraformを書いていました。変数だけで全て必要なリソースを制御できるようにして、事故を起こさない、起こらないようにしました。
詳細については[こちらの記事](https://future-architect.github.io/articles/20211029a/)をご覧ください。

## 最後に
これまでどんなふうに書いてきたかを考えてみると、少々しんみりするものもありますが、立場としても書くだけからリードする立場になったり、視座でも感じるものが変わってきたのかなと思います。
この記事は私の一例ですが、Terraformは公式ドキュメントに忠実に進めるのが1つのパターンだとも思うので、是非興味のある方は書いてみてください。