More than 1 year has passed since last update.

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.privateaws_route_table_association.private-1などどと別々の定義としてtfstateに書き出されます。こうなると事後でstateに合わせるためにはtfファイルに関連付けの数だけリソース定義を書かないといけなくなりそうです。stateと差分がなければコードなんて何でもいいだろという思想も一理ありますが、やはりここは保守性や拡張性なども考えたいところです。

逆にtfstateをコードに合わせる

推奨はしませんがtfstateを手で編集するか、terraformをカスタマイズしてpull requestを出してしまうかですが、余程腕に自信のあるエンジニアでない限り前者の方が手っ取り早いでしょう。aws_route_table_association.private-1aws_route_table_association.private.1
などどコードに合わせて書き換えてしまいましょう。(自己責任)

tfstateの書き換えは下記の記事を参考にさせて頂きました
Terraforming未対応の既存リソースも自力でtfstateを書いてTerraform管理下に入れる

結論

まだまだ未完成の機能なので単にインポートするだけで綺麗にコード化して管理できるとはいかないようです。v1.0が待たれます。

Sign up for free and join this conversation.
Sign Up
If you already have a Qiita account log in.