序章

Terraform モジュールを使用すると、インフラストラクチャの個別のリソースを単一の統合リソースにグループ化できます。 必要になるたびにリソース定義を繰り返すことなく、後でカスタマイズして再利用できます。これは、大規模で複雑な構造のプロジェクトに役立ちます。 定義した入力変数を使用してモジュールインスタンスをカスタマイズしたり、出力を使用してモジュールインスタンスから情報を抽出したりできます。 独自のカスタムモジュールを作成する以外に、 TerraformRegistryで公開されている既成のモジュールを使用することもできます。 開発者は、作成したモジュールなどの入力を使用してそれらを使用およびカスタマイズできますが、ソースコードはクラウドに保存され、クラウドからプルされます。

このチュートリアルでは、冗長性のためにロードバランサーの背後に複数のドロップレットを設定するTerraformモジュールを作成します。 また、 for_eachcount Hashicorp構成言語(HCL)のループ機能により、モジュールの複数のカスタマイズされたインスタンスを同時にデプロイします。

前提条件

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

モジュールの構造と利点

このセクションでは、モジュールがもたらすメリット、プロジェクト内の通常の場所、およびモジュールの構造化方法について学習します。

カスタムTerraformモジュールは、大規模なプロジェクトで頻繁に一緒に使用および展開される接続コンポーネントをカプセル化するために作成されます。 それらは自己完結型であり、必要なリソース、変数、およびプロバイダーのみをバンドルします。

モジュールは通常、プロジェクトのルートにある中央フォルダーに格納され、それぞれがその下のそれぞれのサブフォルダーに格納されます。 モジュール間の明確な分離を維持するために、常に単一の目的を持つようにモジュールを設計し、サブモジュールが含まれないようにしてください。

頻繁にカスタマイズしないでモジュールを繰り返す場合は、リソーススキームからモジュールを作成すると便利です。 単一のリソースをモジュールとしてパッケージ化することは不要であり、アーキテクチャ全体の単純さを徐々に取り除きます。

小規模な開発およびテストプロジェクトの場合、モジュールを組み込む必要はありません。これらの場合、モジュールはあまり改善されないためです。 モジュールはカスタマイズ機能を備えているため、複雑に構造化されたプロジェクトの構成要素です。 コードの重複を回避することには大きな利点があるため、開発者は大規模なプロジェクトにモジュールを使用します。 モジュールには、定義を1か所で変更するだけで済み、それがインフラストラクチャの残りの部分に伝播されるという利点もあります。

次に、Terraformプロジェクトでモジュールを定義、使用、およびカスタマイズします。

モジュールの作成

このセクションでは、複数のドロップレットとロードバランサーをTerraformリソースとして定義し、それらをモジュールにパッケージ化します。 また、モジュール入力を使用して、結果のモジュールをカスタマイズ可能にします。

モジュールをという名前のディレクトリに保存します droplet-lb、というディレクトリの下 modules. あなたがにいると仮定して terraform-modules 前提条件の一部として作成したディレクトリ。次のコマンドを実行して、両方を同時に作成します。

  1. mkdir -p modules/droplet-lb

The -p 引数は指示します mkdir 指定されたパスにすべてのディレクトリを作成します。

そこに移動します:

  1. cd modules/droplet-lb

前のセクションで説明したように、モジュールには、使用するリソースと変数が含まれています。 Terraformから開始 0.13、使用するプロバイダーの定義も含める必要があります。 Terraformは、プロジェクトのルートディレクトリも含め、HCLコードを含むすべてのディレクトリをモジュールと見なすため、モジュールは、コードがモジュールを表すことに注意するための特別な構成を必要としません。

モジュールで定義された変数はその入力として公開され、リソース定義で使用してカスタマイズできます。 作成するモジュールには、作成するドロップレットの数とそのグループの名前の2つの入力があります。 と呼ばれるファイルを作成して編集用に開きます variables.tf 変数を格納する場所:

  1. nano variables.tf

次の行を追加します。

modules / droplet-lb / variables.tf
variable "droplet_count" {}
variable "group_name" {}

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

ドロップレット定義をという名前のファイルに保存します droplets.tf. 編集のために作成して開きます。

  1. nano droplets.tf

次の行を追加します。

modules / droplet-lb / droplets.tf
resource "digitalocean_droplet" "droplets" {
  count  = var.droplet_count
  image  = "ubuntu-20-04-x64"
  name   = "${var.group_name}-${count.index}"
  region = "fra1"
  size   = "s-1vcpu-1gb"
}

