Terraform基本構文メモ

# HCL2とは？
Hashi Corp Language 2 の略称
HashiCorp社独自言語

# HCL2の特徴
- コメントが書ける
- ":"ではなく"="で指定
- ヒアドキュメントが利用可能
- ブロック単位で記述する
```terraform
resource <RESOUCE_TYPE> <RESOUCE_NAME> {
 ...
}
```

- ブロックタイプ一覧

|種類  |説明  |
|---|---|
|locals|外部から変更できないローカル変数|
|variable|外から変更可能な変数|
|terraform|Terraformの設定|
|provider|プロバイダ|
|data|Terraform管理していないリソースの取り込み|
|resource|Terraform管理対象となるリソース|
|output|外部から参照できるようにする値|

# 変数(locals, variables)
- locals, variables ブロック
```terraform
locals {
 ...
}
```
```terraform
variable {
 ...
}
```
- 変数の種類

|種類|説明|
|---|---|
|locals|ローカル変数。<br>プライベートな変数で外部から変更はできない。|
|variable|外から変更可能な変数。<br>コマンドライン実行時にオプションやファイル指定で上書きできる。|

- localsの定義と参照
```terraform
locals {
  # 変数名 = 変数の値
  project = "tastylog"
  env     = "dev"
}

resource <RESOURCE_TYPE> <RESOURCE_NAME> {
  # ${local.<NAME>} で参照
  Tags = {
    Name = "${local.project}-${local.env}-vpc"
  }
```
- variableの定義と参照
```terraform
variable "project" {
  # variable の後が変数名
  # type が変数の型
  # default が変数のデフォルト値
  type = string
  default = "testlog"
}

resource <RESOURCE_TYPE> <RESOURCE_NAME> {
  # ${var.<NAME>} で参照
  Tags = {
    Name = "${var.project}-dev-vpc"
  }
```

# データ型
- HCL2で扱えるデータ型
    - プリミティブ

    |型名|説明|
    |---|---|
    |string|Unicode文字列|
    |number|数値。整数と少数の両方を表現|
    |bool|true/falseの2値|
    
    - 構造体

    |型名|説明|
    |---|---|
    |object({<NAME>=<TYPE>, ...})|キーバリュー型データ|
    |tuple([<TYPE>, ...])|数値。整数と少数の両方を表現|

    - コレクション

    |型名|説明|
    |---|---|
    |list(<TYPE>)|特定の型で構成される配列|
    |map(<TYPE>)|キーが文字列の配列|
    |set(<TYPE>)|値の重複がない配列|

- プリミティブ型
```terraform
variable "message" {
  type = string
  default = "Hello World"
}

variable "max_count" {
  type = number
  default = "10"
}

variable "is_enable" {
  type = bool
  default = "true"
}
```

- 構造体　object
キーバリュー形式で定義されるデータ型
```terraform
variable "obj_sample" {
  type = object({
    name = string
    age  = number
  })
  default = {
    name = "tanaka"
    age  = 28
  }
}

username = var.obj_sample.name
```

- 構造体 tuple
配列のN番目にどういった型を使うかが決められたデータ型
```terraform
variable "tuple_sample" {
  type = tuple([
    string, number
  ])
  default = ["tanaka", 28]
}

username = var.obj_sample[0]
```

- コレクション list
全て同じ型で指定される配列
```terraform
variable "list_sample" {
  type    = list(string)
  default = ["tanaka", "sato"]
}

username = var.list_sample[0]
```

- コレクション map
キーが文字列、バリューが指定された型となる配列
```terraform
variable "map_sample" {
  type    = map(string)
  default = {
    "High" = "m5.2xlarge"
    "Mid"  = "m5.large"
    "Low"  = "t2.micro"
  }
}

instance = var.map_sampole.High
```

- コレクション set
バリューの重複が排除される配列
```terraform
variable "set_sample" {
  type    = set(string)
  default = [
    "tanaka",
    "sato",
    "tanaka",
    "sato"
  ]
}

[for itm in var.set_sample : itm]
```

# 外部から変数を与える
- 変数の上書き方法
外部から変数値を与える方法は3種類
    |種類|説明|
    |---|---|
    |環境変数|環境変数へあらかじめ設定してある値を利用する。<BR>`TF_VAR_<NAME>`|
    |変数ファイル|あらかじめ決められた変数ファイル名のファイルに指定する。<BR>`terraform.tfvars`|
    |コマンド引数|以下のコマンド引数で指定された値を利用する。<BR>`-var <NAME>=<VALUE>`<BR>`-var-file <FILE_PATH>`|

- 環境変数を使った上書き

ソースコード(main.tf)
```terraform
variable = "message" {
  type    = string
  default = "nothing"
}
```

環境変数定義、ビルド実行

```s
$ export TF_VAR_message="Hello World!"
$ terraform apply
```

- 変数ファイルを使った上書き

