メインコンテンツへスキップ

Terraformチートシート:コマンド・構文・関数クイックリファレンス

·
インフラ Terraform AWS メモ
目次

今日学んだこと
#

Terraformを使う上で頻繁に参照するコマンド、ブロック構文、関数、パターンを1つの記事にまとめました。作業中に「あれ、どう書くんだっけ?」となったときにすぐ参照できるチートシートです。

学習内容
#

基本コマンド
#

初期化・実行コマンド
コマンド説明よく使うオプション
terraform init初期化(Provider取得)-upgrade(Provider更新)
terraform plan差分確認(ドライラン)-out=plan.tfplan(計画を保存)
terraform apply変更を適用-auto-approve(確認スキップ)
terraform destroy全リソース削除-target=xxx(特定リソースのみ)
確認・検証コマンド
コマンド説明
terraform validate構文チェック
terraform fmtコード整形(インデント等)
terraform fmt -check整形が必要か確認のみ
terraform show現在のStateを表示
terraform outputOutput値を表示
State操作コマンド
コマンド説明
terraform state list管理中リソース一覧
terraform state show <リソース>特定リソースの詳細
terraform state rm <リソース>Stateから削除(実リソースは残る)
terraform state mv <旧> <新>リソース名変更
terraform force-unlock <LOCK_ID>ロック強制解除
その他のコマンド
コマンド説明
terraform graph依存関係をDOT形式で出力
terraform console対話モード(式の評価テスト)
terraform import <リソース> <ID>既存リソースをStateに取り込み
terraform apply -replace=<リソース>指定リソースを再作成

Note: terraform taintは非推奨。-replaceオプションを使用する。


ブロック構文
#

terraform ブロック(設定)```hcl terraform { required_version = ">= 1.0.0"

required_providers { aws = { source = “hashicorp/aws” version = “~> 5.0” } }

backend “s3” { bucket = “my-tfstate-bucket” key = “terraform.tfstate” region = “ap-northeast-1” dynamodb_table = “my-tfstate-lock” encrypt = true } }


</details>

<details>
<summary>provider ブロック</summary>
```hcl
provider "aws" {
  region = "ap-northeast-1"

  default_tags {
    tags = {
      Project   = "my-project"
      ManagedBy = "terraform"
    }
  }
}

# 複数リージョン対応(alias)
provider "aws" {
  alias  = "us_east_1"
  region = "us-east-1"
}
resource ブロック```hcl resource "aws_instance" "web" { ami = "ami-12345678" instance_type = "t3.micro" subnet_id = aws_subnet.public.id

tags = { Name = “web-server” }

depends_on = [aws_internet_gateway.main]

lifecycle { create_before_destroy = true prevent_destroy = false ignore_changes = [tags] } }


</details>

<details>
<summary>data ブロック(既存リソース参照)</summary>
```hcl
data "aws_ami" "amazon_linux" {
  most_recent = true
  owners      = ["amazon"]

  filter {
    name   = "name"
    values = ["al2023-ami-*-x86_64"]
  }
}

resource "aws_instance" "web" {
  ami = data.aws_ami.amazon_linux.id
}
variable ブロック(入力変数)```hcl variable "instance_type" { type = string default = "t3.micro" description = "EC2 instance type" }

variable “environment” { type = string validation { condition = contains([“dev”, “stg”, “prod”], var.environment) error_message = “environment must be dev, stg, or prod” } }

variable “password” { type = string sensitive = true }


</details>

<details>
<summary>output / locals ブロック</summary>
```hcl
output "instance_id" {
  value       = aws_instance.web.id
  description = "EC2 instance ID"
}

output "db_password" {
  value     = aws_db_instance.main.password
  sensitive = true
}

locals {
  common_tags = {
    Project     = var.project_name
    Environment = var.environment
    ManagedBy   = "terraform"
  }
  name_prefix = "${var.project_name}-${var.environment}"
}
module ブロック```hcl module "vpc" { source = "./modules/vpc"

vpc_cidr = “10.0.0.0/16” environment = var.environment }

module “s3” { source = “terraform-aws-modules/s3-bucket/aws” version = “3.0.0”

bucket = “my-bucket” }

マルチリージョンプロバイダーを渡す
#

module “acm” { source = “./modules/acm”

providers = { aws = aws.us_east_1 } }


</details>

<details>
<summary>moved ブロック(リファクタリング)</summary>
```hcl
moved {
  from = aws_s3_bucket.content
  to   = module.s3_content.aws_s3_bucket.this
}

moved {
  from = aws_instance.web
  to   = aws_instance.web_server
}

よく使う型
#

string"hello"
number123
booltrue, false
list(string)["a", "b", "c"]
set(string)toset(["a", "b"])
map(string){ key1 = "value1", key2 = "value2" }
object({...}){ name = string, port = number }
any任意の型

よく使う関数
#