のために count 作成するリソースのインスタンスの数を指定するパラメーター。 droplet_count 変数。 その値は、モジュールがメインプロジェクトコードから呼び出されるときに指定されます。 デプロイされた各ドロップレットの名前は異なります。これは、現在のドロップレットのインデックスを指定されたグループ名に追加することで実現できます。 ドロップレットの展開は、 fra1 リージョンと彼らはUbuntu20.04を実行します。

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

ドロップレットが定義されたら、ロードバランサーの作成に進むことができます。 そのリソース定義を次の名前のファイルに保存します lb.tf. 次のコマンドを実行して、編集用に作成して開きます。

  1. nano lb.tf

リソース定義を追加します。

モジュール/液滴-lb/lb.tf
resource "digitalocean_loadbalancer" "www-lb" {
  name   = "lb-${var.group_name}"
  region = "fra1"

  forwarding_rule {
    entry_port     = 80
    entry_protocol = "http"

    target_port     = 80
    target_protocol = "http"
  }

  healthcheck {
    port     = 22
    protocol = "tcp"
  }

  droplet_ids = [
    for droplet in digitalocean_droplet.droplets:
      droplet.id
  ]
}

区別できるようにするために、名前にグループ名が含まれるロードバランサーを定義します。 にデプロイします fra1 ドロップレットと一緒に地域。 次の2つのセクションでは、ターゲットと監視ポートおよびプロトコルを指定します。

強調表示 droplet_ids ブロックはドロップレットのIDを取り込みます。これは、ロードバランサーによって管理される必要があります。 複数の液滴があり、それらの数が事前にわからないため、 for ドロップレットのコレクションをトラバースするためのループ(digitalocean_droplet.droplets)そして彼らのIDを取ります。 あなたは for ブラケット付きループ([])結果のコレクションがリストになるようにします。

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

これで、モジュールのドロップレット、ロードバランサー、および変数が定義されました。 プロバイダー要件を定義し、モジュールが使用するプロバイダー(バージョンや場所など)を指定する必要があります。 テラフォーム以来 0.13、モジュールは、使用するHashicorpが管理していないプロバイダーのソースを明示的に定義する必要があります。 これは、親プロジェクトから継承しないためです。

プロバイダー要件を次の名前のファイルに保存します provider.tf. 次のコマンドを実行して、編集用に作成します。

  1. nano provider.tf

次の行を追加して、 digitalocean プロバイダー:

modules / droplet-lb / Provider.tf
terraform {
  required_providers {
    digitalocean = {
      source = "digitalocean/digitalocean"
      version = "~> 2.0"
    }
  }
}

完了したら、ファイルを保存して閉じます。 The droplet-lb モジュールには、 digitalocean プロバイダー。

モジュールは、リソースの状態に関する内部情報を抽出するために使用できる出力もサポートします。 ロードバランサーのIPアドレスを公開する出力を定義し、それを次の名前のファイルに保存します。 outputs.tf. 編集用に作成します。

  1. nano outputs.tf

次の定義を追加します。

modules / droplet-lb / outputs.tf
output "lb_ip" {
  value = digitalocean_loadbalancer.www-lb.ip
}

この出力は、ロードバランサーのIPアドレスを取得します。 ファイルを保存して閉じます。

The droplet-lb これでモジュールは機能的に完成し、展開の準備が整いました。 プロジェクトのルートに保存するメインコードから呼び出します。 まず、ファイルディレクトリを2回上に移動して、そこに移動します。

  1. cd ../..

次に、と呼ばれるファイルを作成して編集用に開きます main.tf、モジュールを使用します:

  1. nano main.tf

次の行を追加します。

main.tf
module "groups" {
  source = "./modules/droplet-lb"

  droplet_count = 3
  group_name    = "group1"
}

output "loadbalancer-ip" {
  value = module.groups.lb_ip
}

この宣言では、 droplet-lb として指定されたディレクトリにあるモジュール source. 提供する入力を構成します。 droplet_countgroup_name、に設定されています group1 したがって、後でインスタンスを識別できるようになります。

ロードバランサーのIP出力はモジュールで定義されているため、プロジェクトを適用するときに自動的に表示されることはありません。 これに対する解決策は、その値を取得する別の出力を作成することです(loadbalancer_ip).

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

次のコマンドを実行してモジュールを初期化します。

  1. terraform init

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