ソースコード(main.tf)
```terraform
variable = "message" {
  type    = string
  default = "nothing"
}
```

変数ファイル(terraform.tfvars)
```
message = "Hello World!"
```

ビルド実行
```s
$ terraform apply
```

- コマンドを使った上書き

ソースコード(main.tf)
```terraform
variable = "message" {
  type    = string
  default = "nothing"
}
```

変数を指定したコマンド実行
```s
$ terraform apply -var message="Hello World!"
```

- 変数の上書き使い分け
    |種類|使い分け|
    |---|---|
    |環境変数|実行ログに残らない(tfstateには場合により出力される)<BR>鍵情報（ファイルとして残したくないもの）、環境依存情報(dev,stgなど。運用管理サーバーで作業すような厳格な場合)|
    |変数ファイル|git管理できる = 構造管理として残せる<BR>ロジック(プロビジョン手続)とデータ（変数）は切り離すことでgit管理したとき変更箇所が分かりやすくなる|
    |コマンド引数|実行ログに残る<BR>テストで部分的に変更したい、デバッグで一部変更したいなど一時的な利用|

# terraformブロック

- Terraform全体に関わる設定
```terraform
terraform {
  ...
}
```

- 課題
    - terraformにバージョンがあるように、各プロバイダーにもバージョンがある。

- terraformのバージョン固定

|項目|説明|
|---|---|
|required_version|Terraformのバージョン指定|

- terraformのバージョン固定

|項目|説明|
|---|---|
|required_providers|providerのバージョン指定|

- a


# providerブロック
- プロバイダーの設定
```terraform
provider <PROVIDER_TYPE> {
  ...
}
```

- クレデンシャル情報

|項目|説明|
|---|---|
|profile|AWSへアクセスするためのプロファイル|

- デフォルトリージョン

|項目|説明|
|---|---|
|region|デフォルトリージョン|

# dataブロック
- 管理対象外のリソースを取り込める
```terraform
data <DATA_TYPE> <DATA_NAME>{
  ...
}
```
- 取り込みたいリソースによって記載方法が異なる


# outputブロック
- 作成したリソースを外部参照できるようにする
```terraform
output <OUTPUT_NAME>{
  ...
}
```

- EC2インスタンスのIDを出力する
ec2_instance_id は外から参照時に指定する名前
出力する値は resource ブロックの内容を指定する
```terraform
resource "aws_instance" "hello-world" {
  ami           = "ami-123456789"
  instance_type = "t2.micro"
}

output "ec2_instance_id" {
  value = aws_instance.hello-world.id
}
```


# outputブロック
- サブネットがVPCを参照する場合
```terraform
resource "aws_vpc" "vpc" {
  cidr_block           = "192.168.0.0/20"
  instance_tenancy     = "default"
  enable_dns_support   = true
  enable_dns_hostnames = true
}

resource "aws_subnet" "public_subnet_1a" {
  vpc_id                  = aws_vpc.vpc.id
  availability_zone       = "ap-nortneast-1a"
  cidr_block              = "192.168.1.0/24"
  map_public_ip_on_launch = true
}
```
- HCL2でリソース参照する記述
"."(ドット)で連結して参照
`<BLOCK_TYPE>.<LABEL_1>.<LABEL_2>`
※resourceブロックの場合、省略される


# 組み込み関数
- 組み込み関数

|種類|説明|
|---|---|
|numeric|数値演算。絶対値、切り上げ、切り捨て、最大、最小など|
|string|文字列操作。フォーマット、結合、抜き出しなど|
|collection|配列操作。結合、分割、ソートなど|
|encoding|エンコード。Base64、CSV、JSON、YAMLなどの変換|
|filesystem|ファイル操作。ディレクトリ名取得、ファイル読み取りなど|
|data&time|日付操作。現在時刻取得、データのフォーマット指定など|
|Hash&Crypt|ハッシュおよび暗号化。Bcrypt、MD5、SHA-256など|
|IP Network|CIDR表記の演算。ホスト名取得、サブネット名取得など|
|Type Conversion|型変換。bool, string, number などへの変換|

- 組み込み関数の試し方
```sh
terraform console
  [-var <KEY>=<VALUE>]
  [-var-file <VAR_FILE>]
```
引数
  `-var <KEY>=<VALUE>` 変数の指定
  `-var-file <FILE>`   変数ファイルの指定

# ファイル分割
- サブディレクトリの.tfファイルは読み込まない
- カレントディレクトリの.tfファイルのみ
- 最小分割構成
```
root
 ├── terraform.tfvars 変数を定義
 └── main.tf          各種リソースを定義
 　　　　　　　　mainの中身が大きくなると分割していく
```

# 公式ドキュメントの見方
- おさえておきたいドキュメント

|種類|説明|
|---|---|
|HCL2|HCL2の仕様に関わるドキュメント|
|CLI|Terraformのコマンドに関わるドキュメント|
|provider|providerに関するドキュメント|