⛏️

Proxmoxに入門したのでTerraformにも入門してみた

に公開

概要

最近Proxmoxに入門したので、ついでにTerraformにも入門してみました。
どちらも初めて触るのでTerraformからVMを作れるようになるまで時間がかかりましたが、一応できたので備忘として残します。
なお、ProxmoxもTerraformも初心者なので間違っていることやもっといいやり方があると思いますがその辺はご容赦を...

前提

TerraformからVMを作るまでの手順

VMのテンプレを作成

まずはVMのテンプレを作成します。
コマンドで作成するのでProxmoxにSSHで接続して直接コマンドを打ってください。
変数のところはそれぞれの環境に合わせて変更してください。

#### 変数 ####
VM_TEMPLATE_ID=9999
VM_TEMPLATE_NAME="ubuntu-2404-tmpl"
VM_TEMPLATE_MEMORY=2048
VM_TEMPLATE_CPU=2
VM_DISK_STORAGE="local-lvm"
UBUNTU_IMG_URL="https://cloud-images.ubuntu.com/releases/24.04/release/ubuntu-24.04-server-cloudimg-amd64.img"
UBUNTU_IMG_FILENAME=$(basename $UBUNTU_IMG_URL)
IMG_ISO_PATH="/var/lib/vz/template/iso"
SCRIPT_TMP_PATH="/tmp"
#### 変数 ####

# Ubuntuのimgファイルをダウンロードしてコピー
wget $UBUNTU_IMG_URL -O "$SCRIPT_TMP_PATH/$UBUNTU_IMG_FILENAME"
cp "/$SCRIPT_TMP_PATH/$UBUNTU_IMG_FILENAME" "$IMG_ISO_PATH/$UBUNTU_IMG_FILENAME"

# VMテンプレートの作成
qm create $VM_TEMPLATE_ID --name $VM_TEMPLATE_NAME --memory $VM_TEMPLATE_MEMORY --cores $VM_TEMPLATE_CPU --net0 virtio,bridge=vmbr0
qm set $VM_TEMPLATE_ID --scsihw virtio-scsi-single
qm set $VM_TEMPLATE_ID --virtio0 $VM_DISK_STORAGE:0,import-from="$SCRIPT_TMP_PATH/$UBUNTU_IMG_FILENAME"
qm set $VM_TEMPLATE_ID --boot c --bootdisk virtio0
qm set $VM_TEMPLATE_ID --ide2 $VM_DISK_STORAGE:cloudinit
qm set $VM_TEMPLATE_ID --serial0 socket --vga serial0
qm set $VM_TEMPLATE_ID --agent enabled=1,fstrim_cloned_disks=1

qm template $VM_TEMPLATE_ID

APIトークンの作成

ProxmoxのAPIトークンを作成します。具体的な手順はドキュメントなどを参照していただけると。
ログイン後に「データセンター > アクセス権限 > APIトークン」の「追加」から作成できる。

Terraform関連のファイルを作成

Terraformのファイルを作成します。同じディレクトリに全てのファイルを作成しています。

providers.tfの作成

Proxmoxを扱えるようにTerraform Registryにあるtemate/proxmoxを使用しました。
https://registry.terraform.io/providers/Telmate/proxmox/3.0.2-rc01

providers.tf
terraform {
  required_version = ">=1.3.3"

  required_providers {
    proxmox = {
      source  = "telmate/proxmox"
      version = "3.0.2-rc01"
    }
    null = {
      source  = "hashicorp/null"
      version = "3.2.2"
    }
  }
}

provider "proxmox" {
  pm_api_url          = var.pm_api_url
  pm_api_token_id     = var.pm_api_token_id
  pm_api_token_secret = var.pm_api_token_secret
  pm_tls_insecure     = var.pm_tls_insecure
  pm_parallel         = var.pm_parallel
  pm_timeout          = var.pm_timeout
}

variables.tfの作成

変数を定義します。ProxmoxのAPI関連とVMの設定値を定義しています。

variables.tf
### Proxmox VE ###
variable "pm_api_url" {
  type        = string
  description = "ProxmoxのAPIエンドポイント"
}
variable "pm_api_token_id" {
  type        = string
  description = "ProxmoxのAPIトークンID"
}
variable "pm_api_token_secret" {
  type        = string
  description = "ProxmoxのAPIトークンシークレット"
  sensitive   = true
}
variable "pm_tls_insecure" {
  type        = bool
  description = "TLS検証を無効にする"
}
variable "pm_target_node" {
  type        = string
  description = "リソースを作成するProxmoxのノード"
}

variable "pm_parallel" {
  type        = number
  description = "Proxmoxリソースの同時作成可能数"
  default     = 2
}

variable "pm_timeout" {
  type        = number
  description = "Proxmox APIの呼び出しタイムアウト(秒)"
  default     = 600
}

### VMs ###
variable "vms" {
  description = "作成するVMリスト"
  type = list(object({
    vmid             = optional(number) # VMのID
    name             = string # VM名
    tags             = optional(string, "terraform") # VMに付与するタグ(default: terraform)
    description      = string # VMの説明
    ubuntu_tmpl_name = string # VMのコピー元テンプレート
    cpu_cores        = number # VMのCPUコア数
    cpu_sockets      = optional(number, 1) # VMのCPUソケット数(default: 1)
    memory_mb        = number # VMのメモリ容量(MB)
    os_disk_size_gb  = number # VMのディスクサイズ(GB)
    os_disk_storage  = string # VMのディスクを保存するストレージ
    net_bridge       = string # VMのネットワークデバイスを接続するブリッジ
    net_ip_address   = string # VMのIPアドレス
    net_subnet_cidr  = string # VMのサブネットマスク
    net_default_gw   = string # VMのデフォルトゲートウェイ
    ciuser           = optional(string, "ubuntu") # VMのユーザー名
    ssh_public_key   = string # VMに登録するSSH公開鍵
  }))
}

