コマンド@Terraform¶
はじめに¶
本サイトにつきまして、以下をご認識のほど宜しくお願いいたします。
01. terraformコマンド¶
global option¶
▼ -chdir¶
コマンドを実行する作業ディレクトリを指定する。
apply¶
▼ applyとは¶
インフラリソースをプロビジョニングする。
▼ -destroy¶
指定したバックエンドで管理するリソースを削除する。
削除後に、パラメーターとして使用したtfvarsファイル自体を削除する必要がある。
# 削除するまでに以下の手順が必要である。
# 初期化
$ terraform init -reconfigure -backend-config=backend.tfvars
# 現状のtfstateファイルと実インフラの間に、差分がないことを確認する。
$ terraform plan -var-file=terraform.tfvars
No changes. Your infrastructure matches the configuration.
# 実行計画
$ terraform plan -destroy -var-file=foo.tfvars
# 削除
$ terraform apply -destroy -var-file=foo.tfvars
▼ -parallelism¶
並列処理数を設定できる。
デフォルト値は10である。
クラウドプロバイダーのレートリミットが小さい場合は、並列処理数を5ほどに小さくし、コマンドのAPIのコールがレートリミットを超過しないようにする。
$ terraform apply \
-var-file=foo.tfvars \
-parallelism=30
オプションで毎回設定するのが大変なため、環境変数で設定しても良い。
$ export TF_CLI_ARGS_plan="--parallelism=50"
$ export TF_CLI_ARGS_apply="--parallelism=50"
▼ -refresh-only¶
すでに管理対象になっている実インフラが、Terraformの管理外から変更された場合、実インフラの状態はそのままに、tfstateファイルにその状態を書き込む。
もし、Terraform管理外の実インフラがない場合は、No changes.になる。
具体的は、terraform planコマンドで出力されるNote: Objects have changed outside of Terraformの内容を指す。
ただし、そもそもTerraformで管理されていない実インフラ (create処理判定されるもの) を処理することはできず、代わりにterraform importコマンドの実行が必要になる。
$ terraform apply -refresh-only
Apply complete! Resources: 0 added, 0 changed, 0 destroyed.
$ terraform plan -refresh-only
# もし、Terraform管理外の実インフラがない場合は、No changes. になる。
No changes. Your infrastructure still matches the configuration.
Changes to Outputs:
...
$ terraform apply -refresh-only
Apply complete! Resources: 0 added, 0 changed, 0 destroyed. # 実インフラは変更しない。
▼ -target¶
特定のresourceブロックを使用して、terraform applyコマンドを実行する。
リリース用のブランチに、今回はリリースしたくない差分が含まれてしまっているような場合、特定の差分のみをプロビジョニングできる。
$ terraform apply \
-var-file=foo.tfvars \
-target='<resourceタイプ>.<resourceブロック名>'
moduleブロックを採用している場合、指定の方法が異なる。
$ terraform apply \
-var-file=foo.tfvars \
-target='module.<moduleブロック名>.<resourceタイプ>.<resourceブロック名>'
*例*
$ terraform apply \
-var-file=foo.tfvars \
-target='aws_instance.bastion'
▼ -var-file¶
クラウドプロバイダー上にクラウドインフラを作成する。
$ terraform apply -var-file foo.tfvars
# ディレクトリを指定することも可能
$ terraform -chdir=<ルートモジュールのディレクトリへの相対パス> apply \
-var-file=<ルートモジュールのディレクトリへの相対パス>/foo.tfvars
成功すると、以下のメッセージが表示される。
Apply complete! Resources: 1 added, 0 changed, 0 destroyed.
▼ .tfplanファイル¶
事前に、terraform planコマンドによって作成された実行プランファイルを元に、terraform applyコマンドを実行する。
実行プランを渡す場合は、環境変数をオプションに設定する必要はない。
$ terraform apply foo.tfplan
init¶
▼ initとは¶
terraformコマンドを実行しているローカルマシンの.terraformディレクトリを初期化 (terraform.lock.hclファイルの作成、ローカル/リモートモジュールやプロバイダーのインストール、バックエンドの切り替えなど) を実行する。
tfstateファイルを書き換えることはしないため、基本的には安全である。
もしプロバイダーをアップグレードした場合は、新バージョンのインストールするために、本コマンドを実行する必要がある。
Initializing provider plugins...
- Reusing previous version of hashicorp/aws from the dependency lock file
- Reusing previous version of pagerduty/pagerduty from the dependency lock file
# AWSプロバイダーのバージョン
- Installing hashicorp/aws v4.3.0...
- Installed hashicorp/aws v4.3.0 (signed by HashiCorp)
# 使用しているその他のプロバイダーのバージョン
- Installing foo/bar v2.3.0...
- Installed foo/bar v2.3.0 (signed by a HashiCorp partner, key ID *****)
▼ -backend=false¶
指定したバックエンドの初期化をスキップする。
一度でもバックエンドを初期化している場合は、改めて初期化することは不要なため、このオプションを使用する。
$ terraform init -backend=false
# ディレクトリを指定することも可能
$ terraform -chdir=<ルートモジュールのディレクトリへの相対パス> init -backend=false
▼ -backend=true, -backend-config¶
指定したバックエンドにあるtfstateファイルを使用して、ローカルマシンの.terraformディレクトリを初期化する。
また、terraform planコマンドやterraform applyコマンドの向き先を別のバックエンドに切り替える。
バックエンドの代わりに、terraformブロック内のbackendオプションで指定しても良い。
ただし、terraform settingブロック内では通常変数を使用できないため、こちらのオプションが推奨である。
$ terraform init \
-backend=true \
-reconfigure \
`# バケット名` \
-backend-config="bucket=prd-foo-tfstate-bucket" \
`# tfstateファイル名` \
-backend-config="key=terraform.tfstate" \
`# 資格情報ファイルのプロファイル名` \
-backend-config="profile=bar" \
-backend-config="encrypt=true"
▼ -reconfigure¶
初期化のためのterraform initコマンドの時、今現在で設定しているバックエンドにあるtfstateファイルをそのまま使用する。
--migrate-stateオプションとは異なり、元のバックエンドが異なる場合、元のバックエンドのtfstateファイルはそのまま保持される。
$ terraform init -reconfigure -backend-config=./foo/backend.tfvars
また、開発時に一時的にlocalをバックエンドとして使用する場合にも役立つ。
▼ --migrate-state¶
初期化のためのterraform initコマンドの時、この時、元のバックエンドにあるtfstateファイルをコピーし、指定したバックエンドに移行する。
元のバックエンドのtfstateファイルを削除するか否かを選択できる。
$ terraform init --migrate-state -backend-config=./foo/backend.tfvars
▼ -upgrade¶
現在のバージョンを基に、自前/公式リモートモジュール、プラグイン、のアップグレード/ダウングレードを行う。
合わせて、.terraform.lock.hclファイルを更新する。
リモートモジュールやプラグインのバージョンを固定していない場合、upgradeオプションによって、最新のバージョンを毎回インストールすることになる。
$ terraform init -upgrade
▼ 問題が起こる場合¶
terraform initコマンドで以下のようなエラーが起こる場合がある。
│ Error: Failed to query available provider packages
│
│ Could not retrieve the list of available versions for provider hashicorp/aws: the previously-selected version <バージョン> is no longer available
╵
その場合、以下のいずれかで解決できることがある。
# プロバイダーの削除
$ rm -r $HOME/.terraform.d/plugins/registry.terraform.io/hashicorp/aws/
# 再インストール
$ terraform init --reconfigure
# プロバイダーの置き換え
$ PROVIDER_VER="<バージョン>"
$ PROVIDER_NAME="aws"
$ ARCH=$(if [ `uname -m` = 'arm64' ]; then echo "darwin_arm64"; else echo "darwin_amd64"; fi)
$ mkdir -p $HOME/.terraform.d/plugins/registry.terraform.io/hashicorp/${PROVIDER_NAME}/${PROVIDER_VER}/${ARCH}/ \
&& wget "https://releases.hashicorp.com/terraform-provider-${PROVIDER_NAME}/${PROVIDER_VER}/terraform-provider-${PROVIDER_NAME}_${PROVIDER_VER}_${ARCH}.zip" \
&& unzip "terraform-provider-${PROVIDER_NAME}_${PROVIDER_VER}_${ARCH}.zip" -d $HOME/.terraform.d/plugins/registry.terraform.io/hashicorp/${PROVIDER_NAME}/${PROVIDER_VER}/${ARCH}/ \
&& rm -f "terraform-provider-${PROVIDER_NAME}_${PROVIDER_VER}_${ARCH}.zip"
fmt¶
▼ fmtとは¶
.tfファイルのコードを整形する。
▼ -check¶
インデントを揃えるべき箇所が存在するか否かを判定する。
もし存在する場合『1』、存在しない場合は『0』を返却する。
$ terraform fmt -check
▼ -diff¶
インデントを揃えるべき箇所が存在する場合、これを取得する。
$ terraform fmt -diff
▼ -recursive¶
設定ファイルのインデントを揃える。
処理を行ったファイルが表示される。
# -recursive: サブディレクトリを含む全ファイルをフォーマット
$ terraform fmt -recursive
main.tf
get¶
terraformコマンドを実行しているローカルマシンの.terraformディレクトリに、ローカル/リモートモジュールをインストールする。
ただし、terraform initコマンドに同じ機能が含まれている。
$ terraform get
graph¶
▼ graphとは¶
tfstateファイルに基づいて、リソース間の依存関係をグラフ化する。
これにより、どのresourceブロックが他のどのresourceブロックを使用しているかがわかる。
Graphvizのダウンロードが必要である。
$ brew install graphviz
$ terraform graph | dot -Tpng > graph.png
▼ -draw-cycles¶
グラフの中で循環参照の矢印を色付きで表示する。
$ terraform graph -draw-cycles | dot -Tpng > graph.png
▼ 図形の見方¶
| 図形 | 種類 |
|---|---|
| 楕円 | ルートモジュール |
| 菱形 | providerブロック |
| 四角 | resourceブロック、dataブロック |
| ノート | variableブロック、outputブロック、localブロック |
▼ 他のツール¶
terraform graphコマンドを使用する以外に、リソース間の依存関係をグラフ化する。
- Terraform graph beautifie
- Rover
- Terraform Visual
- Inframap
- Pluralith
import¶
▼ importとは¶
実インフラの状態を読み込み、tfstateファイルに反映する。
▼ -var-file¶
.tfvarsファイルを指定して、terraform importコマンドを実行する。
$ terraform import \
-var-file=foo.tfvars \
<resourceタイプ>.<resourceブロック名> <実体リソースのARN、ID、名前など>
Import successful!
The resources that were imported are shown above. These resources are now in
your Terraform state and will henceforth be managed by Terraform.
output¶
tfstateファイルのoutputブロックを表示する。
$ terraform output -json
{
"vpc_id": {
"sensitive": "false",
"type": "string",
"value": "vpc-004c2d1ba7394b3d6"
}
}
plan¶
▼ planとは¶
実行計画を取得する。
▼ -destroy¶
指定したバックエンドで管理するリソースを削除する場合の実行計画を取得する。
$ terraform plan -destroy -var-file=foo.tfvars
Terraform will perform the following actions:
...
Plan: 0 to add, 0 to change, 10 to destroy.
▼ -var-file¶
クラウドに対してリクエストを行い、現在のインフラリソースの状態をtfstateファイルには反映せずに、設定ファイルの記述との差分を検証する。
スクリプト実行時に、環境変数が定義されたファイルを実行すると、variableブロックで宣言した変数に、値が格納される。
$ terraform plan -var-file=foo.tfvars
# ディレクトリを指定することも可能
# 第一引数で環境変数ファイルの相対パス、第二引数でをルートモジュールの相対パス
$ terraform -chdir=<ルートモジュールのディレクトリへの相対パス> plan \
-var-file=<ルートモジュールのディレクトリへの相対パス>/foo.tfvars
差分がなければ、以下の通りになる。
No changes. Infrastructure is up-to-date.
This means that Terraform did not detect any differences between your
configuration and real physical resources that exist. As a result, no
actions need to be performed.
▼ -target¶
特定のresourceブロックを使用して、terraform planコマンドを実行する。terraform planコマンドの最初のRefreshingStateフェーズを実行するブロックも絞り込めるため、特定のブロックRefreshingStateフェーズでバグがある場合の回避策にも使用できる。-targetオプションで指定するアドレスは、terraform planコマンド自身の出力結果や、terraform state listコマンドで確認できる。
$ terraform plan \
-var-file=foo.tfvars \
-target='<resourceタイプ>.<resourceブロック名>'
moduleブロックを使用している場合、指定の方法が異なる。
$ terraform plan \
-var-file=foo.tfvars \
-target='module.<moduleブロック名>.<resourceタイプ>.<resourceブロック名>'
指定方法は、全てのブロックを対象としたterraform planコマンドが参考になる。
grepコマンドを使用してresourceタイプ名やmoduleブロック名で抽出すると、指定方法がわかる。
# resourceブロックの指定方法を調べる。
$ terraform plan | grep <resourceタイプ>
# foo.bar will be created
# foo.baz will be changed
$ terraform plan \
-var-file=foo.tfvars \
-target='foo.bar' \
-target='foo.baz'
# moduleブロックの指定方法を調べる。
$ terraform plan | grep <moduleブロック名>
# module.qux.quux will be changed
# module.qux.corge will be changed
# module.grault will be destroyed
$ terraform plan \
-var-file=foo.tfvars \
-target='module.qux.quux' \
-target='module.qux.corge' \
-target='module.grault'
▼ -refresh¶
このオプションをつければ、terraform refreshコマンドを同時に実行してくれる。
ただし、デフォルトでtrueなため、不要である。
$ terraform plan \
-var-file=foo.tfvars \
-refresh=true
▼ -parallelism¶
並列処理数を設定できる。
デフォルト値は10である。
クラウドプロバイダーのレートリミットが小さい場合は、並列処理数を小さくし、コマンドのAPIのコールがレートリミットを超過しないようにする。
$ terraform plan \
-var-file=foo.tfvars \
-parallelism=30
▼ -out¶
実行プランファイルを作成する。
terraform applyコマンドのために使用できる。
$ terraform plan \
-var-file=foo.tfvars \
`# 実行プランファイル名` \
-out=foo.tfplan
planのプラクティス¶
▼ 出力内容の読み方¶
リソースの作成 (+) 、更新 (~) 、削除 (-) 、再作成 (-/+) で表す。
+ create
~ update in-place
- destroy
-/+ destroy and then create replacement
前半部分と後半部分に区別されている。
前半部分は、Terraform管理外の方法 (画面上、他ツール) による実インフラの変更について、その変更前後を検出する。
また、クラウドプロバイダーの新機能に伴う新しいAPIの追加も検出される。
検出のため、applyによって変更される実インフラを表しているわけではない。
そして後半部分は、Terraformのコードの変更によって、実インフラがどのように変更されるかを表している。
結果の最後に表示される対象のresourceブロックの数を確認しても、前半部分のresourceブロックは含まれていないことがわかる。
Note: Objects have changed outside of Terraform
Terraform detected the following changes made outside of Terraform since the
last "terraform apply":
# Terraform管理外の方法 (画面上、他ツール) による実インフラの変更について、その変更前後を検出。
Unless you have made equivalent changes to your configuration, or ignored the
relevant attributes using ignore_changes, the following plan may include
actions to undo or respond to these changes.
─────────────────────────────────────────────────────────────────────────────
Terraform used the selected providers to generate the following execution
plan. Resource actions are indicated with the following symbols:
~ update in-place
Terraform will perform the following actions:
# Terraformのコードの変更によって、実インフラがどのように変更されるか。
Plan: 0 to add, 1 to change, 0 to destroy.
▼ 差分認識される/されない変更¶
値を変更した場合に差分として認識されるものを示した。
ただし、差分として認識されるもののmovedブロックを使用すれば、差分を回避できる。
| 変更内容 | される/されない |
|---|---|
resourceブロック名の変更 |
される |
moduleブロック名の変更 |
される |
| ファイルやディレクトリを指定するパスの変更 | されない |
resourceブロックにハードコーディングされた値を環境変数に変更 (.tfvarsファイルに移行) |
されない |
variablesブロック名の変更 |
されない |
provider¶
▼ providerとは¶
terraform.lock.hclファイルを作成する。
*例*
CPUアーキテクチャ (例:Intel、AMD、ARM) を設定しつつ、terraform.lock.hclファイルを作成する。
$ terraform providers lock \
-platform=darwin_amd64 \
-platform=darwin_arm64 \
-platform=linux_amd64 \
-platform=linux_arm64 \
-platform=windows_amd64
事前に、terraform.lock.hclファイルを削除する必要がある。
$ rm .terraform.lock.hcl
refresh (非推奨)¶
▼ -var-file¶
クラウドに対してリクエストを行い、現在のインフラリソースの状態をtfstateファイルに反映する。非推奨であり、代わりに、terraform apply -refresh-onlyコマンドを使用する。
$ terraform refresh -var-file=foo.tfvars
state¶
▼ stateとは¶
tfstateファイルを操作する。
▼ list¶
tfstateファイルで定義されているresourceブロック (tfstateファイル上ではmanagedモード) の一覧を取得する。terraform applyコマンドで-targetオプションを使用する前にアドレスを確認したい場合や、terraform applyコマンドの実行に失敗した時にtfstateファイルと実インフラにどのような差分があるかを確認する場合に使用する。
$ terraform state list
以下の通り、moduleブロックも含めて、resourceブロックが表示される。
aws_instance.www-1a
aws_instance.www-1c
aws_key_pair.key_pair
module.alb_module.aws_alb.alb
module.ami_module.data.aws_ami.amazon_linux_2
module.route53_module.aws_route53_record.r53_record
module.route53_module.aws_route53_zone.r53_zone
module.security_group_module.aws_security_group.security_group_alb
module.security_group_module.aws_security_group.security_group_ecs
module.security_group_module.aws_security_group.security_group_instance
module.vpc_module.aws_internet_gateway.internet_gateway
module.vpc_module.aws_route_table.route_table_public
module.vpc_module.aws_route_table_association.route_table_association_public_1a
module.vpc_module.aws_route_table_association.route_table_association_public_1c
module.vpc_module.aws_subnet.subnet_public_1a
module.vpc_module.aws_subnet.subnet_public_1c
module.vpc_module.aws_vpc.vpc
▼ pull¶
リモートにあるtfstateファイルをローカルマシンにダウンロードする。
$ terraform state pull > <tfstateファイル名>
▼ rm¶
tfstateファイルから状態を削除し、Terraformの管理外にする。
count引数やfor_each引数を使用している場合は、シングルクオーテーションで囲う必要がある。
# 関数を使用せずに定義されている場合
$ terraform state rm --dry-run aws_instance.bastion
$ terraform state rm aws_instance.bastion
Removed aws_instance.bastion
Successfully removed 1 resource instance(s).
# moduleブロックを使用して定義されている場合
$ terraform state rm --dry-run module.ec2.aws_instance.bastion
$ terraform state rm module.ec2.aws_instance.bastion
Removed module.ec2.aws_instance.bastion
Successfully removed 1 resource instance(s).
# for_each関数で定義されている場合
$ terraform state rm --dry-run 'aws_instance.bastion["<キー名1>"]'
$ terraform state rm 'aws_instance.bastion["<キー名1>"]'
Removed aws_instance.bastion["<キー名1>"]
Successfully removed 1 resource instance(s).
# その他のキー名も削除が必要になる。
$ terraform state rm --dry-run 'aws_instance.bastion["<キー名2>"]'
$ terraform state rm 'aws_instance.bastion["<キー名2>"]'
# count関数で定義されている場合
$ terraform state rm --dry-run 'aws_instance.bastion[0]'
$ terraform state rm 'aws_instance.bastion[0]'
Removed aws_instance.bastion[0]
Successfully removed 1 resource instance(s).
# その他のインデックス番号も削除が必要になる。
$ terraform state rm --dry-run 'aws_instance.bastion[1]'
$ terraform state rm 'aws_instance.bastion[1]'
# moduleブロックを使用して、for_each関数で定義されている場合
$ terraform state rm --dry-run 'module.ec2.aws_instance.bastion["<キー名1>"]'
$ terraform state rm 'module.ec2.aws_instance.bastion["<キー名1>"]'
Removed module.ec2.aws_instance.bastion["<キー名1>"]
Successfully removed 1 resource instance(s).
# その他のキー名も削除が必要になる。
$ terraform state rm --dry-run 'module.ec2.aws_instance.bastion["<キー名2>"]'
$ terraform state rm 'module.ec2.aws_instance.bastion["<キー名2>"]'
▼ show list¶
tfstateファイルを表示する。
$ terraform state
{
"version": 4,
"terraform_version": "1.0.0",
"serial": 3,
"lineage": "*****-*****-*****-*****-*****",
"outputs": { # outputブロックのapplyで追加される。
"foo_ids": {
"value": "*****",
"type": "string"
}
},
"resources": [
{
"mode": "data", # dataブロックのapplyで追加される。
"type": "aws_caller_identity", # resourceタイプ
"name": "current", # リソース名
"provider": "provider[\"registry.terraform.io/hashicorp/aws\"]",
"instances": [ # 設定値
{
"schema_version": 0,
"attributes": {
"account_id": "<AWSアカウントID>",
"arn": "*****",
"id": "*****",
"user_id": "*****"
...
},
"sensitive_attributes": []
}
]
},
{
"module": "module.ec2", # moduleブロックの場合に追加される。
"mode": "managed", # importや、resourceブロックのapplyで追加される。
"type": "aws_instance", # resourceタイプ
"name": "bastion", # リソース名
"provider": "provider[\"registry.terraform.io/hashicorp/aws\"]",
"instances": [ # 設定値
{
"schema_version": 0,
"attributes": {
"arn": "*****",
"name": "prd-foo-instance"
"tags": {
"Env": "prd",
"ManagedBy": "terraform"
"Repository": "https://github.com/*****"
},
"description": "*****",
...
}
}
]
}
]
}
特定のresourceブロックのみを表示することもできる。
$ terraform state show 'aws_instance.bastion'
taint¶
▼ taintとは¶
バックエンドにあるtfstateファイルにて、指定されたresourceブロックのtaintedフラグを立てる。
▼ -var-file <resourceブロック>¶
例えば、applyしたが、途中でエラーが発生してしまい、実インフラに中途半端に作成されてしまうことがある。
ここで、taintedを立てておくと、実インフラのresourceブロックを削除したと想定したterraform planコマンドを実行できる。
$ terraform taint \
-var-file=foo.tfvars \
module.<moduleブロック名>.<resourceタイプ>.<resourceブロック名>
この後のterraform planコマンドのログからも、-/+で削除が行われる想定で、差分を比較していることがわかる。
$ terraform plan -var-file=foo.tfvars
An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
-/+ destroy and then create replacement
Terraform will perform the following actions:
-/+ <resourceタイプ>.<resourceブロック名> (tainted) (new resource required)
id: '1492336661259070634' => <computed> (forces new resource)
Plan: 1 to add, 0 to change, 1 to destroy.
validate¶
▼ validateとは¶
設定ファイルの検証を行う。
$ terraform validate
Success! The configuration is valid.
# ディレクトリを指定することも可能
$ terraform -chdir=<ルートモジュールのディレクトリへの相対パス> validate
02. 実インフラの全ての設定値をtfstateファイルに取り込む¶
importについて¶
実インフラの全ての設定値をtfstateファイルに取り込む場合、これの設定値をresourceブロックの設定値としてtfstateファイルに書き込み、Terraformの管理下におく必要がある (tfstateファイル上では、resourceブロックはmanagedモードという表記になる) 。
この時、terraform importコマンドを実行するか、コンソール画面から一度削除した上でterraform applyコマンドを実行する方法がある (前者が推奨) 。
執筆時点 (2022/07/19) で、複数のインフラリソースを網羅的に確認する方法は公式になく、インフラリソースを1個ずつ指定して、tfstateファイルに書き込んでいく必要がある。
似た目的で使用するterraform apply -refresh-onlyコマンドは実インフラの一部の設定値が対象であるが、importは実インフラの全ての設定値が対象である。
はじめに¶
(1)-
バックエンドがリモートの場合、ローカルマシンに
tfstateファイルをダウンロードする。
# バックエンドがS3バケットの場合
$ aws s3 cp s3://<S3バケット名>/<tfstateファイルへのパス> <ローカルマシンのパス>
# バックエンドがGoogle Cloud Storageの場合
$ gsutil cp gs://<Google Cloud Storage名>/<tfstateファイルへのパス> <ローカルマシンのパス>
(2)-
ダウンロードした
tfstateファイルをlocalバックエンドで指定する。
terraform {
# ローカルマシンで管理するように設定
backend "local" {
path = "terraform.tfstate"
}
}
初期化する¶
(3)-
localバックエンドで初期化する。
$ terraform init -reconfigure
tfファイルを定義する¶
▼ terraform importコマンドの場合¶
(4)-
.tfstateファイルと差分のないtfファイルを定義する手動で作成する場合は、頑張るしかない。
resource "<resourceタイプ>" "<resourceブロック名>" {
...
}
▼ importブロックの場合¶
importブロックを使用すると、.tfファイルを自動生成できる。
import {
# リソースの識別子
id = "<ID>"
# 自動生成するresourceブロック
to = <リソースタイプ>.<リソース名>
}
*実行例*
importブロックを使用して、resource "aws_instance" "ec2" {...}という実装を自動作成する。
import {
# リソースの識別子
id = "i-xxxxxxxx"
# import対象
to = aws_instance.foo
}
$ terraform plan -var-file=foo.tfvars -generate-config-out=aws_instance.tf
これにより、aws_instance.tfファイルを自動作成できる。
# __generated__ by Terraform
# Please review these resources and move them into your main configuration files.
resource "aws_instance" "foo" {
ami = "ami-xxxxxxxx"
associate_public_ip_address = true
availability_zone = "ap-northeast-1a"
cpu_core_count = 1
cpu_threads_per_core = 1
disable_api_stop = false
disable_api_termination = false
....
}
importを実施する¶
▼ terraform importコマンドの場合¶
(5)-
terraform importコマンドを実行する。これにより、
resourceタイプとresourceブロック名を指定し、tfstateファイルに実インフラの状態を書き込む。この時、
tfstateファイルの差分表記と反対に (例:+の場合は削除、-は追加、→は逆向き変更) になるように、tfファイルを修正する。パラメーターの『
<resourceタイプ>.<resourceブロック名>』は、terraform planコマンドの結果が参考になる。また『ARN、ID、名前など』は、
resourceタイプによって異なるため、リファレンスの『Import』の項目を確認すること。何らかの理由で
terraform importコマンドを実行し直したい場合は、terraform state rmコマンドでresourceブロックを削除し、改めて書き込む。
# 関数を使用せずに定義されている場合
$ terraform import \
-var-file=foo.tfvars \
'<resourceタイプ>.<resourceブロック名>' <実体リソースのARN、ID、名前など>
# もし、中途半端な同じリソースがtfstateファイルにある場合は、事前に削除する。
$ terraform state rm --dry-run '<resourceタイプ>.<resourceブロック名>'
$ terraform state rm '<resourceタイプ>.<resourceブロック名>'
# moduleブロックを使用して定義されている場合
$ terraform import \
-var-file=foo.tfvars \
'module.<moduleブロック名>.<resourceタイプ>.<resourceブロック名>' <実体リソースのARN、ID、名前など>
# もし、中途半端な同じリソースがtfstateファイルにある場合は、事前に削除する。
$ terraform state rm --dry-run 'module.<moduleブロック名>.<resourceタイプ>.<resourceブロック名>'
$ terraform state rm 'module.<moduleブロック名>.<resourceタイプ>.<resourceブロック名>'
# for_each関数で定義されている場合
$ terraform import \
-var-file=foo.tfvars \
'<resourceタイプ>.<resourceブロック名>["<キー名1>"]' <実体リソースのARN、ID、名前など>
# その他のキー名もimportが必要になる
$ terraform import \
-var-file=foo.tfvars \
'<resourceタイプ>.<resourceブロック名>["<キー名2>"]' <実体リソースのARN、ID、名前など>
# もし、中途半端な同じリソースがtfstateファイルにある場合は、事前に削除する。
$ terraform state rm --dry-run '<resourceタイプ>.<resourceブロック名>["<キー名1>"]'
$ terraform state rm --dry-run '<resourceタイプ>.<resourceブロック名>["<キー名2>"]'
$ terraform state rm '<resourceタイプ>.<resourceブロック名>["<キー名1>"]'
$ terraform state rm '<resourceタイプ>.<resourceブロック名>["<キー名2>"]'
# count関数で定義されている場合
$ terraform import \
-var-file=foo.tfvars \
'<resourceタイプ>.<resourceブロック名>[0]' <実体リソースのARN、ID、名前など>
# その他のインデックス番号もimportが必要になる
$ terraform import \
-var-file=foo.tfvars \
'<resourceタイプ>.<resourceブロック名>[1]' <実体リソースのARN、ID、名前など>
# もし、中途半端な同じリソースがtfstateファイルにある場合は、事前に削除する。
$ terraform state rm --dry-run '<resourceタイプ>.<resourceブロック名>[0]'
$ terraform state rm --dry-run '<resourceタイプ>.<resourceブロック名>[1]'
$ terraform state rm '<resourceタイプ>.<resourceブロック名>[0]'
$ terraform state rm '<resourceタイプ>.<resourceブロック名>[1]'
# moduleブロックを使用して、for_each関数で定義されている場合
$ terraform import \
-var-file=foo.tfvars \
'module.<moduleブロック名>.<resourceタイプ>.<resourceブロック名>["<キー名1>"]' <実体リソースのARN、ID、名前など>
# その他のキー名もimportが必要になる
$ terraform import \
-var-file=foo.tfvars \
'module.<moduleブロック名>.<resourceタイプ>.<resourceブロック名>["<キー名2>"]' <実体リソースのARN、ID、名前など>
# もし、中途半端な同じリソースがtfstateファイルにある場合は、事前に削除する。
$ terraform state rm --dry-run 'module.<moduleブロック名>.<resourceタイプ>.<resourceブロック名>["<キー名1>"]'
$ terraform state rm --dry-run 'module.<moduleブロック名>.<resourceタイプ>.<resourceブロック名>["<キー名2>"]'
$ terraform state rm 'module.<moduleブロック名>.<resourceタイプ>.<resourceブロック名>["<キー名1>"]'
$ terraform state rm 'module.<moduleブロック名>.<resourceタイプ>.<resourceブロック名>["<キー名2>"]'
▼ importブロックの場合¶
importブロックの場合、自動作成した.tfファイルも含めてterraform applyコマンドを実行する。
$ terraform apply
aws_instance.foo: Preparing import... [id=i-052562f6eee9d60d9]
aws_instance.foo: Refreshing state... [id=i-052562f6eee9d60d9]
...
Apply complete! Resources: 1 imported, 0 added, 0 changed, 0 destroyed.
差分を解消する (importブロックの場合は不要)¶
(6)-
tfstateファイルと実インフラの差分が無くなったら完了である。
$ terraform plan -var-file=foo.tfvars
No changes. Infrastructure is up-to-date.
Tips¶
▼ importできないresourceタイプ¶
resourceブロック間の紐付けに特化したようなresourceブロックは、terraform importコマンドに対応していないものが多い (AWSであれば、aws_acm_certificate_validation、aws_lb_target_group_attachmentなど) 。
その場合、tfstateファイルと実インフラの差分を解消できない。
ただし、こういった非対応のresourceブロックは、クラウドプロバイダーにはインフラリソースが存在しないTerraform特有のresourceブロックであることが多い。
そのため、実際にterraform applyコマンドを実行してみても、実インフラに影響が起こらない可能性がある。
▼ importを行わなかった場合のエラー¶
もしterraform importコマンドを行わないと、すでにクラウド上にインフラリソースが存在しているためにインフラリソースを作成できない、というエラーになってしまう。
(エラー例1)
Error: InvalidParameterException: Creation of service was not idempotent.
(エラー例2)
Error: error creating ECR repository: RepositoryAlreadyExistsException: The repository with name 'f' already exists in the registry with id '*****'
03. 実インフラの一部の設定値をtfstateファイルに取り込む¶
terraform apply -refresh-onlyコマンドについて¶
実インフラから実インフラの一部の設定値をtfstateファイルに取り込む場合、以下の方法が便利である。
似た目的で使用するimportは実インフラの全ての設定値が対象であるが、terraform apply -refresh-onlyコマンドは実インフラの一部の設定値が対象である。
(1)-
先にコンソール画面に設定値を変更する。
(2)-
terraform apply -refresh-onlyコマンドまたはterraform applyコマンドを実行する。 (3)-
実インフラは変更されず、
tfstateファイルに状態が書き込まれる。