terraform
インストール
- tfenv をインストールし、tfenv から terraform の任意のバージョンをインストール
brew install tfenv
tfenv install 0.8.1
tfenv install latest
tfenv install latest:^0.8 # 0.8系で最新インストールされる
# 指定したバージョンを使用する
tfenv use 0.8.1
tfenv use latest:^.0.8
# インストールして使用可能なバージョンを一覧表示
tfenv list
# インストール可能なバージョンを表示
tfenv list-remote
設定
.terraform-version- プロジェクトルートに.terraform-version というファイルを置いておくとそのファイルに書かれたバージョンを優先して利用
変数
外部から変数を付与する方法は主に以下の 3 種類
| No. | 種類 | 例 | 補足 | 上書例 |
|---|---|---|---|---|
| 1 | 環境変数 | TF_VAR_<NAME> |
msgという変数が定義されているとTF_VAR_msgで定義可能 |
export TF_VAR_msg="ABC" terraform apply |
| 2 | 変数ファイル | sample.tfvars | git 管理可能 | tfvars という拡張子で定義されたファイルであれば-var-fileの引数で指定しなくても自動で tfvars 拡張子ファイルが適用される |
| 3 | コマンド引数 | -var |
テストや一時的な利用で使える | terraform apply -var msg="EFG" |
仕様
terraform applyで基本的に実装するが以下の前提がある- カレントディレクトリの
tfファイルをすべて読み込む - サブディレクトリの
tfファイルは読み込まない
- カレントディレクトリの
tfstateとは
tfstateファイルは terraform によって構築されたクラウドの状態情報ファイル- どのようなりソースが作成されたか、そのリソースの ID や設定内容などを保存している
- backend 機能を利用することで、複数のユーザーで terraform を管理する場合、S3 バケットに tfstate を保存して1つの tfstate を共有することが可能
- backend 機能なしでは state ファイルを実行環境のローカル環境に作成するので複数ユーザーで状態管理をするのが難しい
# Backend
terraform {
required_version = "1.5.6"
required_providers {
aws = "5.15.0"
}
backend "s3" {
region = "ap-northeast-1"
key = "任意のファイル名.tfstate"
dynamodb_table = "任意のDynamoDB名" # オプション。状態ロックをDynamodbで管理することが可能
bucket = "任意のバケット名" # オプション
encrypt = true # オプション
}
}
構文
- HCL2 とは
HashiCorpLanguage2の略称で HashiCorp 社の独自言語- json と似ているが違いがあり、下記 json との違い
- 簡易プログラムが組める
- コメント(
#)が記述可能 :ではなく=でキーバリューを指定- ヒアドキュメント利用可能
{}で囲む設定をブロックと呼ぶ- ブロックにはいくつかの種類(ブロックタイプ)があり、ブロックタイプによってラベルを指定可能
ブロックタイプ
| 種類 | 説明 | 補足 | 具体例 |
|---|---|---|---|
| locals | 変数: 外部から変更不可 |
${local.<変数名>}で参照 |
|
| variables | 変数: 外部から変更可能 |
コマンド実行時にオプション、ファイル指定で上書き可能 | ${var.<変数名>}で参照 |
| terraform | terraform 本体の設定 | terraform ブロックは terraform 本体、provider は各サービスのことで対となるような存在 | |
| provider | AWS や Azure,GCP などの対象サービスのこと | ||
| data | terraform 管理外のリソース取得 | ||
| resource | terraform 管理内のリソース | ||
| output | 外部から参照できるようにする値 | ||
| import | 手動で作成した既存リソースの取り込み? | 最終手段? | |
- リソース参照
resource "aws_vpc" "vpc" {省略}というリソースが定義されていたら別のリソースからaws_voc.vpc.idとラベルをドット(.)区切りで指定して参照できる
リソースのインポート
手動作成したリソースなどを terraform 管理下に取り込むことができる。大枠は以下
- 手動作成したリソース名に相当するコードを作成(
アドレス.取り込み先リソース名)- コードの側だけ作成し、中身は後でインポートで取り込むため空で OK
- 指定したリソースをインポート(
terraform import 取り込み先リソース名 ターゲットID) - インポートしたリソースを
terraform state show アドレス.リ対象リソース名で表示し、1のコードに落とし込む
import {
to = aws_codestarconnections_connection.リソース名
id = "arn:aws:codestar-connections:us-west-1:0123456789:connection/idididididididididididididididididid"
}
リソースの移動
# module内リソースの場合は、moduleの中で定義すればOK
moved {
from = aws_codebuild_project.旧リソース名(移動前)
to = aws_codebuild_project.新リソース名(移動後)
}
# moduleの場合も同じ
moved {
from = module.lambda
to = module.main
}
メタ引数
| No. | 種類 | 例 | 補足 | 上書例 |
|---|---|---|---|---|
| depends_on | ||||
| count | ||||
| for_each | ||||
| lifecycle | ||||
| provider |
拡張機能
vscode ではグラフ化に便利なgraphvizという拡張機能があり依存関係を可視化できる
参考ドキュメント
HCL2 と terraformCLI
- 公式ドキュメント
- HCL2
- terraform CLI ※
Alphabetical List of Commandsという項目がアルファベット順でコマンドが検索できてわかりやすい - provider(aws)
よく使う事例
- keys 関数 - キーバリュー形式のキーを表示
- value 関数 - キーバリュー形式のバリューを表示
- range 関数 - 番号リスト作成
- リスト関連
- compact 関数 - リストから空・null を消去する
- concat 関数 - リスト同士を繋げて 1 つのリストにする
- flatten 関数 - リスト同士を繋げてネスト状態や空文字を除去した 1 つのリストにする
- distinct 関数 - リストから重複した値を消去する
- length 関数 - length 確認
terraform console
>length(["a", "b"])
- プレフィックスリストから IP リストを作成
# dataブロックで事前に定義しておくこと
terraform console
>data.aws_ec2_managed_prefix_list.プレフィックスリスト名.entries[*].cidr
lifecycle
# passwordなど変更する余地があるリソースが変更されても更新対象としないように設定する
lifecycle {
ignore_changes = [
master_password
]
}
# prevent_destroyを記述することでterraformで削除されなくなる。削除したいときにはterraform state rmで管理対象から外してから
resource "aws_eip" "nat_single" {
・・・省略
lifecycle {
prevent_destroy = true # terraform destroyで削除を防止
}
コマンド
- 初期化
terraform init
terraform init -migrate-state # stateファイルを維持したままバックエンドに移動する
- 確認
# 現在の状態とコードに定義された状態を比較して、変更が必要な場合に変更内容を表示)
terraform plan
# 特定のリソースのみ確認する
terraform plan -target=指定したいリソース名
# 結果を指定ファイル名へ出力する
terraform plan -out=ファイル名
# デバッグログを有効にして詳細な情報を表示
TF_LOG=DEBUG terraform plan
# クラウド上の現状を反映させる
terraform refresh # こちらはterraform1.0未満の古いコマンドで1.x系では非推奨
terraform apply -refresh-only
# tfstateで管理されているリソースの一覧表示
terraform state list
# tfstateで管理されているリソースの詳細表示。terraform planで差分ない時に詳細確認した場合にも便利
terraform state show アドレス.リソース名
- リソース名の変更
# 注意点としてコードの方も合わせて変更しておくこと
terraform state mv アドレス.変更前リソース名 アドレス.変更後リソース名
- リソースのインポート
# tfstateファイルへリソースのインポートがされるため、コード上は変化なし
terraform import アドレス.リソース名(任意名) ターゲットID
- デプロイ
# y/nのプロンプトで最終確認あり
terraform apply
# 特定のリソースのみデプロイ
terraform apply -target=指定したいリソース名
# プロンプトを表示せずに自動的に承認(確認プロンプトが不要)
terraform apply -auto-approve
- 削除
terraform apply -destroy
terraform apply -destroy -target=指定したいリソース名
terraform destory -auto-approve # プロンプトを表示せずに自動的に承認(確認プロンプトが不要)
# 削除防止はlifecycleを参照
# terraform管理外から外す
terraform state rm アドレス.変更前リソース名 # コード上にリソースが残っていれば再構築されてしまうので注意
- フォーマット
### フォーマット(カレントディレクトリ) ※変更したファイル名のみ表示 ###
terraform fmt
# フォーマット(変更されるファイル名を事前検証)
terraform fmt -check
# フォーマット(サブディレクトリ含む)
terraform fmt -recursive
# フォーマット(サブディレクトリ含んでフォーマット内容をdiffで表示して事前検証)
terraform fmt -recursive -diff -check
- その他
# 組み込み関数などや変数を試したい時のお試し
terraform console
>local.ターゲット名
ターゲット内容が出力される...
>type(local.default_list)
typeが出力される...
トラブルシューティング
- Terraform の状態ロック
terraform apply実行時に以下のようなエラーが表示されることがある。
Terraform acquires a state lock to protect the state from being written
by multiple users at the same time. Please resolve the issue above and try
again. For most commands, you can disable locking with the "-lock=false"
flag, but this is not recommended.
- 状態ロック解除
# 状態ロック自体を解除
terraform force-unlock xxxxxx(ID)
# 状態ロックを無視してapply
terraform apply -lock=false
コード例
- 三項演算子
variable "env" {
default = "dev"
}
// 例 条件 ? true : false
value = var.env == "prod" ? "t2.large" : "t2.micro"
- validation
# 変数の入力値を検証する
validation {
# condition -> trueならバリデーション通過、falseならエラー
# contains(第一引数, 第二引数) -> 第一引数の中に第二引数が含まれていればtrue
condition = contains(["Zip", "Image"], var.package_type)
# エラー時に表示するメッセージ
error_message = "package_type must be either 'Zip' or 'Image'"
}
- リスナールール
# リスナールールの加重ルーティング例
resource "aws_lb_listener_rule" "ecs_https_1" {
listener_arn = aws_lb_listener.tmp_https.arn
priority = 100
action {
type = "forward"
forward {
target_group {
arn = ターゲットグループarn1
weight = 90
}
target_group {
arn = ターゲットグループarn2
weight = 10
}
stickiness {
enabled = true
duration = 600
}
}
}
condition {
host_header {
values = [
対象ドメイン名
]
}
}
lifecycle {
ignore_changes = [
# target_groupはBlue/Greenデプロイで動的に変更される
action["forward"],
]
}
}