https://www.youtube.com/watch?v=0IQ4IScqQws&t=212s https://caddi.tech/archives/4320

terraform とは

公式ドキュメントです。読まないと…。

url: https://developer.hashicorp.com/terraform
title: "Terraform | HashiCorp Developer"
description: "Explore Terraform product documentation, tutorials, and examples."
host: developer.hashicorp.com
favicon: https://developer.hashicorp.com/favicon.ico
image: https://developer.hashicorp.com/og-image/terraform.jpg

terraform の第一歩がわかりやすく書かれています。

url: https://zenn.dev/oyasumipants/articles/6f8c03380d7171
title: "Terraform に入門する"
host: zenn.dev
image: https://res.cloudinary.com/zenn/image/upload/s--E_ibeTkq--/c_fit%2Cg_north_west%2Cl_text:notosansjp-medium.otf_55:Terraform%2520%25E3%2581%25AB%25E5%2585%25A5%25E9%2596%2580%25E3%2581%2599%25E3%2582%258B%2Cw_1010%2Cx_90%2Cy_100/g_south_west%2Cl_text:notosansjp-medium.otf_37:KeigoIbaraki%2Cx_203%2Cy_121/g_south_west%2Ch_90%2Cl_fetch:aHR0cHM6Ly9zdG9yYWdlLmdvb2dsZWFwaXMuY29tL3plbm4tdXNlci11cGxvYWQvYXZhdGFyLzZkZjFhM2RlZjkuanBlZw==%2Cr_max%2Cw_90%2Cx_87%2Cy_95/v1627283836/default/og-base-w1200-v2.png

terraform の基本やスタイルガイド・モジュールなどあらゆることがわかりやすく書かれており、とりあえずこちらを見たほうがよさそうです

url: https://speakerdeck.com/emiki/terraform-this-and-that
title: "Terraformあれやこれ/terraform-this-and-that"
description: "2024/4/19(金)JAWS-UG朝会 #56https://jawsug-asa.connpass.com/event/312976/登壇資料です。"
host: speakerdeck.com
favicon: https://d1eu30co0ohy4w.cloudfront.net/assets/favicon-bdd5839d46040a50edf189174e6f7aacc8abb3aaecd56a4711cf00d820883f47.png
image: https://files.speakerdeck.com/presentations/878ebc08f3554cc8969086bf6ce0c911/slide_0.jpg?31391084

terraform における drift の解決方法など、基本から応用までわかりやすく説明されています。

url: https://caddi.tech/archives/4320
title: "第3回: Terraformの基本とステート管理 - CADDi Tech Blog"
description: "※本記事は、技術評論社「Software Design」(2023年6月号)に寄稿した連載記事「Google Cloudで実践するSREプラクティス」からの転載です。発行元からの許可を得て掲載しております。 はじめに 前回はIaCの考え方や必要性と、筆者らが採用しているTerraformの特徴について紹介しました。今回は今後紹介するプラクティスの前提となるTerraformに触れたことのない方のために、その基本を簡単に紹介します1。 ここで紹介できない事項やTerraformのインストール方法については、HashiCorp 社やGoogleCloudのチュートリアル2を参考にしてください。ぜひ…"
host: caddi.tech
favicon: https://caddi.tech/icon/link
image: https://cdn.image.st-hatena.com/image/scale/5556d88c5f458a98d86fafbbf99e917f1b37493a/backend=imagemagick;version=1;width=1300/https%3A%2F%2Fcaddi.tech%2Fwp-content%2Fuploads%2F2023%2F07%2FTerraform-basic.drawio.png

terraform の設計をどうすべきか

第一に Standard Module Structure (Official) を参考にします。

url: https://developer.hashicorp.com/terraform/language/modules/develop/structure
title: "Standard Module Structure | Terraform | HashiCorp Developer"
description: "Learn about the recommended file and directory structure for developing reusable modules distributed as separate repositories."
host: developer.hashicorp.com
favicon: https://developer.hashicorp.com/favicon.ico
image: https://developer.hashicorp.com/og-image/terraform.jpg

続いて、GCP ならびに Future さんの設計ガイドラインを参考にします。

url: https://cloud.google.com/docs/terraform/best-practices/general-style-structure?hl=ja
title: "一般的なスタイルと構造に関するベスト プラクティス  |  Terraform  |  Google Cloud"
host: cloud.google.com
image: https://cloud.google.com/_static/cloud/images/social-icon-google-cloud-1200-630.png?hl=ja
url: https://future-architect.github.io/arch-guidelines/documents/forTerraform/terraform_guidelines.html
title: "Terraform設計ガイドライン | フューチャー株式会社"
description: "フューチャー株式会社の有志が作成する<wbr>良いアーキテクチャを実現するための設計ガイドライン"
host: future-architect.github.io
favicon: https://future-architect.github.io/arch-guidelines/favicon.ico