文字列関数
関数説明
format()書式化format("Hello, %s!", var.name)
join()結合join(", ", ["a", "b", "c"])"a, b, c"
split()分割split(",", "a,b,c")["a", "b", "c"]
lower()小文字化lower("HELLO")"hello"
upper()大文字化upper("hello")"HELLO"
replace()置換replace("hello", "l", "L")
trimspace()空白除去trimspace(" hello ")"hello"
コレクション関数
関数説明
length()要素数length(["a", "b"])2
element()インデックス参照element(["a", "b"], 0)"a"
concat()リスト結合concat(["a"], ["b"])["a", "b"]
flatten()ネスト解除flatten([["a"], ["b"]])["a", "b"]
merge()マップ結合merge({a=1}, {b=2}){a=1, b=2}
lookup()マップ検索lookup({a=1}, "a", 0)1
keys()キー一覧keys({a=1, b=2})["a", "b"]
values()値一覧values({a=1, b=2})[1, 2]
contains()要素存在確認contains(["a", "b"], "a")true
distinct()重複除去distinct(["a", "a", "b"])["a", "b"]
ファイル関数
関数説明
file()ファイル読み込みfile("./scripts/init.sh")
pathexpand()~をホームパスに展開pathexpand("~/.ssh/id_rsa.pub")
filebase64()Base64で読み込みfilebase64("image.png")
templatefile()テンプレート適用templatefile("user_data.sh", {name = "web"})
条件・型変換関数
関数説明
coalesce()最初の非null値coalesce(null, "default")"default"
try()エラー時のフォールバックtry(var.optional, "default")
tostring()文字列変換tostring(123)"123"
tonumber()数値変換tonumber("123")123
tobool()真偽値変換tobool("true")true
tolist()リスト変換tolist(toset(["a", "b"]))
toset()セット変換toset(["a", "a", "b"])

条件分岐・ループ
#

三項演算子・count```hcl # 三項演算子 instance_type = var.environment == "prod" ? "t3.large" : "t3.micro"

count(インデックスベース)
#

resource “aws_instance” “web” { count = 3 tags = { Name = “web-${count.index}” } }

条件付き作成
#

resource “aws_eip” “nat” { count = var.create_nat ? 1 : 0 }


</details>

<details>
<summary>for_each</summary>
```hcl
# マップ
resource "aws_subnet" "private" {
  for_each = {
    "a" = "10.0.1.0/24"
    "c" = "10.0.2.0/24"
  }

  availability_zone = "ap-northeast-1${each.key}"
  cidr_block        = each.value
}

# セット
resource "aws_security_group_rule" "ports" {
  for_each = toset(["80", "443", "22"])

  from_port = tonumber(each.value)
  to_port   = tonumber(each.value)
}
for式・dynamic ブロック```hcl # for式 locals { upper_names = [for name in var.names : upper(name)] instance_ids = {for inst in aws_instance.web : inst.tags.Name => inst.id} prod_instances = [for inst in var.instances : inst if inst.env == "prod"] }

dynamic ブロック
#

resource “aws_security_group” “main” { name = “main”

dynamic “ingress” { for_each = var.ingress_rules content { from_port = ingress.value.from_port to_port = ingress.value.to_port protocol = ingress.value.protocol cidr_blocks = ingress.value.cidr_blocks } } }


</details>

---

### ディレクトリ構成例

<details>
<summary>シンプル構成</summary>

project/ ├── main.tf ├── variables.tf ├── outputs.tf ├── versions.tf └── terraform.tfvars


</details>

<details>
<summary>モジュール構成</summary>

project/ ├── modules/ │ ├── vpc/ │ │ ├── main.tf │ │ ├── variables.tf │ │ └── outputs.tf │ └── ec2/ ├── environments/ │ ├── dev/ │ │ ├── main.tf │ │ ├── backend.tf │ │ └── terraform.tfvars │ └── prod/ └── backend-setup/ └── main.tf


</details>

---

### よく使うパターン

<details>
<summary>タグの共通化</summary>
```hcl
locals {
  common_tags = {
    Project     = "my-project"
    Environment = var.environment
    ManagedBy   = "terraform"
  }
}

resource "aws_instance" "web" {
  tags = merge(local.common_tags, {
    Name = "web-server"
    Role = "web"
  })
}
条件付きリソース作成```hcl resource "aws_nat_gateway" "main" { count = var.enable_nat_gateway ? 1 : 0

allocation_id = aws_eip.nat[0].id subnet_id = aws_subnet.public.id }

output “nat_gateway_id” { value = var.enable_nat_gateway ? aws_nat_gateway.main[0].id : null }


</details>

<details>
<summary>user_data / セキュリティグループ参照</summary>
```hcl
# user_data
resource "aws_instance" "web" {
  user_data = <<-EOF
              #!/bin/bash
              dnf update -y
              dnf install -y httpd
              systemctl start httpd
              EOF
}

# SGをソースに指定
resource "aws_vpc_security_group_ingress_rule" "rds" {
  security_group_id            = aws_security_group.rds.id
  referenced_security_group_id = aws_security_group.web.id
  from_port                    = 3306
  to_port                      = 3306
  ip_protocol                  = "tcp"
}

注意点・ベストプラクティス
#

やるべきこと
#

  • terraform fmt でコード整形
  • terraform validate で構文チェック
  • .terraform.lock.hcl をGit管理(Providerバージョン固定)
  • terraform.tfvars はGit管理外(機密情報含む場合)
  • sensitive = true でパスワード等をマスク
  • リモートバックエンド(S3 + DynamoDB)で状態管理

避けるべきこと
#

  • 本番環境で -auto-approve を使わない
  • ハードコードされたAMI ID(data sourceで取得)
  • ハードコードされたパスワード(variables or Secrets Manager)
  • terraform state rm の安易な使用
  • force-unlock は他の操作がないことを確認してから

まとめ
#

用途参照セクション
コマンドを調べたい基本コマンド
書き方を確認したいブロック構文
関数の使い方を調べたいよく使う関数
ループの書き方を確認したい条件分岐・ループ
実装パターンを参考にしたいよく使うパターン
  • terraform initplanapply が基本フロー
  • countはインデックス、for_eachはキーでリソースを識別
  • localsで共通値を定義、merge()でタグを結合

参考
#