0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

Terraformメモ1

Last updated at Posted at 2025-03-30

ただのTerraformの個人用メモ。

ファイル

terraformでは、以下のファイルを自動的に読み込む。

  • ディレクトリ内の.tfファイル
  • terraform.tfvars
  • auto.tfvars

terraform基本コマンド

  1. terraform init
  2. terraform fmt (-recursive)
    • フォーマット修正、不要な空白や改行などがあれば修正してくれる、子ディレクトリもやる場合はrecursiveをつける
  3. terraform validate
    • terraformの文法チェックをしてくれる
  4. terraform plan -out plan.tfplan
    • ドライラン、ドライラン結果を
  5. terraform apply plan.tfplan
    • 実際のデプロイ
  6. terraform destroy
    • デプロイしたリソースの削除

Terraformのvariable, local

基本的にvariableはモジュール間でのデータの受け渡し、localは受け取ったデータなどを編集して利用したいときに使うと理解した。variableは受け渡し用のパラメータ、localはスコープ変数。

variables.tf
variable "variable_name" {
    type = string
    description = "this is a exmple description"
    sensitive = true
    default = "default_value"
}
locals.tf
locals {
    key0 = "value0"
    keymap = {
        key1 = "value1",
        key2 = "value2"
    }
}
main.tf
resource "resource_type" "resource_name" {
     attribute1 = var.variable_name
    attribute2 = "${var.variable_name}_suffix" # interapolation、変数を編集できる

    attribute3 = local.key0
    attribute4 = local.keymap.key1
}

variableの設定方法色々

  • 実行時の -var
  • 実行時の -var-file FILE_NAME.tfvars
  • variableのdefault
  • terraform.tfvars
    • この名前であれば自動的に読み込まれる
  • 環境変数のTF_VAR_{VARIABLENAME}

通常のtfvarsとterraform.tfvarsの違いとして、terraform.tfvarsファイルは実行時に-var-fileで指定しなくても自動的に変数ファイルとして読み込まれる。ということは、環境に関係ないデフォルト値を設定するのに便利。逆に通常のtfvarsファイルは環境特有の値を定義するのに使う。tfvarsファイルはなのでgitignoreに定義しチェックインしない。

terraform version

.tfファイルを作成した時のバージョンより高いバージョンを必要とするようにする。

例えば、現在のバージョンがv1.10.5なのでそれ以上のバージョンを必要とするようにする。

vscode ➜ /workspaces/FirstProject (main) $ terraform --version
Terraform v1.10.5
on linux_amd64
main.tf
terraform {
  required_version = ">= v1.10.5"
  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "2.46.0"
    }
  }
}

Terraformの配列、オブジェクト型

配列

  • List
    順序付きの値の集合。
    重複する要素を含むことが可能。
    インデックスを使用して要素にアクセスする。
variable "example_list" {
  type = list(string)
  default = ["apple", "banana", "orange"]
}
  • Set
    重複のない値の集合。
    順序は保証されない。
    同じ型の要素のみを含むことができる。
variable "example_list" {
  type = set(string)
  default = ["apple", "banana", "orange"]
}

toset関数を使用してlistをsetに変換することができる。これにより、重複する値を削除し、ユニークな値のみを保持することができる。また、for_each文はmap型またはset型のみを受け付けるため、リストをsetに変換して使用する。

  • Tuple
    異なる型の値を順序ありで格納する。
variable "person_info" {
  type = tuple([string, number, bool])
  default = ["Alice", 30, true]
}

オブジェクト型

  • Map
    キーと値のペアの集合。
    キーは一意である必要がある。
    重複するキーが追加されると、後から追加された値で上書きされる。
variable "example_map" {
  type = map(string)
  default = {
    key1 = "value1",
    key2 = "value2"
  }
}
  • Object
    キーと値のペアの集合。
    Mapに似ているが、異なる型のデータを混ぜることができる。
variable "example_object" {
  type = object({
    name    = string
    age     = number
    is_admin = bool
  })
  default = {
    name    = "John",
    age     = 30,
    is_admin = true
  }
}

Data

dataを利用して既存のリソースの情報を取得する。
以下はSubscriptionの情報を取得する例。

provider "azurerm" {
  features {}
}

data "azurerm_subscription" "main" {}

resource "azurerm_role_definition" "main" {
  name        = "write-accessrole"
  scope       = data.azurerm_subscription.main.id

  assignable_scopes = [
    data.azurerm_subscription.main.id
  ]
}

ループ

loop

loopで回せるのはmap, set。
foreachによってmapを回してみると以下のようになる。

resource "instance" "web" {
    for_each = {
        aaa = "aaa.txt"
        bbb = "bb.txt"
    }
    key = each.value
    value = "test-${each.value}"
    tags = {
        Name = each.key
    }
}

count

countを使えば複数のリソースを一括で作成可能。

resource "instance" "web" {
    count = 3
    tags = {
        Name = "test-web-${count.index}"
    }
}

terraform function

terraform console

Functionは動作確認するときには、terraform consoleでテストすることができる。

vscode ➜ /workspaces/FirstProject/day3 (main) $ terraform console
> min(1,2,3)
1
> cidrsubnet("10.0.0.0/16",12,1)
"10.0.0.16/28"
> cidrsubnet("10.0.0.0/16",12,2)
"10.0.0.32/28"
> cidrsubnets("10.0.0.0/16", 12, 12, 12)
tolist([
  "10.0.0.0/28",
  "10.0.0.16/28",
  "10.0.0.32/28",
])
> exit