また、下記の講演も非常にわかりやすいです。 State 管理・ファイル・ディレクトリ管理など、 terraform のベストプラクティスがきれいにまとめられています。

url: https://www.youtube.com/watch?v=0IQ4IScqQws
title: "I-2 : 「それ、どこに出しても恥ずかしくないTerraformコードになってるか?」"
description: "✨講師:吉田 祐樹 (アマゾン ウェブ サービス ジャパン合同会社 Professional Services)✨セッション概要: ある日、父にこんなことを言われたあなたは考えます。そういえばMartin Fowlerもこんなことを言っていたな。。。「コンパイラがわかるコードは誰にでも書ける。すぐれたプログラマは..."
host: www.youtube.com
favicon: https://www.youtube.com/s/desktop/ba3a814f/img/logos/favicon_32x32.png
image: https://i.ytimg.com/vi/0IQ4IScqQws/maxresdefault.jpg?sqp=-oaymwEmCIAKENAF8quKqQMa8AEB-AHUBoAC4AOKAgwIABABGH8gMCg6MA8=&rs=AOn4CLA1OluZwhX6MNIjID0rIQ3jWIUQbQ

terraform で疑問に思ったこととその答え

ChatGPT 含む AI ツールに聞いています。

ファイル名に制約はあるのか

terraform ではディレクトリにある *.tf をすべて読み込み 1 つの構成として扱います。 ここで、ファイルは

  • network.tf
  • compute.tf
  • database.tf

のように役割で分割することが推奨されているようです。

よって、必ずしも main.tf が必要である、というわけではありません。 エントリーポイントとして main.tf が利用されるようです。

https://speakerdeck.com/hiyanger/terraform-yarunarasutairugaidowodu-mou-zhong-yao-xiang-mu-10xuan

ディレクトリ構成をどうすべきか?

https://developer.hashicorp.com/terraform/language/modules/develop/structure https://dev.classmethod.jp/articles/terraform_speaker_report_jawsug_tokyo/

環境ごとにディレクトリを切り、その環境の main.tf で必要なモジュールをインポートするのがよいようです。 そして modules で各モジュールにあうディレクトリを切ります。

.
├── environments/
   ├── production/
   ├── main.tf
   └── terraform.tfvars
   └── staging/
       ├── main.tf
       └── terraform.tfvars
└── modules/
    ├── vpc/
   ├── main.tf
   └── ...
    └── webapp/
        ├── main.tf
        └── ...

variables.tf とは?

terraform で利用する変数を多くの場合 variables.tf で宣言します。

variable "instance_type" {
  type        = string
  default     = "t2.micro"
}

明確には variables.tf という名前でなくてもよいです。 main.tf などに変数を定義してもよいです。

.tfvars とは?

variables.tf で定義した変数について、実際に値を設定するファイルです。 -var-file= で指定します。

aws_access_key    = "XXXXXXXXXXXXXXXXXXXX"
aws_secret_key    = "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"

outputs.tf とは?

network/output.tf に下記のように定義していたとします。

output "instance_ip" {
  value = aws_instance.example.public_ip
}

このとき、上記を environment/dev/main.tf で webapp/hoge.tf に引き渡すことで、ネットワークの IP を webapp に渡せます。 詳しくは https://dev.classmethod.jp/articles/terraform_speaker_report_jawsug_tokyo/ にあります。

tfstate とは?

https://zenn.dev/spacemarket/articles/b7bd1422b896ca https://zenn.dev/sway/articles/terraform_biginner_tfstate

terraform が管理するインフラの状態を管理する JSON ファイルです。 terraform は

  • Desired State
    • 各種 tf ファイルによって宣言された構成
  • Real State
    • GCP, AWS 上にある実際のインフラ
  • tfstate
    • 前回の terraform コマンド実行時のインフラ状態を記録した JSON

を比べたうえでおこなうべき変更を apply します。

  1. tfstate と Desired State (tf ファイル) を比べて、どのような変更をしたいのかを見つける
  2. tfstate に記録されている Resource ID をもとに、GCP/AWS に問い合わせて実際の状態を取得する
  3. 3状態すべてを考慮したうえで、変更内容を決める

という流れです。

tfstate の記事を試す

https://zenn.dev/sway/articles/terraform_biginner_tfstate を試したところ、 hello.tf によって生成された tfstate は以下のようになっていました。

  • terraform の version
  • resource の状態
    • name: helloworld
    • provider: local
    • instance
      • text: hello world

が入っています。

