28
16

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

1. はじめに

terraformのバージョン0.13が8/10にリリースされました。
普段terraformを使用しているため、今回のアップデートによりどんな機能が追加になったのか個人的に気になるところを検証してみます。
私が最近Azureを使っていることから、Azureを使用して検証します。

2. バージョンアップによって追加された新機能

新しく追加された機能は以下の5つでした。

  1. moduleブロック内でcountfor_eachが使用可能になり、複数リソースを作成可能

    https://www.terraform.io/docs/configuration/modules.html#multiple-instances-of-a-module
  2. moduleブロック内でdepends_onが使用可能になり、moduleの依存関係を定義可能

    https://www.terraform.io/docs/configuration/modules.html#other-meta-arguments
  3. variableブロック内でvalidationが可能に

    https://www.terraform.io/docs/configuration/variables.html#custom-validation-rules
  4. サードパーティプロバイダーの自動インストールが可能に

    https://www.terraform.io/docs/configuration/provider-requirements.html
  5. stateファイルの保存先をkubernetesに変更可能に

    https://www.terraform.io/docs/backends/types/kubernetes.html

1~3は今後使うことになりそうなので、試してみた結果をまとめていきます。

3, 実践

3.1. terraform アップデート

新機能を使っていくために、まずはterraformのアップデートをします。
私はhomebrewを使ってインストールしたので、以下コマンドにてterraformをアップデートしました。

$ brew upgrade terraform

次に公式サイトのUpgrading to Terraform v0.13を参考に、terraform 0.13upgradeコマンドを実行してみます。

$ terraform 0.13upgrade

This command will update the configuration files in the given directory to use
the new provider source features from Terraform v0.13. It will also highlight
any providers for which the source cannot be detected, and advise how to
proceed.

We recommend using this command in a clean version control work tree, so that
you can easily see the proposed changes as a diff against the latest commit.
If you have uncommited changes already present, we recommend aborting this
command and dealing with them before running this command again.

Would you like to upgrade the module in the current directory?
  Only 'yes' will be accepted to confirm.

  Enter a value: yes

-----------------------------------------------------------------------------

Upgrade complete!

Use your version control system to review the proposed changes, make any
necessary adjustments, and then commit.

こちらを実行するとversions.tfというファイルが実行したパス上にできていました。
中身を見るとrequired_providersブロックが追加されていました。providerの指定をこのブロックで行うよう、変更になったようです。

terraform {
  required_providers {
    azurerm = {
      source = "hashicorp/azurerm"
    }
  }
  required_version = ">= 0.13"
}

Azureプロバイダーは、v2.0.0以上からfeatureブロックが必須となっているため、以下のように追記しておきます。

terraform {
  required_providers {
    azurerm = {
      version = ">=2.0.0"
      source = "hashicorp/azurerm"
    }
  }
  required_version = ">= 0.13"
}

# 以下ブロックを追加してます
provider "azurerm" {
  features {}
}

3.2. module内のcountとfor_each

module内でcountとfor_eachを使って、リソースの複数作成を検証してみます。
Azureのリソースグループを複数作成するシナリオを想定して、ソースコードを書きます。

フォルダ構成は以下のようにしています。

terraform_test
├── development
│   ├── main.tf
│   ├── variable.tf
│   └── versions.tf
└── modules
    └── resource_group
        ├── main.tf
        ├── output.tf
        └── variable.tf

development配下のmain.tfから、modules配下のソースを参照してAzureのリソースを作成します。

modules配下のソースは以下のようになっています。

■ modules/resource_group/main.tf

resource azurerm_resource_group common_rg {
  name     = var.name
  location = var.location

  tags = {
    environment = var.environment
  }
}

■ modules/resource_group/variable.tf

variable name {
  description = "リソースグループ名"
}

variable location {
  description = "リージョン名"
}

variable environment {
  description = "環境名"
}

上記のソースを参照してリソースグループを作成していきます。
結論から言うと、countとfor_each にてリソースを作成した際の差分は、書き方に多少差があることと、module名に以下のような差分が出ています。

  • count : module.resource_group[0]...
  • for_each : module.resource_group["terraform013-test-1"]...

それでは、この結論に至るまでのプロセスを実際のソースとterraform実行結果を見ながら確認していきます。

develop配下のソースをそれぞれのパターンで書いていきます。

3.2.1. for_eachパターン

■ development/main.tf

module resource_group {
  source = "../modules/resource_group"

  for_each    = toset(var.name)
  name        = each.key
  location    = var.location 
  environment = var.environment
}

■ development/variable.tf

variable name {
  type        = list
  default     = [
      "terraform013-test-1",
      "terraform013-test-2"
    ]
  description = "description"
}

variable location {
  type        = string
  default     = "Japan East"
  description = "リージョン名"
}

variable environment {
  type        = string
  default     = "dev"
  description = "環境"
}

■ 実行結果

