はじめに
Infrastructure as Code(IaC)にチャレンジしてみました。
Terraformを使ってAzureのリソースを作成します。
事前準備
- Azure CLIのインストール
- Terraformのインストール
- VSCodeに拡張機能インストール(筆者がVSCodeで記述したいためです)
ディレクトリ構成
envの下に各環境のディレクトリを用意して環境依存のリソースに対応します。
共通で利用できるものに関してはディレクトリの最上位に配置します。
terraform
│ availability.tf
│ recovery_services_vault.tf
│ resource_group.tf
│ storage_account.tf
│ variables.tf
│ virtual_network.tf
│
├─env
│ └─sample
│ main.tf
│ sample-lb.tf
│ sample-nsg.tf
│ sample-vm.tf
│ variables.tf
│
└─modules
├─lb
│ lb.tf
│ outputs.tf
│ variables.tf
│
├─nsg
│ nsg.tf
│ variables.tf
│
└─vm
outputs.tf
variables.tf
vm.tf
定義
基本の定義
ディレクトリの最上位で定義しているリソースの作成はenv\sample\variables.tf
で宣言した変数と値をenv\sample\main.tf
で最上位のvariables.tf
内の変数に渡すことで行います。
環境が複数ある場合は、env\sample2
のようなディレクトリを作成して対応します。
locals {
##### Azureログイン情報 #####
login = {
subscription_id = "xxxxxx"
tenant_id = "xxxxxx"
}
location = {
main = "japaneast"
sub = "japanwest"
}
##### リソースグループ #####
resource_group = {
rg1 = {
name = "sample-rg"
location = local.location.main
}
}
~~~省略~~~
}
変数の渡し方は以下のようになります。
provider "azurerm" {
version = "~>2.0"
features {}
subscription_id = local.login.subscription_id
tenant_id = local.login.tenant_id
}
module "main" {
source = "../../"
resource_group = local.resource_group
virtual_network = local.virtual_network
subnet = local.subnet
public_ip = local.public_ip
availability_set = local.availability_set
storage_account = local.storage_account
recovery_services_vault = local.recovery_services_vault
backup_policy_vm_daily = local.backup_policy_vm_daily
backup_policy_vm_weekly = local.backup_policy_vm_weekly
proximity_placement_group = local.proximity_placement_group
backup_storage_account = local.backup_storage_account
}
最上位のvariables.tf
は値を受け取るだけです。
variable "resource_group" {}
variable "virtual_network" {}
variable "subnet" {}
variable "public_ip" {}
variable "availability_set" {}
variable "storage_account" {}
variable "recovery_services_vault" {}
variable "backup_policy_vm_daily" {}
variable "backup_policy_vm_weekly" {}
variable "proximity_placement_group" {}
variable "backup_storage_account" {}
モジュールの定義
設定項目が多いVM、NSG、LBは可読性を高めるため、モジュール化して1リソース=1ファイルで定義することにしました。
VMの場合は以下env\sample\sample-vm.tf
のように定義した値をmodules\vm\variables.tf
に渡します。
LBやNSGも同じ構成です。
locals {
sample-vm_var = {
resource_group_key = "rg1"
subnet_key = "sub1"
ehable_boot_diagnostics = false
ehable_backup = false
storage_account_key = "sa1"
availability_set_key = ""
proximity_placement_group_key = ""
public_ip_key = ""
recovery_services_vault_key = ""
backup_policy_vm_key = ""
}
}
locals {
##### 仮想マシン #####
sample-vm_vm = {
name = "sample-vm"
resource_group_name = module.main.resource_group[local.sample-vm_var.resource_group_key].name
location = module.main.resource_group[local.sample-vm_var.resource_group_key].location
vm_size = "Standard_D2s_v3"
availability_set_id = length(local.sample-vm_var.availability_set_key) > 0 ? module.main.availability_set[local.sample-vm_var.availability_set_key].id : ""
proximity_placement_group_id = length(local.sample-vm_var.proximity_placement_group_key) > 0 ? module.main.proximity_placement_group[local.sample-vm_var.proximity_placement_group_key].id : ""
##### ディスク関連 #####
delete_os_disk_on_termination = false
delete_data_disks_on_termination = false
ultra_ssd_enabled = false
##### 仮想マシンイメージ #####
image = {
is_windows_image = true
os_id = ""
publisher = "MicrosoftWindowsServer"
offer = "WindowsServer"
sku = "2019-Datacenter"
version = "latest"
}
##### OSディスク #####
# managed_disk_type : Standard_LRS, StandardSSD_LRS, Premium_LRS
os_disk = {
managed_disk_type = "Standard_LRS"
write_accelerator_enabled = false
}
##### 仮想ネットワーク #####
network = {
subnet_id = module.main.subnet[local.sample-vm_var.subnet_key].id
private_ip_address = "10.0.0.5"
public_ip_address_id = length(local.sample-vm_var.public_ip_key) > 0 ? module.main.public_ip[local.sample-vm_var.public_ip_key].id : ""
enable_accelerated_networking = false
}
##### ローカル管理者 #####
os_profile = {
admin_username = "sampleadmin"
admin_password = "Hogehoge12#$"
}
##### ブート診断 #####
boot_diagnostics = {
ehable_boot_diagnostics = local.sample-vm_var.ehable_boot_diagnostics
primary_blob_endpoint = local.sample-vm_var.ehable_boot_diagnostics ? module.main.storage_account[local.sample-vm_var.storage_account_key].primary_blob_endpoint : ""
}
##### Windows個別設定 #####
windows = {
timezone = "Tokyo Standard Time"
}
##### Linux個別設定 #####
linux = {
enable_ssh_key = false
ssh_key = ""
}
##### Backup #####
backup = {
recovery_vault_name = local.sample-vm_var.ehable_backup ? module.main.recovery_services_vault[local.sample-vm_var.recovery_services_vault_key].name : ""
backup_policy_id = local.sample-vm_var.ehable_backup ? module.main.backup_policy_vm_daily[local.sample-vm_var.backup_policy_vm_key].id : ""
}
##### Load Balancer #####
load_balancer = {
ehabled_load_balancer = false
backend_address_pool_id = module.sample-lb.lb_backend_address_pool.id
}
tags = {
name = "サンプル仮想マシン"
}
}
##### データディスク #####
sample-vm_data_disk = {
"disk1" = {
disk_size_gb = "16"
managed_disk_type = "Standard_LRS"
caching = "ReadOnly"
lun = 0
write_accelerator_enabled = false
}
}
}
##### 仮想マシンの作成 #####
module "sample-vm" {
source = "../../modules/vm/"
vm = local.sample-vm_vm
data_disk = local.sample-vm_data_disk
}
受け取り側
variable "vm" {}
variable "data_disk" {}
リソース作成有無の制御
リソース有無による修正箇所を少なくするため、env\sample
内の変数をコメントアウトすることでも対応できるようにしました。
例えばパブリックIPアドレスを作る必要がない場合は以下のようにします。
public_ip = {
# pip1 = {
# name = "vm1-pip"
# resource_group_key = "rg1"
# sku = "Basic"
# allocation_method = "Static"
# }
}
パブリックIPアドレスのリソース作成部分はfor_each
を使って制御しています。
変数public_ip
のmapが存在しない場合は、スルーされます。
resource "azurerm_public_ip" "main" {
for_each = var.public_ip
name = each.value.name
resource_group_name = azurerm_resource_group.main[each.value.resource_group_key].name
sku = each.value.sku
location = azurerm_resource_group.main[each.value.resource_group_key].location
allocation_method = each.value.allocation_method
}
実行
定義が準備できたので実際にリソースを作ってみます。
今回はサービスプリンシパルを使用しないため、事前にAzure CLIでAzureにログインします。
az login
env\sample
に移動後、terraform init
で初期化します。
terraform init
Initializing modules...
- main in ..\..
- sample-lb in ..\..\modules\lb
- sample-nsg in ..\..\modules\nsg
- sample-vm in ..\..\modules\vm
Initializing the backend...
Initializing provider plugins...
- Checking for available provider plugins...
- Downloading plugin for provider "azurerm" (hashicorp/azurerm) 2.14.0...
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 plan
~~~省略~~~
Plan: 15 to add, 0 to change, 0 to destroy.
terraform apply
でリソース作成します。
terraform apply
~~~省略~~~
Apply complete! Resources: 15 added, 0 changed, 0 destroyed.
最後に
一度定義すると簡単にリソースの作成、変更、削除が行えるのは素晴らしいですね。
今回汎用的に使えるように定義しようとして上手くいかず大分苦戦しました。
ただ、そのおかげで少しはTerraformの構文が理解できたのではないかと思っています。
今回書いたサンプルコードはGitHubで公開していますので良かったら利用してみてください。
至らない点も多々あると思いますので使いやすいように修正してお使いいただければと思います。
https://github.com/ytamu2/Terraform-Azure-Template