ちなみにIPレンジを指定する際に変数とcidrsubetどちらを利用するべきかPerplexityに質問してみた。

TerraformでAzure上にVNETとSubnetを作成する際、IPレンジの指定方法については、以下のポイントを考慮するとよいでしょう。

選択肢1: 変数でIPレンジを指定
メリット:
明確に管理可能で、環境ごとに異なるCIDR範囲を簡単に設定できる。
他のツールや手動計算で事前にCIDR範囲を計画し、競合を避けることができる。

デメリット:
手動でCIDR範囲を計算する必要があり、大規模なネットワークではミスが発生しやすい。動的な割り当てには対応しづらい。

選択肢2: cidrsubnet関数を使用
メリット:
Terraformの組み込み関数であるcidrsubnetやcidrsubnetsを利用することで、動的にIPレンジを計算可能。
ネットワーク設計が柔軟になり、複数のサブネットを簡単に生成できる。

デメリット:
cidrsubnetは既存のIPアドレスの使用状況を検証しないため、重複が発生する可能性がある。IPアドレスの競合エラーを防ぐには、事前に範囲の利用状況を確認する仕組みが必要。

推奨事項
小規模なネットワークや固定された環境では、変数でCIDR範囲を指定する方法が簡便で安全です。
大規模なネットワークや動的なサブネット構成が必要な場合は、cidrsubnet関数を使用しつつ、既存のIPアドレス範囲との競合を避けるために事前検証を行う仕組み(例えばTerraform外部スクリプトや手動確認)を導入することが推奨されます。

どちらの方法でも、設計段階でCIDR範囲の計画を十分に行うことが重要です。

Module

普通のModuleを作って使う

Moduleを作成するには、最低限以下の3つのファイルをModulesフォルダ配下に作成する。

  • main.tf
  • output.tf
  • variable.tf

image.png

main.tfにはprovidersの指定は不要。それは呼び出す方の親側で定義する。

main.tf
terraform {
  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "4.25.0"
    }
  }
}

locals {
  tags = {
    "Environment" = var.environment
  }
}

resource "azurerm_storage_account" "securestorage" {
  resource_group_name           = var.resource_group_name
  name                          = var.name
  account_kind                  = "StorageV2"
  location                      = var.location
  account_tier                  = "Standard"
  account_replication_type      = var.environment == "prod" ? "LRS" : "GRS"
  public_network_access_enabled = false
  tags                          = local.tags
}
variables.tf
variable "environment" {
  description = "The environment to deploy to (e.g., dev, staging, prod)"
  type        = string
  default     = "dev"
}

variable "resource_group_name" {
  description = "The name of the resource group to create"
  type        = string
  default     = "myResourceGroup"
}

variable "location" {
  description = "The Azure region to deploy the resources in"
  type        = string
  default     = "East US"
}

variable "name" {
  description = "The name of the storage account"
  type        = string
  default     = "securestorage"
}
output.tf
output "name" {
  description = "The name of the storage account"
  value       = azurerm_storage_account.securestorage.name
}

output "id" {
  description = "The ID of the storage account"
  value       = azurerm_storage_account.securestorage.id
}

output "primary_blob_endpoint" {
  description = "The primary blob endpoint of the storage account"
  value       = azurerm_storage_account.securestorage.primary_blob_endpoint
}

呼び出すには以下のように定義する。

main_parent.tf
terraform {
  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "~> 4.0"
    }
  }
}

provider "azurerm" {
  features {}
  subscription_id = var.subscription_id
}

resource "azurerm_resource_group" "rg" {
  name     = "myResourceGroup1"
  location = "Japan East"
}

# use module to cretate secure storage account
module "samplemodule" {
  source              = "./Modules/securestorage"
  resource_group_name = azurerm_resource_group.rg.name
  name                = "simastorageaccount1"
  location            = "Japan East"
  environment         = "dev"
}


output "name" {
  description = "The name of the storage account"
  value       = module.samplemodule.name
}

Terraform moduleを Private Registryに登録して組織内で共有できるようにする

GithubでRepositoryを作成。Repository名称はterraform-{providername}-{modulename}にする。

今回はterraform-azurerm-securestorageで作成。
image.png

先ほどのコードをそのままチェックインした状態にする。
image.png

TagsからCreate a new release。
image.png

Terraform CloudでRegistryからPublish。
image.png

image.png

Terraform CloudがGitHubにアクセスできるように許可。
image.png

image.png

image.png

Terraform Cloud上のPrivate Repository上にPublishできた。なんかかっこいい。
image.png

使ってみる。terraform login, terraform init, terraform apply。

main.tf
terraform {
  # use azurerm provider version 3.0.0 or later
  required_providers {
    azurerm = {
      source  = "hashicorp/azurerm"
      version = "~> 4.0"
    }
  }
}

# Configure the Azure Provider
provider "azurerm" {
  features {}
  subscription_id = var.subscription_id
}

resource "azurerm_resource_group" "rg" {
  name     = "myResourceGroup1"
  location = "Japan East"
}

module "securestorage" {
  source  = "app.terraform.io/SimaTeraOrg/securestorage/azurerm"
  version = "1.0.0"
  name = "stsimastoaccount1"
  resource_group_name = azurerm_resource_group.rg.name
  location = azurerm_resource_group.rg.location
}
0
0
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
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?