Terraform変数、依存関係、および条件を使用して柔軟性を向上させる方法

提供:Dev Guides
移動先:案内検索

序章

Terraform が使用するHashicorp構成言語(HCL)は、他のプログラミング言語に存在する多くの便利な構造と機能を提供します。 インフラストラクチャコードでループを使用すると、コードの重複が大幅に減少し、読みやすさが向上するため、将来のリファクタリングが容易になり、柔軟性が向上します。 HCLは、リストやマップ(他の言語ではそれぞれ配列や辞書とも呼ばれます)などのいくつかの一般的なデータ構造や、実行パスの分岐の条件も提供します。

Terraformに固有の機能は、依存するリソースを手動で指定できることです。 コードの実行時に作成される実行グラフには、検出されたリンク(ほとんどのシナリオで正しい)がすでに含まれていますが、Terraformが検出できなかった依存関係を強制する必要がある場合があります。

この記事では、HCLが提供するデータ構造、リソースのループ機能(countキー、for_each、およびfor)、既知および不明な値、およびリソース間の依存関係。

前提条件

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

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


HCLのデータ型

コードをより柔軟にするHCLのループやその他の機能について学ぶ前に、まず利用可能なデータ型とその使用法について説明します。

Hashicorp構成言語は、プリミティブおよびコンプレックスデータ型をサポートします。 プリミティブデータ型は、文字列、数値、およびブール値です。これらは、他のデータ型から派生できない基本的な型です。 一方、複合型は、複数の値を1つにグループ化します。 複雑な値の2つのタイプは、構造タイプとコレクションタイプです。

構造タイプを使用すると、さまざまなタイプの値をグループ化できます。 主な例は、インフラストラクチャがどのようになるかを指定するために使用するリソース定義です。 構造タイプと比較すると、コレクションタイプも値をグループ化しますが、同じタイプのもののみです。 私たちが関心を持っているHCLで利用可能な3つのコレクションタイプは、リスト、マップ、およびセットです。

リスト

リストは他のプログラミング言語の配列に似ています。 それらには、同じタイプの既知の数の要素が含まれており、0から始まる整数インデックスによる配列表記([])を使用してアクセスできます。 次の手順でデプロイするドロップレットの名前を保持するリスト変数宣言の例を次に示します。

variable "droplet_names" {
  type    = list(string)
  default = ["first", "second", "third"]
}

typeの場合、要素タイプが文字列のリストであることを指定し、そのdefault値を指定しました。 HCLでは、括弧内に列挙された値はリストを示します。

マップ

マップはキーと値のペアのコレクションであり、各値はタイプstringのキーを使用してアクセスされます。 中括弧内のマップを指定するには、2つの方法があります。値を指定するためにコロン(:)または等号(=)を使用します。 どちらの場合も、値は引用符で囲む必要があります。 コロンを使用する場合は、キーも囲む必要があります。

さまざまな環境のドロップレット名を含む次のマップ定義は、等号を使用して記述されています。

variable "droplet_env_names" {
  type = map(string)

  default = {
    development = "dev-droplet"
    staging = "staging-droplet"
    production = "prod-droplet"
  }
}

キーが数字で始まる場合は、コロン構文を使用する必要があります。

variable "droplet_env_names" {
  type = map(string)

  default = {
    "1-development": "dev-droplet"
    "2-staging": "staging-droplet"
    "3-production": "prod-droplet"
  }
}

セット

セットは要素の順序付けをサポートしていません。つまり、トラバースセットが毎回同じ順序を生成することは保証されておらず、それらの要素にターゲットを絞った方法でアクセスすることはできません。 それらには、1回だけ繰り返される一意の要素が含まれており、同じ要素を複数回指定すると、それらは合体され、セットに存在するインスタンスは1つだけになります。

セットの宣言はリストの宣言に似ていますが、唯一の違いは変数のタイプです。

variable "droplet_names" {
  type    = set(string)
  default = ["first", "second", "third", "fourth"]
}

