#terraform importの使い方メモ
##背景
terraformではv0.7.0以降で実装されたimport
コマンドを使用して既存インフラをterraform管理下に置くことができます。といってもtfstate
へのインポートのみです。しかもv0.9.2
時点では一括インポートができないため、リソースIDを指定してインポートする必要があります。さらにその後terraform plan
で差分がなくなるまでtfファイルを作り込む面倒な作業が待っています。そのような事情もあって現時点ではdtan4/terraformingを使用する人が多いと思われますが、やはり対応リソースの広さに惹かれて本家の機能を使ってみました。
##本題
###事前にモジュール構造を決める
とりあえず手で環境を作ってHashicorpのbest practiceに従ったモジュール構造でコード化しようと試みました。作った環境は上記のコードとだいたい同じで、パブリックのサブネットとプライベートなサブネットがある単純なVPCです。(詳細は割愛)
###インポート
何はともあれ公式のリファレンスに従ってインポートしてみます。vpc-idはマネジメントコンソールから拾ってきます。リソースの多い場合はSDKなどでIDを引っこ抜いてくるスクリプトを作ったほうが良いと思います。
$ terraform import aws_vpc.vpc vpc-********
次にvpcのtfファイルを作成し、planを実行しました。しかし既存リソースは定義なしと見なされ再作成の対象となってしまいます。
$terraform plan
- aws_vpc.vpc
+ module.network.vpc.aws_vpc.vpc
原因は一見してわかるようにモジュール構造が異なるためです。そこでモジュール指定でインポートしてみると、今度はリソース名を解決できないと怒られます。
$ terraform import module.network.vpc.aws_vpc.vpc vpc-********
Error importing: failed to parse resource address 'module.network.vpc.aws_vpc.vpc': Unexpected value for InstanceType field: "vpc"
###モジュールの指定方法
インポートの際はplanの表示と違ってvpcモジュール側もmodule.vpc
と指定する必要があったのでした。apply
等と同じ仕様ですね。
$ terraform import module.network.module.vpc.aws_vpc.vpc vpc-********
この状態でterraform plan
を実行するとめでたく差分なしとなりvpcは破壊されなくて済むのでした。terraformの管理下におく場合はとりあえずインポートしてからtfファイルを作り始めるというよりモジュール構造を決めてからインポートした方が効率的と思います。
###インポートできないリソース
ルートテーブルなどに紐づく関連付けやセキュリティグループのルールは個別のインポートができない仕様です。ルートテーブルに複数の関連付けなどがある場合自動的にリソース名の末尾に数字が付いた名前で別々のリソース定義としてインポートされてきます。
ここで気になるのが、例えばルートテーブルに対する関連付けを動的に生成するような管理をしたい場合です。例えば下記のようなコードでprivate
ルートテーブルに対する関連付けを一括して管理したいとします。
resource "aws_route_table_association" "private" {
count = "${length(var.private_subnet_ids)}"
subnet_id = "${element(var.private_subnet_ids, count.index)}"
route_table_id = "${element(aws_route_table.private.*.id, count.index)}"
}
しかしimport
は上位のルートテーブル単位でしかできません。
terraform import module.network.module.route_table.aws_route_table.private rtb-*******
このコマンドの結果はaws_route_table_association.private
、aws_route_table_association.private-1
などどと別々の定義としてtfstate
に書き出されます。こうなると事後でstateに合わせるためにはtfファイルに関連付けの数だけリソース定義を書かないといけなくなりそうです。state
と差分がなければコードなんて何でもいいだろという思想も一理ありますが、やはりここは保守性や拡張性なども考えたいところです。
###逆にtfstateをコードに合わせる
推奨はしませんがtfstate
を手で編集するか、terraformをカスタマイズしてpull requestを出してしまうかですが、余程腕に自信のあるエンジニアでない限り前者の方が手っ取り早いでしょう。aws_route_table_association.private-1
をaws_route_table_association.private.1
などどコードに合わせて書き換えてしまいましょう。(自己責任)
tfstate
の書き換えは下記の記事を参考にさせて頂きました
Terraforming未対応の既存リソースも自力でtfstateを書いてTerraform管理下に入れる
##結論
まだまだ未完成の機能なので単にインポートするだけで綺麗にコード化して管理できるとはいかないようです。v1.0
が待たれます。