Output
Initializing modules... - groups in modules/droplet-lb Initializing the backend... Initializing provider plugins... - Finding digitalocean/digitalocean versions matching "~> 2.0"... - Installing digitalocean/digitalocean v2.19.0... - Installed digitalocean/digitalocean v2.19.0 (signed by a HashiCorp partner, key ID F82037E524B9C0E8) ... Terraform has been successfully initialized! You may now begin working with Terraform. Try running "terraform plan" to see any changes that are required for your infrastructure. All Terraform commands should now work. If you ever set or change modules or backend configuration for Terraform, rerun this command to reinitialize your working directory. If you forget, other commands will detect it and remind you to do so if necessary.

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

  1. 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: # module.groups.digitalocean_droplet.droplets[0] will be created + resource "digitalocean_droplet" "droplets" { ... + name = "group1-0" ... } # module.groups.digitalocean_droplet.droplets[1] will be created + resource "digitalocean_droplet" "droplets" { ... + name = "group1-1" ... } # module.groups.digitalocean_droplet.droplets[2] will be created + resource "digitalocean_droplet" "droplets" { ... + name = "group1-2" ... } # module.groups.digitalocean_loadbalancer.www-lb will be created + resource "digitalocean_loadbalancer" "www-lb" { ... + name = "lb-group1" ... } Plan: 4 to add, 0 to change, 0 to destroy. ...

この出力では、Terraformが3つのドロップレットを作成することを詳しく説明しています。 group1-0, group1-1、 と group1-2、およびと呼ばれるロードバランサーも作成します group1-lb、3つのドロップレットとの間のトラフィックを管理します。

次のコマンドを実行して、プロジェクトをクラウドに適用してみてください。

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

入る yes プロンプトが表示されたら。 出力にはすべてのアクションが表示され、ロードバランサーのIPアドレスも表示されます。

Output
module.groups.digitalocean_droplet.droplets[1]: Creating... module.groups.digitalocean_droplet.droplets[0]: Creating... module.groups.digitalocean_droplet.droplets[2]: Creating... ... Apply complete! Resources: 4 added, 0 changed, 0 destroyed. Outputs: loadbalancer-ip = ip_address

カスタマイズ可能な数のドロップレットとロードバランサーを含むモジュールを作成しました。これらは、着信トラフィックと発信トラフィックを管理するように自動的に構成されます。

デプロイされたリソースの名前の変更

前のセクションでは、定義して呼び出したモジュールをデプロイしました groups. 名前を変更したい場合は、モジュール呼び出しの名前を変更するだけでは、期待した結果は得られません。 呼び出しの名前を変更すると、Terraformはリソースを破棄して再作成するように促され、過度のダウンタイムが発生します。

たとえば、開く main.tf 実行による編集の場合:

  1. nano main.tf

名前を変更します groups モジュールから groups_renamed、強調表示されているように:

main.tf
module "groups_renamed" {
  source = "./modules/droplet-lb"

  droplet_count = 3
  group_name    = "group1"
}

output "loadbalancer-ip" {
  value = module.groups_renamed.lb_ip
}

ファイルを保存して閉じます。 次に、プロジェクトを再度初期化します。

  1. terraform init

これで、プロジェクトを計画できます。

  1. 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 - destroy Terraform will perform the following actions: # module.groups.digitalocean_droplet.droplets[0] will be destroyed ... # module.groups_renamed.digitalocean_droplet.droplets[0] will be created ...

Terraformは、既存のインスタンスを破棄して新しいインスタンスを作成するように求めるプロンプトを表示します。 これは破壊的で不必要であり、望ましくないダウンタイムにつながる可能性があります。

代わりに、 moved ブロックすると、古いリソースを新しい名前で移動するようにTerraformに指示できます。 開ける main.tf 編集して、ファイルの最後に次の行を追加します。

moved {
  from = module.groups
  to   = module.groups_renamed
}

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

これで、プロジェクトを計画できます。

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

あなたがで計画するとき moved に存在するブロック main.tf、Terraformは、リソースを再作成するのではなく、リソースを移動したいと考えています。

Output
Terraform will perform the following actions: # module.groups.digitalocean_droplet.droplets[0] has moved to module.groups_renamed.digitalocean_droplet.droplets[0] ... # module.groups.digitalocean_droplet.droplets[1] has moved to module.groups_renamed.digitalocean_droplet.droplets[1] ...

リソースを移動すると、Terraform状態での場所が変わります。つまり、実際のクラウドリソースが変更、破棄、または再作成されることはありません。

次の手順で構成を大幅に変更するため、次のコマンドを実行して、デプロイされたリソースを破棄します。

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

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