ubuntu_vm.tfの作成

VMのresourceを作成します。一度に複数のVMを作れるようにしたかったので、作成するVMのリストを渡せるようにしています。

ubuntu_vm.tf
resource "proxmox_vm_qemu" "ubunut_vm" {
  count = length(var.vms)

  vmid        = var.vms[count.index].vmid
  name        = var.vms[count.index].name
  desc        = var.vms[count.index].description
  target_node = var.pm_target_node
  clone       = var.vms[count.index].ubuntu_tmpl_name
  agent       = 1
  os_type     = "cloud-init"
  boot        = "order=virtio0"

  tags = var.vms[count.index].tags

  cpu {
    cores   = var.vms[count.index].cpu_cores
    sockets = var.vms[count.index].cpu_sockets
    type    = "host"
  }
  memory = var.vms[count.index].memory_mb
  scsihw = "virtio-scsi-single"

  disks {
    ide {
      ide0 {
        cloudinit {
          storage = var.vms[count.index].os_disk_storage
        }
      }
    }
    virtio {
      virtio0 {
        disk {
          size     = var.vms[count.index].os_disk_size_gb
          storage  = var.vms[count.index].os_disk_storage
          iothread = true
        }
      }
    }
  }

  serial {
    id   = 0
    type = "socket"
  }

  network {
    id     = 0
    model  = "virtio"
    bridge = var.vms[count.index].net_bridge
  }

  ipconfig0 = "ip=${var.vms[count.index].net_ip_address}/${split("/", var.vms[count.index].net_subnet_cidr)[1]},gw=${var.vms[count.index].net_default_gw}"

  ciuser = var.vms[count.index].ciuser
  sshkeys = var.vms[count.index].ssh_public_key
}

output.tfの作成

出力をスッキリさせたかったので、VM名、IPアドレス、メモリ容量、vCPU数を表示するようにしてます。

output.tf
output "vm_list" {
  value = [
    for idx, vm in var.vms : {
      name       = vm.name
      ip_address = vm.net_ip_address
      memory_mb  = vm.memory_mb
      vcpu       = vm.cpu_cores * vm.cpu_sockets
    }
  ]
}

terraform.tfvars

最後に設定ファイルを作成します。ここではVMを2つ作る設定ファイルにしています。
適用する環境に合わせて設定を変更します。

terraform.tfvars
# Proxmoxの設定
pm_api_url          = "https://<ProxmoxノードのIP>:8006/api2/json"
pm_api_token_id     = "root@pam!terraform"
pm_api_token_secret = "aaaaaaaaaaaa-bbbb-cccc-dddd-eeeeeeeeeeee"
pm_tls_insecure     = true
pm_target_node      = "pve"
pm_parallel         = 2
pm_timeout          = 600

# VMの設定
vms = [
  {
    vmid             = 155
    name             = "ubuntu-vm-01"
    description      = "Ubuntu VM 01"
    ubuntu_tmpl_name = "ubuntu-2404-tmpl"
    cpu_cores        = 3
    cpu_sockets      = 1
    memory_mb        = 2048
    os_disk_size_gb  = 20
    os_disk_storage  = "local-lvm"
    net_bridge       = "vmbr0"
    net_ip_address   = "192.168.50.184"
    net_subnet_cidr  = "192.168.50.0/24"
    net_default_gw   = "192.168.50.1"
    ciuser           = "ubuntu"
    ssh_public_key   = "ssh-rsa <SSH-PUBLIC-KEY-TEXT> ubuntu@pc"
    }, {
    vmid             = 156
    name             = "ubuntu-vm-02"
    description      = "Ubuntu VM 02"
    ubuntu_tmpl_name = "ubuntu-2404-tmpl"
    cpu_cores        = 2
    cpu_sockets      = 1
    memory_mb        = 2048
    os_disk_size_gb  = 20
    os_disk_storage  = "local-lvm"
    net_bridge       = "vmbr8"
    net_ip_address   = "192.168.8.185"
    net_subnet_cidr  = "192.168.8.0/24"
    net_default_gw   = "192.168.8.1"
    ciuser           = "ubuntu"
    ssh_public_key   = "ssh-rsa <SSH-PUBLIC-KEY-TEXT> ubuntu@pc"
  },
]

VMを作成してみる

Terrafrom関連のファイルが作成できたので最後に適用します。なお、コマンドの出力を含めると長くなるのでここでは省略します

# モジュールなどを初期化
$ terraform init

# Terraformの実行計画を確認
$ terraform plan

# Proxmoxに適用(最後にoutput.tfで定義した形で出力されます)
$ terraform apply -auto-approve
...
Outputs:

vm_list = [
  {
    "ip_address" = "192.168.50.184"
    "memory_mb" = 2048
    "name" = "ubuntu-vm-01"
    "vcpu" = 3
  },
  {
    "ip_address" = "192.168.8.185"
    "memory_mb" = 4096
    "name" = "ubuntu-vm-02"
    "vcpu" = 2
  },
]

大変だったところ

知識が全くなかったので全体的に大変でしたが、ProxmoxのGUIからコンソールになかなかアクセスできず、解決までに無駄に時間を使ってしまいました。結果的に、ubuntu_vm.tfserialブロックを追加して解消できましたが、ずっとVM自体がスタックしていると勘違いして全然違うところ調べていました(早くpingを飛ばしてVMが起動しているか確認すればよかった...)

参考にしたサイト

Discussion