💨

Terraformのデバッグのコツ(AWSの場合)

2021/09/07に公開

このページは

  • Terraformのデバッグのコツを残します

考え方

Terraformでエラーが出た場合原因として大まかに7パターン(実質6パターン)が考えられます。上から順に遭遇する確率は大きいです。
特に4以降に遭遇することはあまりないでしょう。

  1. Terraformの実行環境の問題
  2. Terraformのコードの問題
  3. Terraformでプロビジョニングする対象(AWS側)の問題
  4. Terraform自体の問題
  5. Terraformが内部で使用するAWS SDK Goの問題
  6. AWSのAPIの問題->わからなかったらAWSに問い合わせ
  7. Go言語の問題(ここまでくることはほぼ0なので対象外)

切り分け方

Terraformの実行環境の問題

terraform -vでバージョンが出れば実行環境としては問題ないです。
これが出ないときは環境構築やterraformのバイナリへのパスが通っていない問題が考えられるので確認します。

Terraformのコードの問題

  1. terraform validateコマンドで構文チェック
  2. terraform plan
    を実行すると大体解決します。
    Terraform自体のバリデーションが甘いこともあるのでこれで問題が解決しないこともあるのですがplanまでエラーなく通ればほぼ問題ないです

なおTerraformの書き方についてはTerraform providerのドキュメントに書き方が載っていることが多いです。

Terraformでプロビジョニングする対象(AWS側)の問題

おそらく、これが遭遇するエラーで一番多いです。
Terraformの定義ファイルは正しいのにエラーになる場合はほぼ間違いなくAWS側の制約が原因でエラーになっています。
例えば特定のオプションの組み合わせはAWS側として許されていない等のエラーです。
この場合はまずエラーメッセージを読みます。
なお、このメッセージが出る段階ではAWSのAPIをTerraform内部で実行した結果が出ていることが多いのでAWSのAPIドキュメントを確認したり、AWSのコンソールから同じ操作をしたときにエラーとなるか確認すると原因が判明することがあります。

Terraform自体の問題

ここからはTerraform内部の話になるのであんまりググっても情報が出てこないことが多いです。
いわゆるTerraform側のバグの可能性です。
こちらに関連するのは主に以下の3つのレポジトリです。
それぞれ

  1. provider =>AWS等対象リソースのプロビジョニングの処理が書かれている、だいたいこちらを見ると各リソースをどのように作成/定義しているのかが記載されている
  2. Terraform本体=>Terraform共通の処理planとかapplyとかの処理が書かれているが本体が原因となっている場合はあまりないと思うので優先度は低め
  3. plugin sdk=>provider側のコードを読んでいるとなんでこの処理で色々な操作ができるのだろうと思うことがあります。この秘密はこちらで定義されていることが多いです。こちらもほとんど読む必要はないです。

特にprovider側のISSUE やPull Requestに同じような問題がないかうまいキーワードを考えて検索します。だいたい捜査対象のリソースで絞ると問題一覧が出てくるのでここにもなければ新規の問題の可能性が高いです。

Terraformが内部で使用するAWS SDK Goの問題

*AWSを例にしています

Terraform provider awsではaws-sdk-goを使用しています。2021/9/7の時点ではV1使っています。こちらの問題の可能性もあります。

調べ方

Terraform provider aws側でどのようにリソースを作成しているのか調べます。
まず当該リソースについて記載されたコードを探します。
コードの命名規則は
/aws/resource_<調べたいリソース名>.go
のようになっているので見つけるのはそんなに難しくないです。

例えばAuroraのインスタンスの場合
https://github.com/hashicorp/terraform-provider-aws/blob/main/aws/resource_aws_rds_cluster_instance.go
注目は
resourceAwsRDSClusterInstanceCreate
のようにCreateと記載があるメソッドです、これがリソースの作成処理が書かれています。
terraform-provider-aws各リソース処理のコードは基本的に

  • 当該リソースの定義(resourceAwsRDSClusterInstance:Schemaの箇所)
  • CRUD
    の構成になっています。
    なのでリソースの定義情報を確認したい場合はSchemaの箇所を確認する、作成処理を確認したい場合はCreateとついたメソッドを確認します。

その形でみていくと
https://github.com/hashicorp/terraform-provider-aws/blob/main/aws/resource_aws_rds_cluster_instance.go#L298

		resp, err = conn.CreateDBInstance(createOpts)

のようにconn.<なんかのメソッド>
の処理が出てきます。
ここがAWS SDK経由でAWSのAPIを呼び出している箇所です。
この場合はCreateDBInstanceというSDK側のコードを呼び出しています。
実際aws-sdk-go側に
https://raw.githubusercontent.com/aws/aws-sdk-go/main/service/rds/api.go

func (c *RDS) CreateDBInstance(input *CreateDBInstanceInput) (*CreateDBInstanceOutput, error) {
	req, out := c.CreateDBInstanceRequest(input)
	return out, req.Send()
}

のように同じ名前のメソッドがあります。
あとはこのメソッドの中身を確認して実装有無を調べます。

AWSのAPIの問題

AWS SDK Goまで調べたのに問題がみつからないケースがあります。
この場合はAWS SDK Goで呼び出しているAWS APIの情報も確認して最終的にそれでもわからなければAWS側に原因の問い合わせすることになります。

例えば
https://github.com/hashicorp/terraform-provider-aws/issues/20789
のケースだとAWS SDK Go側にタグの定義がなくさらにAWSのAPI側の処理を調べる必要がありました。
https://docs.aws.amazon.com/cloudhsm/latest/APIReference/API_CreateHsm.html
APIの定義情報を確認するとそもそもタグが用意されていないかったということがわかりました。

まとめ

  1. Terraformで問題が起きたらTerraformの書き方に問題がないかterraform validate + planで調べよう
  2. その上でエラーが起きたらエラーメッセージを読もう
  3. それでもエラーメッセージの意味がわからなかったら結構難しい問題の可能性があるのでみんなにとりあえず聞いてみよう
    くらいでデバッグを進めるとよいのではないかと思います。

Discussion