あきれぽ

自由日記帳

Terraform Moduleを使ったAzureリソースの管理方法を考えてみる

Terraform Moduleとは

Terraform Moduleを使うことで、同じリソースを複数作成する際に、変更したいパラメータだけを記述して簡単にリソースを作成できます。詳細については以下の記事が役立ちました。

今回はAzureを対象に構成を検討してみました。Terraformの構成はシステムごとにベストプラクティスが異なるため、あくまで一例としてご参考ください。

全体構成

terraform-azure
│   .gitignore
│   README.md
│
├───environments
│   ├───dev
│   │        main.tf  ... シンボリックリンク
│   │        providers.tf  ... シンボリックリンク
│   │        terraform.tfvars
│   │        variables.tf  ... シンボリックリンク
│   │
│   ├───prod
│   │       main.tf  ... シンボリックリンク
│   │       providers.tf  ... シンボリックリンク
│   │       terraform.tfvars
│   │       variables.tf  ... シンボリックリンク
│   │
│   └───stg
│           main.tf  ... シンボリックリンク
│           providers.tf  ... シンボリックリンク
│           terraform.tfvars
│           variables.tf  ... シンボリックリンク
│
└───shared
    │   main.tf
    │   providers.tf
    │   variables.tf
    │
    └───modules
        ├───management
        │       main.tf
        │       output.tf
        │       variables.tf
        │
        ├───network
        ├───security
        └───vm

モジュールがshared/modules、それを呼び出すルートがenvironmentsです。ルートは環境ごとに管理したいためenvironment/devのようにdev/stg/prodでそれぞれディレクトリを用意しています。

Terraformでは環境の分け方としてディレクトリの他にもWorkspaceを使う方法がありますのでお好みで。

environments

ルート側のファイルは4つありますが、実はそのうち3つが共通の記述で使えるため、shared配下にあるファイルのシンボリックリンクにしています。

  • main.tf ... 作成したいリソースを記載する。主な変更箇所。
  • providers.tf ... azurermのversion等を記載する。変更しない。
  • variables.tf ... 以下のtfvarsに記載する変数を記述する。環境ごとに変わらない。
  • terraform.tfvars ... 環境ごとに異なる変数を記載する。シンボリックリンクでない唯一のファイル。
environments/main.tf
locals {
    resource_group_name_test = "rg-${var.env_name}-test"
    resource_group_name_test2 = "rg-${var.env_name}-test2"
}

# TEST用のRG
module "management" {
    source = "../../shared/modules/management"
    resource_group_name = local.resource_group_name_test
}

# TEST用のRGその2
module "management2" {
    source = "../../shared/modules/management"
    resource_group_name = local.resource_group_name_test2
}

main.tfでは実際に作成するリソースを記述します。上記の例ではモジュール../../shared/modules/managementを呼び出しています。これはリソースグループのモジュールです。managementとmanagement2で2回呼び出しているためRGが2つ作成されます。

environments/variables.tf
variable "env_name" {
    type = string
    description = "環境名"
}

env_nameは環境ごとに値を変えたいためvariablesに記載しています。具体的な値はtfvarsに記載します。

environments/terraform.tfvars
env_name = "dev"

modules

shared/modulesにモジュールを記載します。今回は検証のためにmanagementモジュールだけを作成します。

  • main.tf ... モジュールを記載する。
  • output.tf ... 他のリソースで呼び出したいouputを記載します。今回はなし。
  • variables.tf ... environments/main.tfで呼び出す変数を記載します。中にはdefaultの値を記載している変数もあります。
main.tf
resource "azurerm_resource_group" "main" {
    name = var.resource_group_name
    location = var.resource_group_location
}

managementモジュールではリソースグループのみ記載しています。そのためresouce_groupモジュールのような名称を付けた方が良い気はしますが、今後複数のリソースをmanagementとして管理したいなぁと思ったためこう記載しています。どちらが有用かはわかりません。

variables.tf
variable "resource_group_name" {}
variable "resource_group_location" {
    default = "japaneast"
}

ルート側でresource_group_nameresource_group_locationを指定したいため上記のように記述しています。ただしresource_group_locationはdefaultに東日本を指定しているため、ルート側で指定がなければデフォルトの値でリソースを作成します。

実行

# 準備
az login
terraform init
terraform plan

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

Terraform will perform the following actions:

  # module.management.azurerm_resource_group.main will be created
  + resource "azurerm_resource_group" "main" {
      + id       = (known after apply)
      + location = "japaneast"
      + name     = "rg-dev-test"
    }

  # module.management2.azurerm_resource_group.main will be created
  + resource "azurerm_resource_group" "main" {
      + id       = (known after apply)
      + location = "japaneast"
      + name     = "rg-dev-test2"
    }

想定通り2つのRGが作成されます。moduleのazurerm_resource_group.mainが複数ありますがモジュールなので問題ないようです。削除するときにはターゲットにmodule.management2を指定することで片方のみ削除が可能でした。

terraform plan -destroy -target=module.management2

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:

  # module.management2.azurerm_resource_group.main will be destroyed
  - resource "azurerm_resource_group" "main" {
      - id       = "xxx" -> null
      - location = "japaneast" -> null
      - name     = "rg-dev-test2" -> null
      - tags     = {} -> null
    }
terraform destroy -target=module.management2

もっとこうした方が良い等あればコメントください。