クラウドインフラの構成管理をするデファクトスタンダードとしての地位を確立しているTerraform。
この記事は、以下についてまとめたものである。
- Terraformの概要
- 動作イメージ
- 利用フロー
- Terraformの利用
- ローカル環境の構築方法
- Terraformのディレクトリ・ファイル構成
- .tfファイルの記述方法
- 主要なterraformコマンド
- 今後参照することが多いと思われる公式ドキュメント
(TODOになっているところも今後更新していく予定です)
1. Terraformの概要
-
Terraform
は、HashiCorp社(Vagrant, Vault)によってGo言語で開発されたOSSで、Infratructure as Codeを実現するツール。 -
AWS,GCP,Azureの他、DatadogやHerokuなど様々なクラウドインフラの構成管理ができる。
- 類似ツールに
CloudFormation
があるが、こちらはAWSのインフラリソースのみが対象 - ちなみに、クラウドインフラ以外にローカルのDocker環境の構成管理もできる
- 類似ツールに
-
インフラ構成の定義は、.tfという拡張子のファイルに、各インフラのリソースの定義をコードで記述することによって行う。
- 具体的には、各インフラの初期化、更新、削除といった内容を記述する。
- .tfファイルに記述されたコードに基づいてTerraformが自動でインフラを構築してくれる。
- 利用者は、インフラリソースの構築・設定順を気にする必要はあまりなく、インフラリソース間の依存関係は基本的にTerraform側でいい感じに考慮して制御してくれる。
- 冪等性の担保もしてくれて、コードとして記述している内容が対象のインフラリソースですでに実現されている場合、その構築処理をスキップしてくれる。
- Terraformの主な構成要素は、
TERRAFORM CORE
とTERRAFORM PROVIDER
である。
1.1. 動作イメージ
[.tfファイル]
↓
↓
↓
---------------- Terraform ------------------
[TERRAFORM CORE]
↓
↓(gRPC)
↓
[TERRAFORM PROVIDER]
↓
↓(Golang)
↓
[各社クラウドインフラが提供するSDK(API)]
---------------------------------------------
↓
↓(HTTP(s))
↓
[各社クラウドインフラのリソース]
TERRAFORM PROVIDER
- HassiCorp社とTerraformコミュニティによってGolangで開発されているプラグインである。以下単にプロバイダと呼ぶ。
- Terraform Registyで公開されている
- .tfファイルの設定に基づき、各社クラウドから提供されているAPI, SDKを利用していい感じに各社クラウドインフラリソースを操作してくれるものである。
- TERRAFORM PROVIDERは、ローカルでgRPCサーバとして動作する。
1.2. 利用フロー
Terraformを利用して、インフラリソースの構築・設定反映をする工程は、以下の通り。
- ①インフラリソースの設定ファイル(.tf)を記述
-
②設定ファイルの検証
-
terraform validate
コマンドを実行する
-
-
③作業用ディレクトリの初期化
-
terraform init
コマンドを実行する
→設定ファイルのインフラリソース定義の反映に必要な分のプロバイダがDLされる
-
-
④インフラリソースへ設定を適用するための具体的な操作を確認
-
terraform plan
コマンドを実行する
→「クラウドリソースに対して、Terraformがこれからどんな操作をするのか?」の内容が表示されるので、問題ないかを確認する
-
-
⑤インフラリソースへ設定を適用
-
teffaform apply
コマンドを実行する
-
2. Terraformの利用
2.1. ローカル環境構築
公式ドキュメントを参考に、以下をインストール。
- Terraform(※)
- terraformコマンド補完機能
※terraformのバージョンを管理しながら使いたいならば、tfenv経由でインストールして利用する。
# tfenvをインストール
brew install tfenv
# バージョン指定してterraformをインストールし、tfenv管理下におく
tfenv install <バージョン>
# 使用するterraformのバージョンを指定する
tfenv use <バージョン>
2.2. Terraformのディレクトリ・ファイル構成
設定ファイル(.tf
or .tf.json
)群を同じディレクトリにまとめたものを、モジュールという。
- モジュールは、基本的にディレクトリ直下の設定ファイル群のみで構成される。
- サブディレクトリは完全に別のモジュールとして扱われる
- モジュール呼び出しという仕組みを使わない限り、自動的に読み込まれたりすることはない。
- Terraformはモジュールのディレクトリ直下の設定ファイル内の記述すべてを評価し、それが1つの設定ファイルであるかのように動作する。
- ブロックを別ファイルにわけるのは、純粋に読む人・メンテナンスする人にとってわかりやすくするためだけで、動作には全く影響しない。
- Terraformは単一のルートモジュールを起点として動作する。
- Terraform CLIでは、Terraformを起動する作業用ディレクトリ = ルートモジュール。
- コマンドライン引数で、別ディレクトリをルートモジュールにすることもできるが、実際にはほぼやらないらしい。
- Terraform CLIでは、Terraformを起動する作業用ディレクトリ = ルートモジュール。
2.3. .tfファイルの記述方法
- 文字コード: UTF-8
- 改行コード: 慣習的にLF(CRLFでも可)
- コメント:
#
で一行コメントを記述
基本的な構造、構文と用語
# --- ブロック ----
<ブロックタイプ> "<ラベル>" "<ラベル>" {
# --- ボディ ---
...
# 引数
<引数名> = <値> or <式>
# --- ボディここまで ---
}
# --- ブロックここまで ---
- ブロック: 設定内容のコンテナであり、ブロックタイプ, 任意の数のラベル, ボディ(
{}
で囲まれる部分。引数、他のブロックを含む)から構成される。 - 引数: 引数名に「値」もしくは「式」を紐付ける形で記述する。
- 式: 他の値を参照したり、組み合わせたりするもの。
例えば、以下のような形になる。
resource "aws_vpc" "main" {
cidr_block = var.base_cidr_block
}
2.3.1. ブロックタイプ
terraform
ブロック
Terraform自体の基本的な設定をするブロック。
モジュールに必要なプロバイダ(required_providers
ブロック)や、tfstateの置き場(backend
ブロック)をボディに記述する。
例.
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 1.0.4"
}
}
backend "gcs" {
bucket = "tf-state-prod"
prefix = "terraform/state"
}
}
required_providers
ブロック
モジュールで利用する全てのプロバイダを列挙するブロック。
required_providers {
<プロバイダのローカル名> = {
source = "<プロバイダのソースアドレス>",
version = "<プロバイダのバージョン>"
}
}
プロバイダのローカル名はprovider
ブロックで使われる。
backend
ブロック
ステートファイル(.tfstate)の保存方法(バックエンド)を設定するブロック。
backend "<バックエンドタイプ>" {
<バックエンドタイプ固有の設定>
}
ステートファイルは、その名の通りTerraformの管理対象であるインフラ構成の状態を保存するもの。
backend
ブロックで指定できるバックエンドタイプや、その固有の設定については、使用するTerraformバージョンのリファレンスを参照する必要がある。例えばgcs
バックエンドタイプでは、以下のような設定をする。
terraform {
backend "gcs" {
bucket = "tfstate" # 保存先のGCSバケット名
prefix = "terraform/production" # <保存先のバケット名以下のディレクトリ名>/<tfstateファイル名>
}
}
valiable
TODO
provider
ブロック
プロバイダを使って、各種インフラリソースの詳細設定をするにあたっての、前提条件を設定するブロック。
provider <プロバイダのローカル名> {
<プロバイダ固有の設定>
}
ボディにはプロバイダ固有の設定を記述する。
例えばgoogle
プロバイダだとproject, region
という固有の設定がある。
provider "google" {
# resourceブロックで設定するインフラリソースが所属するGoogle Cloudプロジェクトのデフォルト値
project = "acme-app"
# resourceブロックで設定するインフラリソースが所属するGoogle Cloudリージョンのデフォルト値
region = "us-central1"
}
ボディで設定できる項目は、各プロバイダのリファレンスを参照する必要がある。
resource
ブロック
仮想ネットワークなどのインフラリソースの設定をするブロック。
resource "<リソースタイプ>" "<リソースのローカル名>" { # リソースタイプとローカル名の組み合わせはモジュール内で一意
<リソースタイプ固有の設定>
}
対象のリソース(1番目のラベル)に対する詳細設定を記述(ボディ)し、任意のローカル名(2番目のラベル)を与える。
指定できるリソースタイプは、required_providers
ブロックで設定したプロバイダから提供されるもの。
ローカル名はモジュール内で一意である必要があり、そのモジュール内だけで有効である。
ボディで設定できる項目は、provider
ブロック同様、各プロバイダのリファレンスを参照する必要がある。
for_each
記述したresourceブロックをstringのmapやset(配列)を使ってループさせつつ、別のブロックインスタンスとして扱えるという機能。map, setの要素となったブロックは、以下のように参照可能。
- mapの場合:
<リソースタイプ>.<リソースのローカル名>[mapのキー名]
- setの場合:
<リソースタイプ>.<リソースのローカル名>[setの要素値]
module
TODO
data
TODO
2.4. terraform コマンド
主要なものをTerraformを使用する際の工程順に並べると以下の通り。
-
terraform validate
: .tfファイルの検証 -
terraform init
: .tfファイルに基づくクラウドインフラへの設定反映に必要なPROVIDERのダウンロード -
terraform plan
: クラウドリソースに対する現設定からの変化点の確認 -
terraform apply
: クラウドリソースに.tfファイルの設定を反映 -
terraform destory
: .tfファイルで定義したクラウドリソースを削除
また、terraform fmt
という.tfファイル内の標準の記述形式に則ってフォーマットしてくれるコマンドもある。
plan,apply,destroy
について
差分に現れる記号の意味
-
+
: 追加 -
-
: 削除 -
-/+
: 置換 (削除からの追加) -
~
: 更新 (削除からの追加じゃなくて、単純な更新) -
<=
: 読み込み? (データリソースへの適用時のみ発生しうるらしい)
tfstate
Terraformで適用したインフラリソースの状態を保存しておくファイル。
terraform plan
を実行すると、「実際の環境の状態」、「過去にTerraformで適用した際の状態(tfstate)」、「これから適用しようとしている内容(.tf)」を加味し、結果どういう変更がなされるのか?の結果が出力される。
(Terraformを介さず手動で手を加てしまった場合、以下のようなメッセージで指摘される
Terraform detected the following changes made outside of Terraform since the last "terraform apply":
特定のリソースに対してだけインフラ設定を反映させたい場合
以下のようにする。
terraform plan -target='<対象のリソース1>' -target='<対象のリソース2>' ...
リソースは、'module.<モジュール名>.<リソースタイプ>.<リソースのローカル名>'
という形で指定するのが無難。
for_eachで暗黙的に生成されるresourceオブジェクトを指定する場合、
'module.<モジュール名>.<リソースタイプ>.<リソースのローカル名>["キー名"]'
みたいな形になるが、'
でくくらずに実行して以下のエラーに遭遇したことがあった
Error: Invalid target "module.<モジュール名>.<リソースタイプ>.<リソースのローカル名>[<キー名>]"
│
│ Index brackets must contain either a literal number or a literal string.
╵
2.5. 公式ドキュメント
以下、特に有用と思われるドキュメント。
3. 参考