Output
... Destroy complete! Resources: 4 destroyed.

このセクションでは、プロセスでリソースを破棄せずに、Terraformプロジェクトのリソースの名前を変更しました。 次に、を使用して同じコードからモジュールの複数のインスタンスをデプロイします for_eachcount.

複数のモジュールインスタンスの展開

このセクションでは、 countfor_each を展開するには droplet-lb カスタマイズを使用してモジュールを複数回。

使用する count

同じモジュールの複数のインスタンスを一度にデプロイする1つの方法は、その数をに渡すことです。 count パラメータ。すべてのモジュールで自動的に使用できます。 開ける main.tf 編集用:

  1. nano main.tf

このように変更して、既存の出力定義を削除し、 moved ブロック:

main.tf
module "groups" {
  source = "./modules/droplet-lb"

  count  = 3

  droplet_count = 3
  group_name    = "group1-${count.index}"
}

設定することにより count3、モジュールを3回デプロイするように、それぞれ異なるグループ名でTerraformに指示します。 完了したら、ファイルを保存して閉じます。

次のコマンドを実行して、展開を計画します。

  1. 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: # module.groups[0].digitalocean_droplet.droplets[0] will be created ... # module.groups[0].digitalocean_droplet.droplets[1] will be created ... # module.groups[0].digitalocean_droplet.droplets[2] will be created ... # module.groups[0].digitalocean_loadbalancer.www-lb will be created ... # module.groups[1].digitalocean_droplet.droplets[0] will be created ... # module.groups[1].digitalocean_droplet.droplets[1] will be created ... # module.groups[1].digitalocean_droplet.droplets[2] will be created ... # module.groups[1].digitalocean_loadbalancer.www-lb will be created ... # module.groups[2].digitalocean_droplet.droplets[0] will be created ... # module.groups[2].digitalocean_droplet.droplets[1] will be created ... # module.groups[2].digitalocean_droplet.droplets[2] will be created ... # module.groups[2].digitalocean_loadbalancer.www-lb will be created ... Plan: 12 to add, 0 to change, 0 to destroy. ...

3つのモジュールインスタンスのそれぞれに3つのドロップレットとロードバランサーが関連付けられているというTerraformの詳細が出力に表示されます。

使用する for_each

使用できます for_each より複雑なインスタンスのカスタマイズが必要な場合、またはインスタンスの数がコードの記述中に認識されていないサードパーティのデータ(多くの場合マップとして表示される)に依存する場合のモジュールの場合。

ここで、グループ名をドロップレットカウントにペアリングし、のインスタンスをデプロイするマップを定義します。 droplet-lb それによると。 開ける main.tf 実行による編集の場合:

  1. nano main.tf

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

main.tf
variable "group_counts" {
  type    = map
  default = {
    "group1" = 1
    "group2" = 3
  }
}

module "groups" {
  source   = "./modules/droplet-lb"
  for_each = var.group_counts

  droplet_count = each.value
  group_name    = each.key
}

最初にというマップを定義します group_counts これには、特定のグループに必要なドロップレットの数が含まれています。 次に、モジュールを呼び出します droplet-lb、ただし、 for_each ループはで動作する必要があります var.group_counts、直前に定義したマップ。 droplet_count かかります each.value、現在のペアの値。これは、現在のグループのドロップレットの数です。 group_name グループの名前を受け取ります。

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

次のコマンドを実行して、構成を適用してみてください。

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

出力には、ドロップレットとロードバランサーを使用して2つのグループを作成するために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: # module.groups["group1"].digitalocean_droplet.droplets[0] will be created ... # module.groups["group1"].digitalocean_loadbalancer.www-lb will be created ... # module.groups["group2"].digitalocean_droplet.droplets[0] will be created ... # module.groups["group2"].digitalocean_droplet.droplets[1] will be created ... # module.groups["group2"].digitalocean_droplet.droplets[2] will be created ... # module.groups["group2"].digitalocean_loadbalancer.www-lb will be created ...

このステップでは、 countfor_each 同じコードから同じモジュールの複数のカスタマイズされたインスタンスをデプロイします。

結論

このチュートリアルでは、Terraformモジュールを作成してデプロイしました。 モジュールを使用して論理的にリンクされたリソースをグループ化し、それらをカスタマイズして、中央のコード定義から複数の異なるインスタンスをデプロイしました。 また、出力を使用して、モジュールに含まれるリソースの属性を表示しました。

Terraformの詳細については、Terraformシリーズでインフラストラクチャを管理する方法をご覧ください。