HCLが提供するデータ構造のタイプについて学習し、このチュートリアル全体で使用するリスト、マップ、およびセットの構文を確認したので、次に、複数のインスタンスをデプロイするいくつかの柔軟な方法を試してみましょう。 Terraformの同じリソース。

countキーを使用したリソース数の設定

このセクションでは、countキーを使用して同じリソースの複数のインスタンスを作成します。 countキーは、作成するインスタンスの数を指定する、すべてのリソースで使用可能なパラメーターです。

前提条件の一部として作成したプロジェクトディレクトリのdroplets.tfという名前のファイルに保存する、Dropletリソースを作成することでどのように機能するかを確認できます。 次のコマンドを実行して、編集用に作成して開きます。

nano droplets.tf

次の行を追加します。

terraform-flexibility / droplets.tf

resource "digitalocean_droplet" "test_droplet" {
  count  = 3
  image  = "ubuntu-20-04-x64"
  name   = "web"
  region = "fra1"
  size   = "s-1vcpu-1gb"
}

このコードは、test_dropletと呼ばれるDropletリソースを定義し、1GBのRAMとCPUコアを備えたUbuntu20.04を実行します。

countの値が3に設定されていることに注意してください。これは、Terraformが同じリソースの3つのインスタンスを作成しようとすることを意味します。 完了したら、ファイルを保存して閉じます。

プロジェクトを計画して、Terraformが実行するアクションを確認できます。

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

出力は次のようになります。

Output...
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated
with the following symbols:
  + create

Terraform will perform the following actions:

  # digitalocean_droplet.test_droplet[0] will be created
  + resource "digitalocean_droplet" "test_droplet" {
        ...
        name                 = "web"
        ...
    }

  # digitalocean_droplet.test_droplet[1] will be created
  + resource "digitalocean_droplet" "test_droplet" {
        ...
        name                 = "web"
        ...
    }

  # digitalocean_droplet.test_droplet[2] will be created
  + resource "digitalocean_droplet" "test_droplet" {
        ...
        name                 = "web"
        ...
    }

Plan: 3 to add, 0 to change, 0 to destroy.
...

Terraformがtest_dropletの3つのインスタンスを作成し、すべて同じ名前webであるという出力の詳細。 可能ではありますが、好ましくないので、Droplet定義を変更して、各インスタンスの名前を一意にします。 droplets.tfを開いて編集します。

nano droplets.tf

強調表示された行を変更します。

terraform-flexibility / droplets.tf

resource "digitalocean_droplet" "test_droplet" {
  count  = 3
  image  = "ubuntu-20-04-x64"
  name   = "web.${count.index}"
  region = "fra1"
  size   = "s-1vcpu-1gb"
}

ファイルを保存して閉じます。

countオブジェクトは、indexパラメーターを提供します。このパラメーターには、0から始まる現在の反復のインデックスが含まれています。 現在のインデックスは、文字列補間を使用してドロップレットの名前に置き換えられます。これにより、変数を置き換えることで文字列を動的に作成できます。 プロジェクトを再度計画して、変更を確認できます。

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

出力は次のようになります。

Output...
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated
with the following symbols:
  + create

Terraform will perform the following actions:

  # digitalocean_droplet.test_droplet[0] will be created
  + resource "digitalocean_droplet" "test_droplet" {
        ...
        name                 = "web.0"
        ...
    }

  # digitalocean_droplet.test_droplet[1] will be created
  + resource "digitalocean_droplet" "test_droplet" {
        ...
        name                 = "web.1"
        ...
    }

  # digitalocean_droplet.test_droplet[2] will be created
  + resource "digitalocean_droplet" "test_droplet" {
        ...
        name                 = "web.2"
        ...
    }

Plan: 3 to add, 0 to change, 0 to destroy.
...

今回は、test_dropletの3つのインスタンスの名前にインデックスが含まれるため、追跡が容易になります。

これで、countキーを使用してリソースの複数のインスタンスを作成する方法と、プロビジョニング中にインスタンスのインデックスをフェッチして使用する方法をマスターしました。 次に、リストからドロップレットの名前を取得する方法を学習します。

