【随時更新】実務でTerraformを使う人は"最低限"抑えておきたい構文をサクッとまとめてみた

# 実務で急に使うことになった人向けの確認リスト

Terraformは、HashiCorpが開発した「Infrastructure as Code」ツールで、クラウドやオンプレミスのインフラをコードで定義・管理します。案件や転職などで同ツールを急に覚えなければならない人向けに、基本構文や要点をサクッと確認できるリストを作成しました。

:::note info
ご案内
本記事は個人的な備忘用の意味合いもあるため細かい説明は割愛しています。詳細は公式ドキュメントをご覧頂けますと幸いですす。
:::

# 基本構文

リソース定義や属性指定はキー・バリュー形式で、繰り返しや条件分岐もサポートしています。CloudFormationよりも表現力は豊かですが、複雑でもないため、エンジニアであれば比較的学習コストは比較的低いです。ここでは、基本構文をあげます。

## Providers
Terraformのproviderブロックでは、特定のクラウドプロバイダやサービスとの連携に必要な設定を行います。リージョン、AWSプロファイルなどの設定も行えます。

```terraform
provider "aws" {
  region  = "ap-northeast-1"
  version = "~> 3.0"
}
```

## Resources
Terraformのリソースブロックは、インフラの構成要素（例：EC2インスタンスやS3バケット）を定義するための主要な構文です。それぞれのリソースブロックは特定のタイプのリソースを表し、必要な属性や設定が含まれています。

```terraform
resource "aws_vpc" "this" {
  cidr_block = var.cidr_block
  tags = {
    Name = var.vpc_name
  }
}
```

## Variables
TerraformのVariablesはインフラ構成のカスタマイズを可能にするパラメータ。variable宣言で定義し、var.変数名で参照する。

```terraform
variable "instance_type" {
  description = "EC2 instance type"
  default     = "t2.micro"
}
```

## Outputs

TerraformのOutputsは、Terraform設定の実行結果として得られるデータを表示するための方法です。outputブロックで定義され、terraform applyの後に表示されます。これにより、リソースの属性や計算結果などを簡単に確認できます。ユーザーは、これらの出力を他のシステムやワークフローと統合する際にも利用できます。

```terraform
output "instance_public_ip" {
  value = aws_instance.example.public_ip
}
```

## Data Sources

TerraformのData Sourcesは、既存のインフラリソースのデータを参照・読み取るための方法です。`data`ブロックで定義し、他のリソースの情報や設定を取得します。これを使用して、外部のリソースや管理外のリソースの情報をTerraform設定内で利用することが可能となります。

```terraform
data "aws_s3_bucket" "existing_bucket" {
  bucket = "my-existing-s3-bucket" # 参照したいS3バケットの名前を指定
}
output "bucket_arn" {
  value = data.aws_s3_bucket.existing_bucket.arn
}
```

## Module

TerraformのModuleは、再利用可能なTerraformコードの単位です。moduleブロックを使って呼び出し、変数で設定をカスタマイズします。モジュールは独自の入力変数、出力、リソースを持つことができ、コードの再利用と組織を向上させるための強力なツールです。

```terminal:ディレクトリ階層
.
├── main.tf
└── modules
    └── network
        ├── main.tf
        ├── outputs.tf
        └── variables.tf
```

```terraform:modules/network/main.tf
# モジュール定義
resource "aws_vpc" "my_vpc" {
  cidr_block = var.cidr_block
  tags = {
    Name = "MyVPC"
  }
}

resource "aws_subnet" "my_subnet" {
  vpc_id     = aws_vpc.my_vpc.id
  cidr_block = var.subnet_cidr_block
  tags = {
    Name = "MySubnet"
  }
}
```

```terraform:modules/network/variables.tf
# モジュールで用いる変数(引数)
variable "cidr_block" {
  description = "CIDR for VPC"
  type        = string
}

variable "subnet_cidr_block" {
  description = "CIDR for Subnet"
  type        = string
}
```

```terraform:modules/network/outputs.tf
# モジュールの出力を定義
output "vpc_id" {
  value = aws_vpc.my_vpc.id
}

output "subnet_id" {
  value = aws_subnet.my_subnet.id
}
```

```terraform:main.tf
# モジュールを呼び出す
module "network_module" {
  source            = "./modules/network"
  cidr_block        = "10.0.0.0/16"
  subnet_cidr_block = "10.0.1.0/24"
}

output "created_vpc_id" {
  value = module.network_module.vpc_id
}

output "created_subnet_id" {
  value = module.network_module.subnet_id
}
```

## Functions

