著者は、 Write for DOnations プログラムの一環として、 Free and Open SourceFundを選択して寄付を受け取りました。

序章

物事は常に計画どおりに進むとは限りません。展開が失敗したり、既存のリソースが予期せず壊れたり、あなたとあなたのチームができるだけ早く問題を修正することを余儀なくされる可能性があります。 迅速な対応が必要な場合は、Terraformプロジェクトのデバッグに取り組む方法を理解することが重要です。

他のプログラミング言語やフレームワークで開発するのと同様に、Terraformでログレベルを設定して、必要な冗長性を備えた内部ワークフローを洞察することは、トラブルシューティングの際に役立つ機能です。 内部アクションをログに記録することにより、不適切なデータ型にデフォルト設定された変数など、暗黙的に隠されたエラーを明らかにすることができます。 また、フレームワークに共通するのは、サードパーティのモジュール(またはライブラリ)をインポートして使用し、プロジェクト間のコードの重複を減らす機能です。

このチュートリアルでは、変数が常に適切な値を持っていることを確認し、競合を防ぐために必要なプロバイダーとモジュールのバージョンを正確に指定します。 また、さまざまなレベルのデバッグモードの詳細度を有効にします。これは、Terraform自体の根本的な問題を診断するのに役立ちます。

前提条件

  • DigitalOceanパーソナルアクセストークン。DigitalOceanコントロールパネルから作成できます。 手順については、DigitalOcean製品ドキュメントパーソナルアクセストークンの作成方法を参照してください。
  • ローカルマシンにインストールされたTerraformと、DigitalOceanプロバイダーでセットアップされたプロジェクト。 DigitalOcean チュートリアルでTerraformを使用する方法のステップ1およびステップ2を完了し、代わりにプロジェクトフォルダーにterraform-troubleshootingという名前を付けてください。 loadbalanceの。 ステップ2の間、pvt_key変数とSSHキーリソースを含めないでください。

注:このチュートリアルは、Terraform1.0.2で特別にテストされています。

バージョン制約の設定

サードパーティのモジュールとプロバイダーを利用する機能により、Terraformコードを作成する際のコードの重複と労力を最小限に抑えることができますが、サードパーティのモジュールの開発者が新しいバージョンをリリースして、特定のコードに重大な変更をもたらす可能性もあります。 。 これを防ぐために、Terraformではバージョン境界を指定して、必要なバージョンのみがインストールおよび使用されるようにすることができます。 バージョンを指定するということは、コードでテストしたバージョンが必要になることを意味しますが、将来の更新の可能性も残します。

バージョン制約は文字列として指定され、モジュールまたはプロバイダーの要件を定義するときにversionパラメーターに渡されます。 前提条件の一部として、provider.tfdigitaloceanプロバイダーを既にリクエストしています。 次のコマンドを実行して、指定されているバージョン要件を確認します。

  1. cat provider.tf

プロバイダーコードは次のとおりです。

terraform-トラブルシューティング/provider.tf
terraform {
  required_providers {
    digitalocean = {
      source = "digitalocean/digitalocean"
      version = "~> 2.0"
    }
  }
}
...

この場合、digitaloceanプロバイダーをリクエストし、バージョンを2.xに設定しました。これは、2で始まるすべてのバージョンが一致することを意味します。 2.10.1などの明示的なバージョンを指定することもできます。

上記の場合のように、バージョンの制約は、1つのバージョンを指定するよりも複雑になる可能性があります。 条件の1つ以上のグループを、コンマ(,)で区切って含めることができます。 グループはそれぞれ、許容可能なバージョンの範囲を定義し、次のような演算子を含めることができます。

  • ><>=<=>=1.0などの比較用で、バージョンがまたは1.0より大きい。
  • !=:特定のバージョンを除外する場合-!= 1.0は、バージョン1.0の使用および要求を拒否します。
  • ~>:指定されたバージョンを右端のバージョン部分まで一致させるため。増分が許可されます(~>1.5.101.5.10および1.5.11と一致しますが、 1.5.9とは一致しません)。

複数のグループを持つバージョン制約の2つの例を次に示します。

  • >=1.0, <2.01.0シリーズ以降の2.0までのすべてのバージョンを許可します。
  • >1.0, != 1.51.5を除いて、1.0以上のバージョンを許可しますが、これも除外されます。