resource "local_file" "helloworld" {
    content         = "hello world!"
    filename        = "hello.txt"
    file_permission = "0777"
}
{
  "version": 4,
  "terraform_version": "1.12.2",
  "serial": 1,
  "lineage": "7a8ec19f-7c87-93bd-9d95-5d0797d86b96",
  "outputs": {},
  "resources": [
    {
      "mode": "managed",
      "type": "local_file",
      "name": "helloworld",
      "provider": "provider[\"registry.terraform.io/hashicorp/local\"]",
      "instances": [
        {
          "schema_version": 0,
          "attributes": {
            "content": "hello world!",
            "content_base64": null,
            "content_base64sha256": "dQnlvaDHYtK6x/kNdYtbImP6Acy8VCq1498WO+CObKk=",
            "content_base64sha512": "25sc0yYt7jd1agm5BklzWJhHyqjlPTGp0ULqJwGxsoq9l4OLuaJwaLowXcjQSkWh/PB53lTWB2ZplrPMVPa2fA==",
            "content_md5": "fc3ff98e8c6a0d3087d515c0473f8677",
            "content_sha1": "430ce34d020724ed75a196dfc2ad67c77772d169",
            "content_sha256": "7509e5bda0c762d2bac7f90d758b5b2263fa01ccbc542ab5e3df163be08e6ca9",
            "content_sha512": "db9b1cd3262dee37756a09b9064973589847caa8e53d31a9d142ea2701b1b28abd97838bb9a27068ba305dc8d04a45a1fcf079de54d607666996b3cc54f6b67c",
            "directory_permission": "0777",
            "file_permission": "0777",
            "filename": "hello.txt",
            "id": "430ce34d020724ed75a196dfc2ad67c77772d169",
            "sensitive_content": null,
            "source": null
          },
          "sensitive_attributes": [
            [
              {
                "type": "get_attr",
                "value": "sensitive_content"
              }
            ]
          ],
          "identity_schema_version": 0
        }
      ]
    }
  ],
  "check_results": null
}

.terraform ディレクトリには必要になる provider (local) のバイナリが入っていました。

Imgur

強引に hello.txt を hello WORLD! に書き換えてから terraform plan したところ、 desired と tfstate の差分が検知され、変更予定の内容が表示されました。 apply すると hello, world! にちゃんと修正されます。

hello WORLD!
❯ terraform plan
local_file.helloworld: Refreshing state... [id=430ce34d020724ed75a196dfc2ad67c77772d169]

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # local_file.helloworld will be created
  + resource "local_file" "helloworld" {
      + content              = "hello world!"
      + content_base64sha256 = (known after apply)
      + content_base64sha512 = (known after apply)
      + content_md5          = (known after apply)
      + content_sha1         = (known after apply)
      + content_sha256       = (known after apply)
      + content_sha512       = (known after apply)
      + directory_permission = "0777"
      + file_permission      = "0777"
      + filename             = "hello.txt"
      + id                   = (known after apply)
    }

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

続いて hello, world! の状態で terraform.tfstate を削除しました。 その状態で plan すると下記のように差分がある、とのように表示されました。

これは

  • hello.txt には hello, world! というテキストは正しく入っている
  • しかし、 terraform.tfstate がないため terraform は未実行だと判断している

とわかります。

❯ terraform plan

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # local_file.helloworld will be created
  + resource "local_file" "helloworld" {
      + content              = "hello world!"
      + content_base64sha256 = (known after apply)
      + content_base64sha512 = (known after apply)
      + content_md5          = (known after apply)
      + content_sha1         = (known after apply)
      + content_sha256       = (known after apply)
      + content_sha512       = (known after apply)
      + directory_permission = "0777"
      + file_permission      = "0777"
      + filename             = "hello.txt"
      + id                   = (known after apply)
    }

Plan: 1 to add, 0 to change, 0 to destroyy

apply するとファイルが更新されたようです。

Enter a value: yes

local_file.helloworld: Creating...
local_file.helloworld: Creation complete after 0s [id=430ce34d020724ed75a196dfc2ad67c77772d169]

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

このように tfstate を消してしまうと実際にリソースが存在したとしても作り直してしまうため、ちゃんと S3 / GCS などの backend に tfstate を保存しないと駄目ですね。

providers.tf とは?

GCP, AWS など、各プロバイダーごとに設定したい内容を記述します。 provider block で記述します。

terraform block とは?

providers block とは対象的に、 terraform 全体とした設定を記述します。 必要になるプロバイダプラグインの指定や backend file を指定します。

terraform {
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 4.0"
    }
  }
 
  backend "s3" {
    bucket = "my-terraform-state-bucket"
    key    = "production/terraform.tfstate"
    region = "ap-northeast-1"
  }
 
  required_version = "~> 1.0"
}

linter / test をどうするのがよいか

linter

https://github.com/terraform-linters/tflint

tflint という terraform の linter があります。 これを利用してベストプラクティスにそった tf になっているか?を CD でチェックするのがよさそうです。

https://www.checkov.io/ checkov というセキュリティチェックツールもあるようですが個人であれば導入しなくてもよいですね。

test

https://zenn.dev/kyohei_saito/articles/a32b5a11c81e97

terraform test というコマンドがあり plan → apply を実際に実行して想定どおりの変更になっているか? を assert できるようです。 こちらは個人で導入してもよさそうですね。