$ terraform apply

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # module.resource_group["terraform013-test-1"].azurerm_resource_group.common_rg will be created
  + resource "azurerm_resource_group" "common_rg" {
      + id       = (known after apply)
      + location = "japaneast"
      + name     = "terraform013-test-1"
      + tags     = {
          + "environment" = "dev"
        }
    }

  # module.resource_group["terraform013-test-2"].azurerm_resource_group.common_rg will be created
  + resource "azurerm_resource_group" "common_rg" {
      + id       = (known after apply)
      + location = "japaneast"
      + name     = "terraform013-test-2"
      + tags     = {
          + "environment" = "dev"
        }
    }

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

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

module.resource_group["terraform013-test-2"].azurerm_resource_group.common_rg: Creating...
module.resource_group["terraform013-test-1"].azurerm_resource_group.common_rg: Creating...
module.resource_group["terraform013-test-1"].azurerm_resource_group.common_rg: Creation complete after 3s [id=/subscriptions/f9d36b58-96cd-48d1-9dc8-f760b1cf174e/resourceGroups/terraform013-test-1]
module.resource_group["terraform013-test-2"].azurerm_resource_group.common_rg: Creation complete after 3s [id=/subscriptions/f9d36b58-96cd-48d1-9dc8-f760b1cf174e/resourceGroups/terraform013-test-2]

Apply complete! Resources: 2 added, 0 changed, 0 destroyed.

3.2.2. countパターン

■ development/main.tf

module resource_group {
  source = "../modules/resource_group"

  count       = length(var.name)
  name        = element(var.name, count.index)
  location    = var.location 
  environment = var.environment
}

■ development/variable.tf

variable name {
  type        = list
  default     = [
      "terraform013-test-1",
      "terraform013-test-2"
    ]
  description = "description"
}

variable location {
  type        = string
  default     = "Japan East"
  description = "リージョン名"
}

variable environment {
  type        = string
  default     = "dev"
  description = "環境"
}

■実行結果

$ terraform apply

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # module.resource_group[0].azurerm_resource_group.common_rg will be created
  + resource "azurerm_resource_group" "common_rg" {
      + id       = (known after apply)
      + location = "japaneast"
      + name     = "terraform013-test-1"
      + tags     = {
          + "environment" = "dev"
        }
    }

  # module.resource_group[1].azurerm_resource_group.common_rg will be created
  + resource "azurerm_resource_group" "common_rg" {
      + id       = (known after apply)
      + location = "japaneast"
      + name     = "terraform013-test-2"
      + tags     = {
          + "environment" = "dev"
        }
    }

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

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

module.resource_group[1].azurerm_resource_group.common_rg: Creating...
module.resource_group[0].azurerm_resource_group.common_rg: Creating...
module.resource_group[0].azurerm_resource_group.common_rg: Creation complete after 3s [id=/subscriptions/f9d36b58-96cd-48d1-9dc8-f760b1cf174e/resourceGroups/terraform013-test-1]
module.resource_group[1].azurerm_resource_group.common_rg: Creation complete after 3s [id=/subscriptions/f9d36b58-96cd-48d1-9dc8-f760b1cf174e/resourceGroups/terraform013-test-2]

Apply complete! Resources: 2 added, 0 changed, 0 destroyed.

上記のように、countとfor_eachで2つのリソースグループが作成できました。

2つの差分を見てみると、書き方に多少差があることと、module名に以下のような差分が出ています。

  • count : module.resource_group[0]...
  • for_each : module.resource_group["terraform013-test-1"]...

可読性を考えるとfor_eachの方が何のためのリソースなのかがわかりやすいため、個人的にはfor_eachを積極的に使っていこうと思います。

3.3. module内のdepends_on

次にmoduleブロック内でのdepends_onを検証してみます。
通常依存関係はterraformが解消してくれますが、依存関係が見えないリソースがあった場合、意図的に作成順序を変更する必要がありました。依存関係を解消するために、この機能は便利です。

今回は検証として、depends_onを記載することでの動作の違いを見ていきます。
3.2と同様にAzureのリソースグループを2つ作成するシナリオを想定します。
それぞれのソースを書いていきます。

3.3.1 depends_on なし

こちらのソースコードは、以下のように書き、実行します。

■ development/main.tf

module first_resource_group {
  source = "../modules/resource_group"

  name        = var.resource_group_name.first
  location    = var.location 
  environment = var.environment
}

module secound_resource_group {
  source = "../modules/resource_group"

  name        = var.resource_group_name.secound
  location    = var.location 
  environment = var.environment
}

■ development/variable.tf

variable resource_group_name {
  type        = map(string)
  description = "リソースグループ名"
  default     = {
    first   = "terraform013-test-1"
    secound = "terraform013-test-2"
  }
}

variable location {
  type        = string
  default     = "Japan East"
  description = "リージョン名"
}

variable environment {
  type        = string
  default     = "dev"
  description = "環境"
}

■実行結果