利用可能なバージョンを選択するには、指定されたすべての制約に合格し、他のモジュールやプロバイダー、および使用しているTerraformのバージョンとの互換性を維持する必要があります。 Terraformが組み合わせを受け入れられないと判断した場合、依存関係が未解決のままであるため、Terraformはタスクを実行できません。 Terraformは、制約を満たす許容可能なバージョンを識別すると、利用可能な最新のバージョンを使用します。

このセクションでは、バージョンの制約を指定することにより、プロジェクトにインストールできるモジュールとリソースのバージョンの範囲をロックする方法について学習しました。 これは、サードパーティのコードのテストおよび承認されたバージョンのみを使用して安定性が必要な場合に役立ちます。 次のセクションでは、より詳細なログを表示するようにTerraformを構成します。これは、バグレポートとクラッシュの場合のさらなるデバッグに必要です。

デバッグモードの有効化

ワークフロー内にバグまたは不正な形式の入力がある可能性があり、その結果、リソースが意図したとおりにプロビジョニングされない可能性があります。 このようなまれなケースでは、Terraformが実行していることを説明する詳細なログにアクセスする方法を知ることが重要です。 エラーの原因を特定したり、ユーザーが作成したものかどうかを通知したり、内部のバグである場合はTerraform開発者に問題を報告するように求めたりする場合があります。

Terraformは、ログの詳細度のレベルを設定するためのTF_LOG環境変数を公開します。 5つのレベルがあります:

  • TRACE:Terraformが実行するすべてのステップを示し、内部ログを使用して膨大な出力を生成するため、最も複雑な冗長性。
  • DEBUGTRACEと比較してより簡潔な方法で内部的に何が起こるかを説明します。
  • ERROR:Terraformの続行を妨げるエラーを表示します。
  • WARN:警告をログに記録します。これは、構成の誤りや間違いを示している可能性がありますが、実行には重要ではありません。
  • INFO:実行プロセスに関する一般的な高レベルのメッセージを表示します。

目的のログレベルを指定するには、環境変数を適切な値に設定する必要があります。

  1. export TF_LOG=log_level

TF_LOGが定義されているが、値がリストされている5つの詳細レベルのいずれでもない場合、TerraformはデフォルトでTRACEになります。

次に、Dropletリソースを定義し、さまざまなログレベルでデプロイしてみます。 ドロップレット定義をdroplets.tfという名前のファイルに保存するので、作成して開いて編集します。

  1. nano droplets.tf

次の行を追加します。

terraform-troubleshooting / droplets.tf
resource "digitalocean_droplet" "test-droplet" {
  image  = "ubuntu-18-04-x64"
  name   = "test-droplet"
  region = "fra1"
  size   = "s-1vcpu-1gb"
}

このドロップレットは、fra1リージョンに1つのCPUコアと1GBのRAMを搭載したUbuntu18.04を実行します。 あなたはそれをtest-dropletと呼ぶでしょう。 定義する必要があるのはこれだけなので、ファイルを保存して閉じます。

ドロップレットをデプロイする前に、以下を実行してログレベルをDEBUGに設定します。

  1. export TF_LOG=DEBUG

次に、ドロップレットのプロビジョニングを計画します。

  1. terraform plan -var "do_token=${DO_PAT}"

出力は非常に長くなります。さらに詳しく調べると、各行が二重括弧内の冗長性(重要度)のレベルで始まっていることがわかります。 ほとんどの行が[DEBUG]で始まることがわかります。

[WARN]および[INFO]も存在します。 これは、TF_LOGが最低のログレベルを設定するためです。 つまり、TRACEと他のすべてのログレベルを同時に表示するには、TF_LOGTRACEに設定する必要があります。

内部エラーが発生した場合、Terraformはスタックトレースを表示して終了し、実行を停止します。 そこから、ソースコード内のどこでエラーが発生したかを特定し、バグである場合はTerraform開発者に報告することができます。 それ以外の場合、コードにエラーがあると、Terraformがそれを指摘するので、プロジェクトで修正できます。

DigitalOceanバックエンドがAPIトークンを検証できない場合のログ出力は次のようになります。 入力が正しくないため、ユーザーエラーがスローされます。

