こんにちは。会員システムグループでエンジニアをしている山田です。
今回はterraformの注意点について紹介します。
概要
terraform import
はterraformを使っていなかった頃のリソースを取り込むためのものであり、定常運用で使うものではないという話です。
terraformで運用するならterraformだけで完結させてください。importは常用するための機能ではありません。
importの限界
importを前提とした運用には以下の問題があります
import漏れ
コンソールで作成したものを後からimportする、という運用では、作られたリソース全てがterraform管理下にある、という保証ができません。
コンソール上でよしなに作成されたIAM RoleやS3 Policy、Route53レコードなどを見逃してしまい、terraform管理外だから不要だと思って消したら実は必要だった、というような事態が発生します。
再現性がない
1から実行されたことのないterraformコードには再現性がありません。
例えば暗黙的な依存関係にあるInternet GWとNAT GWは
1 2 3 4 5 6 7 8 9 |
resource "aws_internet_gateway" "igw" { ... } resource "aws_nat_gateway" "ngw" { ... depends_on = [aws_internet_gateway.igw] } |
のようにdepens_on
を明示しないと実行に失敗しますが、importではこれに気づくことができません。
importブロックが使えないことがある
terraform 1.5よりimportブロックが使えるようになりました。
これはimportの内容をtfファイルに記述できるものであり、コマンド実行前にplanができることでterraform importコマンドを使うより安全な操作が行えます。
しかしながら、AWS APIが非対称なケース、つまりPOSTで設定した内容と、GETで帰って来る内容が異なるようなリソースでは実行に失敗します。
ex) aws_lb_listener
のdefault_action
1 2 3 4 5 6 7 8 9 10 |
resource "aws_lb_listener" "https" { ... default_action { type = "forward" target_group_arn = aws_lb_target_group.a.arn } ... } |
1 2 3 4 5 6 7 8 9 10 11 12 |
Planning failed. Terraform encountered an error while generating this plan. ╷ │ Error: Invalid Attribute Combination │ │ Only one of "default_action[0].target_group_arn" or "default_action[0].forward" can be specified. │ default_action[0] │ │ with module.ecs_front.aws_lb_listener.https, │ on ../../modules/ecs_front/lb.tf line 41, in resource "aws_lb_listener" "https": │ 41: resource "aws_lb_listener" "https" { │ |
上記例ではdefault_action[0].target_group_arn
のみを指定しようとしていますが、AWS APIのGET結果はdefault_action[0].target_group_arn
と default_action[0].forward
が両方指定された状態で返ってきてしまいます。両方指定された状態をterraform planは許容しないのでエラーとなります。
terraform importコマンドを使えばplanを実行することはないため、失敗することはなくなります。ただしimport後にchangedが出てしまうことがあります。
不要なchanged
terraform importしたリソースは、再度plan・applyすると必ずchangedが出るものがあります。
これは主にAWS上に存在せず、tfstate上にのみ存在する値があることによって発生します。
- ex)
aws_ecs_service
のwait_for_steady_state
など、terraform自体の実行を制御するパラメータ - ex)
sensitive = true
の設定などにより、terraform上でsensitiveとして扱うべきパラメータ
これらがあるため、「importした後にchangedが出なくなるようにコードを編集すればOK」とはいきません。特に前者はtfstateを直接編集しないとapplyすらできないというケースも存在します。
import不可リソース
稀ですがimportが不可能なリソースも存在します。AWS Providerの場合はドキュメントにimportできない旨の記載があります。
ex) aws_lb_target_group_attachment
これはimportができないため、applyしてみるしかありません。
(上記の場合、全く同じ設定でapplyすればエラーなく成功します)
どうすればよいのか
コンソール作業をやめてterraformですべて作るようにしましょう。
一度コンソール作業を行わないとどのようなリソースを作ればよいのかわからない、という場合は以下のような手順にします。
- コンソール上でお試しリソースを作り、動く状態にする
- このとき、リソース名は本番用とは別の名称にする
- 同等の構成を再現できるようにterraformコードを書き、applyする
- こちらのリソース名は本番相当とし、お試し用とは被らないようにする
- お試しリソースを手動で全削除する
- 動作検証を行う
Terraformで0から作成できる状態を担保し、コードが信頼できる状態を保つようにしましょう。importは最後の手段です。
今回はTerraformの適切な使用方法と、Terraform inportの限界について紹介しました。 Terraformを利用する際はぜひこれらの注意点を念頭に置いて実践してみてください。