リストからの液滴名の取得

同じリソースの複数のインスタンスにカスタム名を付ける必要がある場合は、定義したリスト変数からそれらを動的に取得できます。 チュートリアルの残りの部分では、名前のリストからDropletの展開を自動化し、柔軟性と使いやすさを促進するいくつかの方法を説明します。

最初に、ドロップレット名を含むリストを定義する必要があります。 variables.tfというファイルを作成し、編集用に開きます。

nano variables.tf

次の行を追加します。

terraform-flexibility / variables.tf

variable "droplet_names" {
  type    = list(string)
  default = ["first", "second", "third", "fourth"]
}

ファイルを保存して閉じます。 このコードは、文字列firstsecondthird、およびfourthを含むdroplet_namesというリストを定義します。

droplets.tfを開いて編集します。

nano droplets.tf

強調表示された行を変更します。

terraform-flexibility / droplets.tf

resource "digitalocean_droplet" "test_droplet" {
  count  = length(var.droplet_names)
  image  = "ubuntu-20-04-x64"
  name   =  var.droplet_names[count.index]
  region = "fra1"
  size   = "s-1vcpu-1gb"
}

柔軟性を向上させるために、一定数の要素を手動で指定する代わりに、droplet_namesリストの長さをcountパラメーターに渡します。これにより、常にリスト内の要素の数が返されます。 名前には、配列ブラケット表記を使用して、count.indexにあるリストの要素をフェッチします。 完了したら、ファイルを保存して閉じます。

プロジェクトの計画を再試行してください。 次のような出力が表示されます。

Output...
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated
with the following symbols:
  + create