Output
... digitalocean_droplet.test-droplet: Creating... 2021/01/20 06:54:35 [ERROR] eval: *terraform.EvalApplyPost, err: Error creating droplet: POST https://api.digitalocean.com/v2/droplets: 401 Unable to authenticate you 2021/01/20 06:54:35 [ERROR] eval: *terraform.EvalSequence, err: Error creating droplet: POST https://api.digitalocean.com/v2/droplets: 401 Unable to authenticate you Error: Error creating droplet: POST https://api.digitalocean.com/v2/droplets: 401 Unable to authenticate you on droplets.tf line 1, in resource "digitalocean_droplet" "test-droplet": 1: resource "digitalocean_droplet" "test-droplet" { ...

デバッグモードを無効にし、ログの詳細度をデフォルトレベルにリセットするには、次のコマンドを実行してTF_LOG環境変数をクリアします。

  1. unset TF_LOG

これで、より詳細なロギングモードを有効にする方法を学びました。 これらは、クラッシュや予期しないTerraformの動作を診断するのに非常に役立ちます。 次のセクションでは、変数の検証とエッジケースの防止について確認します。

変数の検証

このセクションでは、変数のタイプと検証パラメーターに応じて、変数が常に適切で適切な値を持つようにします。

HCL(HashiCorp Configuration Language)では、変数を定義するときに、名前以外のものを指定する必要はありません。 次のように、test_ipという変数の例を宣言します。

variable "test_ip" { }

その後、コードを通じてこの値を使用し、Terraformの実行時にその値を渡すことができます。

それは機能しますが、この定義には2つの欠点があります。1つは、実行時に値を渡すことができないことです。 第二に、それはその目的に適していないかもしれないどんなタイプ(boolstringなど)でもありえます。 これを修正するには、常にデフォルト値を指定して次のように入力する必要があります。

variable "test_ip" {
  type    = string
  default = "8.8.8.8"
}

default値を設定することにより、より具体的な値が提供されなかった場合でも、変数を参照するコードが機能し続けることが保証されます。 タイプを指定すると、Terraformは変数を設定する必要のある新しい値を検証し、タイプに準拠していない場合はエラーを表示できます。 この動作の例は、stringnumberに適合させようとすることです。

検証が失敗した場合にエラーメッセージを表示できる変数の検証ルーチンを提供できます。 検証の例としては、新しい値が文字列の場合はその長さをチェックするか、構造化データの場合は正規表現と一致するものを少なくとも1つ探します。

変数に入力検証を追加するには、validationブロックを定義します。

variable "test_ip" {
  type    = string
  default = "8.8.8.8"

  validation {
    condition     = can(regex("\d{1,3}\.\d{1,3}\.\d{1,3}\.\d{1,3}", var.test_ip))
    error_message = "The provided value is not a valid IP address."
  }
}

validationでは、中括弧内に2つのパラメーターを指定できます。

  • 計算するboolを受け入れるconditionは、検証に合格したかどうかを示します。
  • 検証に合格しなかった場合のエラーメッセージを指定するerror_message

この例では、変数値でregexの一致を検索して、conditionを計算します。 それをcan関数に渡します。 can関数は、パラメーターとして渡された関数がエラーなしで実行された場合にtrueを返すため、関数が正常に完了したか、結果が返されたかを確認するのに役立ちます。

ここで使用しているregex関数は、 Reg ular Ex pression(RegEx)を受け入れ、それを特定の文字列に適用して、一致したサブ文字列を返します。 RegExは、3桁の数字の4つのペアを、それらの間のドットで区切って照合します。 正規表現の概要チュートリアルにアクセスすると、RegExの詳細を知ることができます。

これで、変数のデフォルト値を指定する方法、その型を設定する方法、および正規表現を使用して入力検証を有効にする方法を理解しました。

結論

このチュートリアルでは、デバッグモードを有効にし、ログの詳細度を適切なレベルに設定することで、Terraformのトラブルシューティングを行いました。 また、検証手順の宣言や適切なデフォルトの設定など、変数の高度な機能のいくつかについても学びました。 デフォルト値を除外することは、プロジェクトの開発においてさらに奇妙な問題を引き起こす可能性のある一般的な落とし穴です。

プロジェクトの安定性のために、サードパーティのモジュールとプロバイダーのバージョンをロックすることをお勧めします。これにより、必要に応じて安定したシステムとアップグレードパスが提供されます。

変数の入力値の検証は、regexとの一致に限定されません。 利用できるその他の組み込み関数については、公式ドキュメントにアクセスしてください。

このチュートリアルは、Terraformシリーズでインフラストラクチャを管理する方法の一部です。 このシリーズでは、Terraformの初めてのインストールから複雑なプロジェクトの管理まで、Terraformの多くのトピックを取り上げています。