- 技術 💻
Terraform入門|基本の流れからstate管理・既存リソースの取り込みまで
Terraformとは、サーバーやネットワーク、ストレージなどのインフラを、コード(設定ファイル)で定義して作成・変更・削除できるツールです。こうした考え方を IaC(Infrastructure as Code) と呼びます。管理画面での手作業の代わりにコードで管理することで、同じ環境を何度でも作れる・変更の履歴が残る・レビューできるようになります。
入門記事の多くは plan と apply までで終わりますが、実務で本当に大切なのは、state(状態ファイル)の管理と、すでにある環境をどうTerraformに取り込むかです。この記事では、AWSのS3バケットを例に基本の流れを解説したうえで、チームで使うための運用まで紹介します。
Terraformの早見表
| やりたいこと | コマンド・書き方 |
|---|---|
| 初期化(プロバイダーのダウンロード) | terraform init |
| コードの整形 | terraform fmt |
| 文法のチェック | terraform validate |
| 変更内容の確認(実際には変更しない) | terraform plan |
| 変更の適用 | terraform apply |
| 管理しているリソースの一覧 | terraform state list |
| すべて削除 | terraform destroy |
| 既存リソースの取り込み | import ブロック + terraform plan -generate-config-out=generated.tf |
| リソース名の変更 | moved ブロック |
| stateのロック(S3) | backend "s3" に use_lockfile = true |
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「Terraform入門|基本の流れからstate管理・既存リソースの取り込みまで」
Terraformの仕組み
Terraformは、次の3つを見比べて、何を作り、何を変え、何を消すかを計算します。
| もの | 内容 |
|---|---|
コード(.tf ファイル) |
あるべき姿 |
state(terraform.tfstate) |
Terraformが前回作ったもの・管理しているものの記録 |
| 実際のクラウドの状態 | いま本当にあるもの |
この「あるべき姿」との差分を plan で確認し、apply で反映する、というのが基本の流れです。手順(何をするか)ではなく、完成形(どうあるべきか)を書くのが、シェルスクリプトとの大きな違いです。
最初のコード:S3バケットを作る
my-infra/
├── versions.tf # Terraformとプロバイダーのバージョン
├── main.tf # リソースの定義
├── variables.tf # 変数
└── outputs.tf # 出力
# versions.tf
terraform {
required_version = ">= 1.10"
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 6.0"
}
}
}
provider "aws" {
region = var.region
}
# variables.tf
variable "region" {
type = string
default = "ap-northeast-1"
}
variable "env" {
type = string
description = "環境名(dev / stg / prod)"
}
# main.tf
resource "aws_s3_bucket" "reports" {
bucket = "example-reports-${var.env}"
tags = {
Env = var.env
ManagedBy = "terraform"
}
}
resource "aws_s3_bucket_versioning" "reports" {
bucket = aws_s3_bucket.reports.id
versioning_configuration {
status = "Enabled"
}
}
# outputs.tf
output "reports_bucket_name" {
value = aws_s3_bucket.reports.bucket
}
aws_s3_bucket.reports.id のように、ほかのリソースの値を参照すると、Terraformが作る順番を自動で判断します。バケットができてから、バージョニングの設定が行われます。
基本の流れ
terraform init # プロバイダーをダウンロード
terraform fmt # 書き方を整える
terraform validate # 文法をチェック
terraform plan -var="env=dev" # 何が変わるかを確認
terraform apply -var="env=dev" # 反映(確認のあと yes を入力)
plan の結果は、記号で表示されます。
| 記号 | 意味 |
|---|---|
+ |
作成 |
~ |
変更(その場で更新) |
- |
削除 |
-/+ |
削除してから作り直し(データが消える可能性がある) |
特に -/+(作り直し)には注意が必要です。名前など、変更できない項目を変えると、既存のリソースを消して作り直す計画になります。DBやストレージで出たら、apply の前に立ち止まって確認します。
変数は、-var のほかに terraform.tfvars ファイルでも渡せます。
# dev.tfvars
env = "dev"
terraform plan -var-file="dev.tfvars"
stateの管理:チームで使うための一番大切なポイント
terraform apply をすると、作ったリソースの情報が state(terraform.tfstate) に記録されます。
stateはローカルに置いたままにしないのが基本です。
| 問題 | 起きること |
|---|---|
| 各自のPCにstateがある | 別の人が同じリソースを「知らない」まま作ろうとする |
| 2人が同時に apply する | stateが壊れる |
| PCが壊れる・消える | Terraformが管理しているものがわからなくなる |
| stateをGitにコミットする | stateにはパスワードなどの値が平文で入ることがあり、漏えいの原因になる |
S3にstateを置き、ロックする
terraform {
backend "s3" {
bucket = "example-terraform-state"
key = "my-infra/dev/terraform.tfstate"
region = "ap-northeast-1"
encrypt = true
use_lockfile = true
}
}
use_lockfile = trueで、S3上のロックファイルを使って同時実行を防ぎます(Terraform 1.10以降)- 以前はロックにDynamoDBのテーブル(
dynamodb_table)を使っていましたが、公式ドキュメントでは非推奨とされ、S3のロックへの移行が勧められています - stateのバケットではバージョニングを有効にしておくと、誤った変更から復元できます(公式ドキュメントでも推奨)
.gitignoreに入れるもの・入れないもの
# .gitignore
.terraform/
*.tfstate
*.tfstate.*
*.tfvars # 秘密の値を含む場合
.terraform.lock.hcl はコミットします。プロバイダーのバージョンを固定するファイルで、チームのメンバー全員が同じバージョンを使えるようになります。
既存のリソースを取り込む:importブロック
管理画面で手作業で作ったリソースも、Terraformの管理下に取り込めます。
# import.tf
import {
to = aws_s3_bucket.legacy_logs
id = "example-legacy-logs"
}
terraform plan -generate-config-out=generated.tf
-generate-config-out を付けると、取り込むリソースの設定を、Terraformのコードとして自動生成してくれます。生成された generated.tf を見直して整え、plan で差分がないことを確認してから apply すると、取り込みが完了します。
| 方法 | 特徴 |
|---|---|
import ブロック(Terraform 1.5以降) |
コードとして残り、planで確認してからレビュー・適用できる |
terraform import コマンド |
その場でstateに取り込む。記録が残りにくい |
チームで作業するなら import ブロックがおすすめです。取り込みもプルリクエストでレビューできます。
名前を変えるときは:movedブロック
リソースの名前(aws_s3_bucket.reports の reports の部分)をそのまま変えると、Terraformは「古いものを削除して、新しいものを作る」と解釈します。
moved {
from = aws_s3_bucket.reports
to = aws_s3_bucket.monthly_reports
}
moved ブロックを書くと、実際のリソースはそのままで、Terraform上の名前だけを変更できます。リファクタリングのときに欠かせない書き方です。
モジュール:同じ構成を使い回す
同じ構成を複数の環境で使うときは、モジュールにまとめます。
my-infra/
├── modules/
│ └── report_bucket/
│ ├── main.tf
│ ├── variables.tf
│ └── outputs.tf
└── envs/
├── dev/
│ └── main.tf
└── prod/
└── main.tf
# envs/dev/main.tf
module "reports" {
source = "../../modules/report_bucket"
env = "dev"
}
環境ごとにディレクトリを分け、それぞれに別のstateを持たせると、開発環境の作業が本番環境に影響しにくくなります。
チームでの運用:プルリクエストでplanを確認する
| 手順 | 内容 |
|---|---|
| 1. ブランチで変更 | .tf ファイルを編集する |
| 2. プルリクエストを作る | CIで fmt -check・validate・plan を自動で実行する |
| 3. planの結果をレビュー | 特に「削除」「作り直し」がないかを確認する |
| 4. マージ後にapply | mainにマージされたものだけを、CIや決められた担当者が適用する |
「コードのレビュー」だけでなく、「planの結果のレビュー」を必須にするのがポイントです。同じコードでも、実際の環境によって計画が変わることがあるためです。
つまずきやすいポイント
| つまずき | 対処 |
|---|---|
| 管理画面で手動で変更してしまった | 次の plan で差分として表示される。コードに反映するか、コードどおりに戻すかを決める |
-/+(作り直し)が出た |
変更できない項目を変えていないか確認。名前の変更なら moved を使う |
| stateのロックが外れない | 実行中の処理がないことを確認してから terraform force-unlock |
| 秘密の値をコードに書いてしまった | 変数(sensitive = true)や、シークレット管理サービスから読み込む形にする |
| 削除を防ぎたいリソースがある | lifecycle { prevent_destroy = true } を付ける |
よくある質問
Q. CloudFormationやAWS CDKとの違いは何ですか? A. CloudFormationとCDKはAWS専用ですが、TerraformはAWS・Google Cloud・Azureなど複数のクラウドや、GitHub・Datadogなどのサービスも同じ書き方で管理できます。AWSだけを使い、AWSの新機能にすぐ対応したい場合はCloudFormationやCDKも有力な選択肢です。
Q. OpenTofuとは何ですか? A. Terraformのライセンス変更をきっかけに生まれた、オープンソースのフォークです。基本的な書き方はTerraformと共通です。
Q. AIにTerraformのコードを書かせてもいいですか? A. 下書きを作るのには向いています。ただし、planの結果は必ず人が確認します。特に削除や作り直しの計画は、AIの説明ではなく、実際のplanの出力で判断することが大切です。
まとめ
- Terraformは、インフラをコードで定義し、planで確認してapplyで反映するIaCのツール
planの-/+(作り直し) に注意する- stateはS3などのリモートに置き、
use_lockfile = trueでロックする。stateはGitにコミットしない .terraform.lock.hclはコミットしてバージョンを揃える- 既存のリソースは importブロック +
-generate-config-outで取り込む - 名前の変更は movedブロック、使い回しはモジュール
- チームでは planの結果をプルリクエストでレビューしてから適用する
本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。
(記載例)出典:株式会社RJC「Terraform入門|基本の流れからstate管理・既存リソースの取り込みまで」
株式会社RJCでは、クラウドやインフラの技術も、プロジェクトやグループ活動の中で仲間と学び合っています。こうした知識を共有しながら、日々技術を磨いています。
株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。
WE ARE HIRING
RJCで一緒に開発しながら、
成長を楽しみませんか?
RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!
- 127日年間休日
- 12時間平均残業時間
- 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!
ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。