Terraform will perform the following actions:

  # digitalocean_droplet.test_droplet[0] will be created
  + resource "digitalocean_droplet" "test_droplet" {
        ...
      + name                 = "first"
        ...
    }

  # digitalocean_droplet.test_droplet[1] will be created
  + resource "digitalocean_droplet" "test_droplet" {
        ...
      + name                 = "second"
        ...
    }

  # digitalocean_droplet.test_droplet[2] will be created
  + resource "digitalocean_droplet" "test_droplet" {
        ...
      + name                 = "third"
        ...
    }

  # digitalocean_droplet.test_droplet[3] will be created
  + resource "digitalocean_droplet" "test_droplet" {
      ...
      + name                 = "fourth"
      ...

Plan: 4 to add, 0 to change, 0 to destroy.
...

これらの変更の結果として、4つのドロップレットが展開され、droplet_namesリストの要素にちなんで名前が付けられます。

count、その機能と構文について学び、リストと一緒に使用してリソースインスタンスを変更しました。 これで、その欠点と、それらを克服する方法がわかります。

countのデメリットを理解する

countの使用方法がわかったので、使用するリストを変更するときの欠点を調べてみましょう。

ドロップレットをクラウドにデプロイしてみましょう。

terraform apply -var "do_token=${DO_PAT}"

プロンプトが表示されたら、yesと入力します。 出力の終わりは次のようになります。

OutputApply complete! Resources: 4 added, 0 changed, 0 destroyed.

次に、droplet_namesリストを拡大して、もう1つのDropletインスタンスを作成しましょう。 variables.tfを開いて編集します。

nano variables.tf

リストの先頭に新しい要素を追加します。

terraform-flexibility / variables.tf

variable "droplet_names" {
  type    = list(string)
  default = ["zero", "first", "second", "third", "fourth"]
}

完了したら、ファイルを保存して閉じます。

プロジェクトを計画します。

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

次のような出力が表示されます。

Output...
Terraform used the selected providers to generate the following execution plan. Resource actions are indicated
with the following symbols:
  + create
  ~ update in-place

Terraform will perform the following actions:

  # digitalocean_droplet.test_droplet[0] will be updated in-place
  ~ resource "digitalocean_droplet" "test_droplet" {
      ...
      ~ name               = "first" -> "zero"
      ...
    }

  # digitalocean_droplet.test_droplet[1] will be updated in-place
  ~ resource "digitalocean_droplet" "test_droplet" {
      ...
      ~ name               = "second" -> "first"
      ...
    }

  # digitalocean_droplet.test_droplet[2] will be updated in-place
  ~ resource "digitalocean_droplet" "test_droplet" {
      ...
      ~ name               = "third" -> "second"
      ...
    }

  # digitalocean_droplet.test_droplet[3] will be updated in-place
  ~ resource "digitalocean_droplet" "test_droplet" {
      ...
      ~ name               = "fourth" -> "third"
      ...
    }

  # digitalocean_droplet.test_droplet[4] will be created
  + resource "digitalocean_droplet" "test_droplet" {
      ...
      + name                 = "fourth"
      ...
    }

Plan: 1 to add, 4 to change, 0 to destroy.
...

出力は、Terraformが最初の4つのドロップレットの名前を変更し、fourthという5番目のドロップレットを作成することを示しています。これは、インスタンスを順序付きリストと見なし、リスト内のインデックス番号で要素(ドロップレット)を識別するためです。 これは、Terraformが最初に4つのドロップレットを考慮する方法です。

インデックス番号 0 1 2 3
液滴名 最初 2番目 第3 第4

新しいドロップレットzeroが最初に追加されると、その内部リスト表現は次のようになります。

インデックス番号 0 1 2 3 4
液滴名 最初 2番目 第3 第4

これで、最初の4つのドロップレットが1つ右にシフトされます。 次に、Terraformは、テーブルに表されている2つの状態を比較します。位置0で、ドロップレットは first と呼ばれ、2番目のテーブルとは異なるため、更新アクションを計画します。 これは、最初のテーブルに同等の要素がない位置4まで続き、代わりにドロップレットプロビジョニングアクションが計画されます。

これは、リストの最後以外の場所に新しい要素を追加すると、必要のないときにリソースが変更されることを意味します。 droplet_namesリストの要素が削除された場合、同様の更新アクションが計画されます。

不完全なリソース追跡は、同じリソースの異なるインスタンスの動的な数を展開するためにcountを使用することの主な欠点です。 一定数の定数インスタンスの場合、countはうまく機能する単純なソリューションです。 ただし、このような状況では、一部の属性が変数から取得される場合は、このチュートリアルの後半で学習するfor_eachループの方がはるかに適しています。

現在のリソースの参照(self

countのもう1つの欠点は、リソースの任意のインスタンスをそのインデックスで参照できない場合があることです。

主な例は、破棄時間プロビジョナーです。これは、リソースが破棄される予定のときに実行されます。 その理由は、要求されたインスタンスが存在しない(すでに破棄されている)か、相互依存サイクルを作成する可能性があるためです。 このような状況では、インスタンスのリストからオブジェクトを参照する代わりに、selfキーワードから現在のリソースにのみアクセスできます。

その使用法を示すために、test_droplet定義にdestroy-timeローカルプロビジョナーを追加します。これにより、実行時にメッセージが表示されます。 droplets.tfを開いて編集します。

nano droplets.tf

次の強調表示された行を追加します。

terraform-flexibility / droplets.tf

resource "digitalocean_droplet" "test_droplet" {
  count  = length(var.droplet_names)
  image  = "ubuntu-20-04-x64"
  name   =  var.droplet_names[count.index]
  region = "fra1"
  size   = "s-1vcpu-1gb"

  provisioner "local-exec" {
    when    = destroy
    command = "echo 'Droplet ${self.name} is being destroyed!'"
  }
}

ファイルを保存して閉じます。

local-execプロビジョナーは、Terraformが実行されているローカルマシンでコマンドを実行します。 whenパラメーターはdestroyに設定されているため、リソースが破棄される場合にのみ実行されます。 実行するコマンドは、文字列をstdoutにエコーします。これにより、self.nameを使用して現在のリソースの名前が置き換えられます。

次のセクションでは別の方法でドロップレットを作成するため、次のコマンドを実行して、現在展開されているドロップレットを破棄します。

terraform destroy -var "do_token=${DO_PAT}"

プロンプトが表示されたら、yesと入力します。 local-execプロビジョナーが4回実行されます。

Output...
digitalocean_droplet.test_droplet[0] (local-exec): Executing: ["/bin/sh" "-c" "echo 'Droplet first is being destroyed!'"]
digitalocean_droplet.test_droplet[1] (local-exec): Executing: ["/bin/sh" "-c" "echo 'Droplet second is being destroyed!'"]
digitalocean_droplet.test_droplet[1] (local-exec): Droplet second is being destroyed!
digitalocean_droplet.test_droplet[2] (local-exec): Executing: ["/bin/sh" "-c" "echo 'Droplet third is being destroyed!'"]
digitalocean_droplet.test_droplet[2] (local-exec): Droplet third is being destroyed!
digitalocean_droplet.test_droplet[3] (local-exec): Executing: ["/bin/sh" "-c" "echo 'Droplet fourth is being destroyed!'"]
digitalocean_droplet.test_droplet[3] (local-exec): Droplet fourth is being destroyed!
digitalocean_droplet.test_droplet[0] (local-exec): Droplet first is being destroyed!
...

このステップでは、countの欠点を学びました。 ここで、for_eachループ構造について学習します。これは、それらを克服し、より幅広い変数型の配列で機能します。

for_eachを使用したループ

このセクションでは、for_eachループ、その構文、および複数のインスタンスでリソースを定義する際の柔軟性にどのように役立つかを検討します。

for_eachは各リソースで使用可能なパラメーターですが、作成に多数のインスタンスを必要とするcountとは異なり、for_eachはマップまたはセットを受け入れます。 提供されたコレクションの各要素は1回トラバースされ、そのためのインスタンスが作成されます。 for_eachは、eachキーワードで属性としてキーと値を使用できるようにします(ペアのキーと値はそれぞれeach.keyeach.value)。 セットが提供される場合、キーと値は同じになります。

eachオブジェクトの現在の要素を提供するため、リストの場合のように目的の要素に手動でアクセスする必要はありません。 セットの場合、内部で観察可能な順序がないため、それは不可能です。 リストを渡すこともできますが、最初にtoset関数を使用してリストをセットに変換する必要があります。

for_eachを使用する主な利点は、3つのコレクションデータ型すべてを列挙できることを除けば、影響を受ける要素のみが変更、作成、または削除されることです。 入力内の要素の順序を変更した場合、アクションは計画されません。入力から要素を追加、削除、または変更した場合、適切なアクションはその要素に対してのみ計画されます。

Dropletリソースをcountからfor_eachに変換して、実際にどのように機能するかを見てみましょう。 droplets.tfを開いて、次のコマンドを実行して編集します。

nano droplets.tf

強調表示された行を変更します。

terraform-flexibility / droplets.tf

resource "digitalocean_droplet" "test_droplet" {
  for_each = toset(var.droplet_names)
  image    = "ubuntu-20-04-x64"
  name     = each.value
  region   = "fra1"
  size     = "s-1vcpu-1gb"
}

local-execプロビジョナーを削除できます。 完了したら、ファイルを保存して閉じます。

最初の行はcountを置き換え、for_eachを呼び出し、toset関数を使用して、セットの形式でdroplet_namesリストを渡します。これにより、指定されたものが自動的に変換されます。入力。 ドロップレット名には、each.valueを指定します。これは、ドロップレット名のセットからの現在の要素の値を保持します。

次のコマンドを実行してプロジェクトを計画します。

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

出力には、Terraformが実行する手順の詳細が示されます。

Output...

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated
with the following symbols:
  + create

Terraform will perform the following actions:

  # digitalocean_droplet.test_droplet["first"] will be created
  + resource "digitalocean_droplet" "test_droplet" {
      ...
      + name                 = "first"
      ...
    }

  # digitalocean_droplet.test_droplet["fourth"] will be created
  + resource "digitalocean_droplet" "test_droplet" {
      ...
      + name                 = "fourth"
      ...
    }

  # digitalocean_droplet.test_droplet["second"] will be created
  + resource "digitalocean_droplet" "test_droplet" {
      ...
      + name                 = "second"
      ...
    }

  # digitalocean_droplet.test_droplet["third"] will be created
  + resource "digitalocean_droplet" "test_droplet" {
      ...
      + name                 = "third"
      ...
    }

  # digitalocean_droplet.test_droplet["zero"] will be created
  + resource "digitalocean_droplet" "test_droplet" {
      ...
      + name                 = "zero"
      ...
    }

Plan: 5 to add, 0 to change, 0 to destroy.
...

countを使用するのとは対照的に、Terraformは、順序付きリストの要素としてではなく、各インスタンスを個別に考慮するようになりました。 各インスタンスは、作成される各リソースの横の括弧内に示されている文字列要素によって示されるように、指定されたセットの要素にリンクされています。

次のコマンドを実行して、プランをクラウドに適用します。

terraform apply -var "do_token=${DO_PAT}"

プロンプトが表示されたら、yesと入力します。 終了したら、droplet_namesリストから1つの要素を削除して、他のインスタンスが影響を受けないことを示します。 variables.tfを開いて編集します。

nano variables.tf

リストを次のように変更します。

terraform-flexibility / variables.tf

variable "droplet_names" {
  type    = list(string)
  default = ["first", "second", "third", "fourth"]
}

ファイルを保存して閉じます。

プロジェクトを再度計画すると、次の出力が表示されます。

Output...

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated
with the following symbols:
  - destroy

Terraform will perform the following actions:

  # digitalocean_droplet.test_droplet["zero"] will be destroyed
  - resource "digitalocean_droplet" "test_droplet" {
      ...
      - name               = "zero" -> null
      ...
    }

Plan: 0 to add, 0 to change, 1 to destroy.
...

今回は、Terraformは削除されたインスタンス(zero)のみを破棄し、他のインスタンスには触れません。これは正しい動作です。

このステップでは、for_each、その使用方法、およびcountに対するその利点について学習しました。 次に、forループ、その構文と使用法、および特定のタスクを自動化するために使用できる場合について学習します。

forを使用したループ

forループはコレクションで機能し、入力の各要素に変換を適用することで新しいコレクションを作成します。 出力の正確なタイプは、ループが角かっこ([])で囲まれているか、中かっこ({})で囲まれているかによって異なり、それぞれリストまたはマップを提供します。 そのため、リソースのクエリや、後の処理のための構造化された出力の形成に適しています。

forループの一般的な構文は次のとおりです。

for element in collection:
transform(element)
if condition

他のプログラミング言語と同様に、最初にトラバーサル変数(element)に名前を付け、collectionを指定して列挙します。 ループの本体は変換ステップであり、オプションのif句を使用して入力コレクションをフィルタリングできます。

次に、出力を使用していくつかの例を実行します。 それらをoutputs.tfという名前のファイルに保存します。 次のコマンドを実行して、編集用に作成します。

nano outputs.tf

デプロイされたドロップレット名とそのIPアドレスのペアを出力するには、次の行を追加します。

terraform-flexibility / outputs.tf

output "ip_addresses" {
  value = {
    for instance in digitalocean_droplet.test_droplet:
    instance.name => instance.ipv4_address
  }
}

このコードは、ip_addressesという出力を指定し、前の手順でカスタマイズしたtest_dropletリソースのインスタンスを反復処理するforループを指定します。 ループは中括弧で囲まれているため、出力はマップになります。 マップの変換手順は、他のプログラミング言語のラムダ関数に似ており、ここでは、キーとしてのインスタンス名とその値としてのプライベートIPを組み合わせて、キーと値のペアを作成します。

ファイルを保存して閉じてから、Terraformの状態を更新して、次のコマンドを実行して新しい出力を考慮します。

terraform refresh -var "do_token=${DO_PAT}"

Terraform refreshコマンドは、ローカル状態をクラウド内の実際のインフラストラクチャ状態で更新します。

次に、出力の内容を確認します。

Outputip_addresses = {
  "first" = "ip_address"
  "fourth" = "ip_address"
  "second" = "ip_address"
  "third" = "ip_address"
}

Terraformは、[X90X]ループによって作成されたマップであるip_addresses出力の内容を示しています。 (エントリの順序は異なる場合があります。)ループはエントリの数ごとにシームレスに機能します。つまり、droplet_namesリストに新しい要素を追加し、作成される新しいドロップレットを追加できます。さらに手動で入力しなくても、この出力に自動的に表示されます。

forループを角かっこで囲むことにより、出力をリストにすることができます。 たとえば、Droplet IPアドレスのみを出力できます。これは、データを解析している可能性のある外部ソフトウェアに役立ちます。 コードは次のようになります。

terraform-flexibility / outputs.tf

output "ip_addresses" {
  value = [
    for instance in digitalocean_droplet.test_droplet:
    instance.ipv4_address
  ]
}

ここで、変換ステップはIPアドレス属性を選択します。 次の出力が得られます。

Outputip_addresses = [
  "ip_address",
  "ip_address",
  "ip_address",
  "ip_address",
]

前述のように、if句を使用して入力コレクションをフィルタリングすることもできます。 fra1領域でフィルタリングするループを作成する方法は次のとおりです。

terraform-flexibility / outputs.tf

output "ip_addresses" {
  value = [
    for instance in digitalocean_droplet.test_droplet:
    instance.ipv4_address
    if instance.region == "fra1"
  ]
}

HCLでは、==演算子は、両側の値が等しいかどうかをチェックします。ここでは、instance.regionfra1と等しいかどうかをチェックします。 そうである場合、チェックに合格し、instanceが変換されて出力に追加されます。そうでない場合、スキップされます。 test_dropletリソース定義によれば、すべてのDropletインスタンスがfra1領域にあるため、このコードの出力は前の例と同じになります。 if条件は、ドロップレットのサイズや分布など、プロジェクト内の他の値の入力コレクションをフィルタリングする場合にも役立ちます。

次のセクションでは別の方法でリソースを作成するため、次のコマンドを実行して、現在デプロイされているリソースを破棄します。

terraform destroy -var "do_token=${DO_PAT}"

プロセスを終了するように求められたら、yesと入力します。

forループ、その構文、および出力での使用例について説明しました。 ここで、条件文と、それらをcountと一緒に使用する方法について学習します。

ディレクティブと条件

前のセクションの1つで、countキーとその機能について説明しました。 ここでは、Terraformコードの他の場所で使用できる3値条件演算子と、それらをcountで使用する方法について学習します。

三項演算子の構文は次のとおりです。

condition ? value_if_true : value_if_false

conditionは、ブール値(trueまたはfalse)に計算される式です。 条件が真の場合、式はvalue_if_trueと評価されます。 一方、条件がfalseの場合、結果はvalue_if_falseになります。

三元演算子の主な用途は、変数の内容に応じて単一のリソースの作成を有効または無効にすることです。 これは、比較結果(1または0のいずれか)を目的のリソースのcountキーに渡すことで実現できます。

三項演算子を使用してリストまたはセットから単一の要素をフェッチする場合は、one関数を使用できます。 指定されたコレクションが空の場合、nullを返します。 それ以外の場合は、コレクション内の単一の要素を返すか、複数ある場合はエラーをスローします。

ドロップレットを作成するかどうかを制御するcreate_dropletという変数を追加しましょう。 まず、variables.tfを開いて編集します。

nano variables.tf

強調表示された行を追加します。

terraform-flexibility / variables.tf

variable "droplet_names" {
  type    = list(string)
  default = ["first", "second", "third", "fourth"]
}

variable "create_droplet" {
  type = bool
  default = true
}

このコードは、タイプboolcreate_droplet変数を定義します。 ファイルを保存して閉じます。

次に、Droplet宣言を変更するには、droplets.tfを開いて、次のコマンドを実行して編集します。

nano droplets.tf

次のようにファイルを変更します。

terraform-flexibility / droplets.tf

resource "digitalocean_droplet" "test_droplet" {
  count  = var.create_droplet ? 1 : 0
  image  = "ubuntu-20-04-x64"
  name   =  "test_droplet"
  region = "fra1"
  size   = "s-1vcpu-1gb"
}

countの場合、三項演算子を使用して、create_droplet変数がtrueの場合は1を返し、falseの場合は0を返します。これにより、ドロップレットは生成されません。プロビジョニングされています。 完了したら、ファイルを保存して閉じます。

次のコマンドを実行して、変数をfalseに設定してプロジェクト実行プランを計画します。

terraform plan -var "do_token=${DO_PAT}" -var "create_droplet=false"

次の出力が表示されます。

OutputChanges to Outputs:
  + ip_addresses = {}

You can apply this plan to save these new output values to the Terraform state, without changing any real infrastructure.

create_dropletfalseの値で渡されたため、インスタンスのcount0であり、ドロップレットは作成されないため、IPはありません。出力するアドレス。

三元条件演算子をcountキーと一緒に使用して、必要なリソースをデプロイするかどうかをより高いレベルで柔軟に選択できるようにする方法を確認しました。 次に、リソースのリソース依存関係を明示的に設定する方法について学習します。

リソースの依存関係を明示的に設定する

プロジェクトの実行プランを作成する際、Terraformはリソース間の依存関係チェーンを検出し、適切な順序で構築されるように暗黙的にそれらを順序付けます。 ほとんどの場合、リソース内のすべての式をスキャンしてグラフを作成することにより、関係を検出できます。

ただし、1つのリソースをプロビジョニングするために、アクセス制御設定をクラウドプロバイダーに既にデプロイする必要がある場合、それらが関連していることをTerraformに明確に示すことはできません。 次に、Terraformは、それらが相互に動作的に依存していることを認識しません。 このような場合、依存関係はdepends_on引数を使用して手動で指定する必要があります。

depends_onキーは各リソースで使用可能であり、特定のリソース間の非表示の依存関係リンクを指定するために使用されます。 隠された依存関係は、リソースが宣言でデータを使用せずに他のリソースの動作に依存している場合に形成されます。これにより、Terraformはそれらを一方向に接続するように促されます。

コードでdepends_onを指定する方法の例を次に示します。

resource "digitalocean_droplet" "droplet" {
  image  = "ubuntu-20-04-x64"
  name   = "web"
  region = "fra1"
  size   = "s-1vcpu-1gb"

  depends_on = [
    # Resources...
  ]
}

他のリソースへの参照のリストを受け入れ、任意の式を受け入れません。

depends_onは慎重に使用し、他のすべてのオプションが使い果たされた場合にのみ使用してください。 その使用は、宣言しようとしていることがTerraformの自動依存検知システムの境界の外に出ていることを意味します。 これは、リソースが必要以上のリソースに明示的に依存していることを示している場合があります。

これで、depends_onキーを使用してリソースに追加の依存関係を明示的に設定する方法と、それをいつ使用する必要があるかについて学習しました。

結論

この記事では、デプロイするリソースインスタンスの数を指定するためのcountや、高度なものとしてのfor_eachなど、コードの柔軟性とスケーラビリティを向上させるHCLの機能について説明しました。コレクションのデータ型をループしてインスタンスをカスタマイズする方法。 正しく使用すると、コードの重複と、展開されたインフラストラクチャを管理するための運用上のオーバーヘッドが大幅に削減されます。

また、条件演算子と3項演算子、およびそれらを使用してリソースをデプロイするかどうかを制御する方法についても学習しました。 Terraformの自動依存関係分析システムは非常に優れていますが、depends_onキーを使用してリソースの依存関係を手動で指定する必要がある場合があります。

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