ただのTerraformの個人用メモ。
ファイル
terraformでは、以下のファイルを自動的に読み込む。
- ディレクトリ内の.tfファイル
- terraform.tfvars
- auto.tfvars
terraform基本コマンド
- terraform init
- terraform fmt (-recursive)
- フォーマット修正、不要な空白や改行などがあれば修正してくれる、子ディレクトリもやる場合はrecursiveをつける
- terraform validate
- terraformの文法チェックをしてくれる
- terraform plan -out plan.tfplan
- ドライラン、ドライラン結果を
- terraform apply plan.tfplan
- 実際のデプロイ
- terraform destroy
- デプロイしたリソースの削除
Terraformのvariable, local
基本的にvariableはモジュール間でのデータの受け渡し、localは受け取ったデータなどを編集して利用したいときに使うと理解した。variableは受け渡し用のパラメータ、localはスコープ変数。
variable "variable_name" {
type = string
description = "this is a exmple description"
sensitive = true
default = "default_value"
}
locals {
key0 = "value0"
keymap = {
key1 = "value1",
key2 = "value2"
}
}
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
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
main.tfにはprovidersの指定は不要。それは呼び出す方の親側で定義する。
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
}
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 "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
}
呼び出すには以下のように定義する。
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で作成。
Terraform CloudでRegistryからPublish。
Terraform CloudがGitHubにアクセスできるように許可。
Terraform Cloud上のPrivate Repository上にPublishできた。なんかかっこいい。
使ってみる。terraform login, terraform init, terraform apply。
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
}