$ terraform apply

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # module.first_resource_group.azurerm_resource_group.common_rg will be created
  + resource "azurerm_resource_group" "common_rg" {
      + id       = (known after apply)
      + location = "japaneast"
      + name     = "terraform013-test-1"
      + tags     = {
          + "environment" = "dev"
        }
    }

  # module.secound_resource_group.azurerm_resource_group.common_rg will be created
  + resource "azurerm_resource_group" "common_rg" {
      + id       = (known after apply)
      + location = "japaneast"
      + name     = "terraform013-test-2"
      + tags     = {
          + "environment" = "dev"
        }
    }

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

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

module.secound_resource_group.azurerm_resource_group.common_rg: Creating...
module.first_resource_group.azurerm_resource_group.common_rg: Creating...
module.first_resource_group.azurerm_resource_group.common_rg: Creation complete after 1s [id=/subscriptions/f9d36b58-96cd-48d1-9dc8-f760b1cf174e/resourceGroups/terraform013-test-1]
module.secound_resource_group.azurerm_resource_group.common_rg: Creation complete after 1s [id=/subscriptions/f9d36b58-96cd-48d1-9dc8-f760b1cf174e/resourceGroups/terraform013-test-2]

Apply complete! Resources: 2 added, 0 changed, 0 destroyed.

どちらのリソースグループも並列に作成されました。

次に depends_on を追加した際の動作を確認します。

3.3.2 depends_on あり

こちらのソースコードは、以下のようになってます。

■ development/main.tf

module first_resource_group {
  source = "../modules/resource_group"

  name        = var.resource_group_name.first
  location    = var.location 
  environment = var.environment
}

module secound_resource_group {
  source = "../modules/resource_group"

  name        = var.resource_group_name.secound
  location    = var.location 
  environment = var.environment
  depends_on  = [ module.first_resource_group ]
}

■ development/variable.tf

3.3.1と同様のため割愛

■実行結果

$ terraform apply

An execution plan has been generated and is shown below.
Resource actions are indicated with the following symbols:
  + create

Terraform will perform the following actions:

  # module.first_resource_group.azurerm_resource_group.common_rg will be created
  + resource "azurerm_resource_group" "common_rg" {
      + id       = (known after apply)
      + location = "japaneast"
      + name     = "terraform013-test-1"
      + tags     = {
          + "environment" = "dev"
        }
    }

  # module.secound_resource_group.azurerm_resource_group.common_rg will be created
  + resource "azurerm_resource_group" "common_rg" {
      + id       = (known after apply)
      + location = "japaneast"
      + name     = "terraform013-test-2"
      + tags     = {
          + "environment" = "dev"
        }
    }

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

Do you want to perform these actions?
  Terraform will perform the actions described above.
  Only 'yes' will be accepted to approve.

  Enter a value: yes

module.first_resource_group.azurerm_resource_group.common_rg: Creating...
module.first_resource_group.azurerm_resource_group.common_rg: Creation complete after 1s [id=/subscriptions/f9d36b58-96cd-48d1-9dc8-f760b1cf174e/resourceGroups/terraform013-test-1]
module.secound_resource_group.azurerm_resource_group.common_rg: Creating...
module.secound_resource_group.azurerm_resource_group.common_rg: Creation complete after 0s [id=/subscriptions/f9d36b58-96cd-48d1-9dc8-f760b1cf174e/resourceGroups/terraform013-test-2]

Apply complete! Resources: 2 added, 0 changed, 0 destroyed.

実行結果を見ると、first_resource_groupが作成された後にsecound_resource_groupが作成されました。

3.4. variable内のvalidation

こちらの機能を使うと、定義している変数をバリデーションチェックできるようになりました。
こちらの機能を試してみます。

今回は、環境名に dev,stg,prod 以外を指定した場合、バリデーションチェックエラーとなるようなシナリオを想定し、コードを書いてみます。

■development/variable.tf

variable environment {
  type        = string
  default     = "dev"
  description = "環境"

  validation {
    condition     = var.environment == "dev" || var.environment == "stg" || var.environment == "prod"
    error_message = "The environment must be dev, stg, or prod."
  }
}

■実行結果

$ terraform plan -var 'environment=test'

Error: Invalid value for variable

  on variable.tf line 16:
  16: variable environment {

The environment must be dev, stg, or prod.

This was checked by the validation rule at variable.tf:21,3-13.

実行結果からわかるように、バリデーションチェックができ、自分の指定したエラーメッセージを出力することができました。
チームで決まっている、ネーミングルールを統一する際や、クラウドの文字数制限等を事前にチェックできる便利な機能です。

4. まとめ

terraform 0.13のバージョンアップ後の新機能を3つ検証しました。
3つとも待ち望んでいたような機能だったので、今後有効活用していきます。
特にvalidationは、ネーミングルールの統一だったり、クラウドの制約だったりを簡単にチームメンバーにお知らせできるようになるので、どんどん使っていこうと思います。

また、kubernetesにもstateファイルを保持できるようになっているので、kubernetesを本格導入する際に使っていこうと思いました。

28
16
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
28
16

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?