Terraformには便利な組み込み関数や制御構造があります。これにはConditional Expressionsやjoin関数、リソースの繰り返しを制御するfor_eachなどが含まれます。これらの機能は、コードの柔軟性と再利用性を向上させるために設計されています。

```terraform:
# for_eachを使用して複数のサブネットを作成
resource "aws_subnet" "main" {
  for_each = {
    "a" = "10.0.1.0/24",
    "b" = "10.0.2.0/24"
  }

  vpc_id     = aws_vpc.main.id
  cidr_block = each.value
  tags = {
    Name = "Subnet-${each.key}"
  }
}
```

```terraform:
# 文字列操作
output "joined_string" {
  value = join("-", ["Hello", "Terraform"])
}
// 出力: "Hello-Terraform"
```

```terraform:
# 条件関数
output "conditioned_value" {
  value = conditional(true, "Hello", "Terraform")
}
// 出力: "Hello"
```

```terraform:
# リスト操作
output "example_list" {
  value = list("Hello", "Terraform")
}
// 出力: ["Hello", "Terraform"]

# 要素取得
output "second_element" {
  value = element(["Hello", "Terraform"], 1)
}
// 出力: ["Hello", "Terraform"]
```

```terraform:
# 日付生成
output "current_timestamp" {
  value = timestamp()
}
// 出力は現在の日時のISO 8601形式の文字列
```

# ローカル環境構築方法

Terraformのローカル環境構築には、主に2つの方法があります。一つは、Dockerコンテナ内でTerraformを実行する方法。これは環境の隔離やバージョン管理が容易で、初期セットアップも迅速に行えます。もう一つの方法は、直接ローカルマシンにTerraformをインストールするものです。これはシンプルで直感的なアプローチで、Dockerを介さずにTerraformを使用したい場合に適しています。

## ローカルマシンにインストール

```shell:Terminal
# tfenvのインストール
brew install tfenv

# 利用可能なTerraformのバージョン一覧を表示
tfenv list-remote

# 特定のバージョンをインストール
tfenv install <desired_version>

# インストールリスト一覧
tfenv list

# 利用するバージョン指定
tfenv use <desired_version>

# 現在のバージョンを確認
terraform version
```

## Dockerを利用

```shell:Terminal
# 公式イメージを利用
docker run \                                                                             
  -v ~/.aws:/root/.aws \
  -v $(pwd):/terraform \
  -w /terraform \
  -it \
  --entrypoint=ash \
  hashicorp/terraform:1.5
```

# S3を活用したリモートバックエンドでのtfstateバージョン管理

S3を活用したリモートバックエンドでTerraformのtfstateを保存・管理します。複数開発者間の共有やバージョン管理に適しています。さらに、DynamoDBなどを使用してロック機構を提供し、複数人が同時にtfstateを変更することを防ぐ安全対策も整っています。これにより、安全かつ効果的なインフラ管理が可能となります。

```shell:Terminal
# Terraformのstateファイルを保存するためのS3バケットを作成
aws s3api create-bucket --bucket your-tfstate-bucket-name --region ap-northeast-1 --create-bucket-configuration LocationConstraint=ap-northeast-1

# バケットバージョニングの有効化
aws s3api put-bucket-versioning --bucket your-tfstate-bucket-name --versioning-configuration Status=Enabled

# 同時実行を防ぐためのロックを提供するDynamoDBテーブルを作成
aws dynamodb create-table --table-name your-tfstate-lock-table --attribute-definitions AttributeName=LockID,AttributeType=S --key-schema AttributeName=LockID,KeyType=HASH --provisioned-throughput ReadCapacityUnits=5,WriteCapacityUnits=5 --region ap-northeast-1

# main.tf または backend.tf などの設定ファイルに以下を追加
terraform {
  backend "s3" {
    bucket         = "your-tfstate-bucket-name"
    key            = "path/to/your/key"
    region         = "ap-northeast-1"
    dynamodb_table = "your-tfstate-lock-table"
    encrypt        = true
  }
}
```

# Terraformコマンド


Terraformコマンドは、インフラストラクチャのライフサイクルを効率的に管理します。初期化からリソースのプレビュー、適用、そして破棄までの手順をシンプルなコマンドで制御できるため、手作業のエラーや冗長性を大幅に削減します。加えて、一貫性のある状態管理や変更の監査も可能とし、信頼性の高いインフラ運用をサポートします。


```shell:Terminal
# 新しいTerraformプロジェクトを初期化するためのコマンド。
terraform init

# 変更の確認や、どのリソースが作成/変更/削除されるかをプレビューする。
terraform plan

# 実際に変更を適用するコマンド
terraform apply

# 設定したリソースを全て削除する。
terraform destroy

# 現在の`tfstate`を管理・調整するためのコマンド
terraform state
```