Help us understand the problem. What is going on with this article?

terraform-provider-esxi を使って自宅 ESXi サーバに VM を立てよう

はじめに

この記事は terraform Advent Calendar 2020 6日目です。

  • Qiita に知見がないプロバイダの使ってみた系記事です
  • 自宅サーバのようなオンプレかつ低コストに、かつ Terraform を使って ESXi の VM を管理したい人向けです
  • この記事を書いている人は Terraform 素振り歴が累計1年あるかないかぐらいです
    • (初参加です、よろしくお願いします)

terraform { required_version = ">= 0.13" } にてお送りします。

terraform-provider-esxi とは

github.com/josenk/terraform-provider-esxi

これは、Terraform から ESXi 仮想マシンを直接デプロイできるプロバイダです。

何をしてくれるのかと言うと:

  1. VMware ESXi を導入したサーバに対し
  2. このプロバイダを介して直接 SSH 接続し
  3. vim-cmd などのコマンドを実行して仮想マシン諸々の管理をしてくれます

このプロバイダの利点は vSphere を介さずに動作するため、ESXi 単体で(無償ライセンスの範疇で)利用できるという点です。

プロバイダの性質的には terraform-provider-libvirt と似ていると思います。

ただ、気を付けなければいけない点として、ESXi サーバの SSH 接続が有効でなければ使用できないので、安全性を含めて使用には注意が必要だと思います。

もう少し詳細な解説


通常、無償ライセンスで ESXi を使うには少し苦労する点があります。

ESXi 自体は有償・無償のライセンスがあり、無償版では API による仮想マシンなどのリソースの新規作成などが制限されているため、
単体で仮想マシンを作成するには Web の GUI クライアントか、直接 SSH 接続したうえで vim-cmdesxcli などを叩く必要があります1

なお、Terraform の公式プロバイダには terraform-provider-vsphere が用意されていますが、API を介して ESXi を管理するため、無償版 ESXi はサポートされていません。

This provider requires API write access and hence is not supported on a free ESXi license.
Docs overview | hashicorp/vsphere | Terraform Registry

今回使用する terraform-provider-esxi は、ESXi に備え付けられている vim-cmdesxcli を SSH 接続して代わりに実行してくれるので、
API を介さずに ESXi 単体で仮想マシンやネットワークの構成を自動化出来るような仕組みになっています。



さらに詳細な使い方は READMEWiki を一読しましょう。

というわけで、この記事では実際に terraform-provider-esxi を使って仮想マシンを作成してみます。

事前準備

ESXi がインストールされたサーバが必要になります(割愛します)。
そして、ESXi 管理コンソールにブラウザなどからアクセスし SSH を有効にしておきます。

リソースの作成

Terraform で仮想マシンリソースを作成します。
今回は Fedora CoreOS(FCOS)と言う、コンテナランタイム環境に特化したフットプリントの軽い OS をデプロイしてみます。

VM の作成方法

このプロバイダで仮想マシンをデプロイする方法は 2種類あり、今回は FCOS の公式からダウンロードできる OVF テンプレートによるデプロイとなります。

そして、FCOS の Ignition という仕組みを使い、ユーザの作成、SSH サーバの設定、open-vm-tools のインストールをあらかじめ構成した仮想マシンをデプロイします。

ちなみに、もう一つのデプロイ方法として、すでに ESXi 上にある VM リソースをクローンすることが出来ます。

更にもう一つ、上記のどちらの方法も指定しなかった場合は、空の状態(デフォルトで PXE ブート)で仮想マシンを作成することも可能なようです。

Fedora CoreOS VM イメージの取得

まず、Terraform を実行する PC 上に、coreos-installer で OVA フォーマットの VM イメージをあらかじめダウンロードしておきます。

$ docker run --rm -v $PWD:/data -w /data quay.io/coreos/coreos-installer:release download -s stable -p vmware -f ova
Read disk 11.1 MiB/791.0 MiB (1%)
Read disk 22.2 MiB/791.0 MiB (2%)
(snip)
Read disk 791.0 MiB/791.0 MiB (100%)
gpg: Signature made Mon Nov  2 23:13:28 2020 UTC
gpg:                using RSA key 97A1AE57C3A2372CCA3A4ABA6C13026D12C944D0
gpg: Good signature from "Fedora (32) <fedora-32-primary@fedoraproject.org>" [ultimate]
Read disk 791.0 MiB/791.0 MiB (100%)
./fedora-coreos-32.20201018.3.0-vmware.x86_64.ova

構成

Terraform ファイルを構成します。
ここでは Ignition を設定するため、 terraform-provider-ct も依存関係に追加します。

versions.tf
terraform {
  required_version = ">= 0.13"
  required_providers {
    esxi = {
      source  = "josenk/esxi"
      version = "1.8.0"
    }
    ct = {
      source  = "poseidon/ct"
      version = "0.6.1"
    }
  }
}

esxi プロバイダの接続情報には、Web クライアント上でリソースの作成権限があるユーザ情報を入力してください

providers.tf
provider "esxi" {
  esxi_hostname = "esxi.example.com"
  esxi_username = "username"
  esxi_password = "password"
}

provider "ct" {}

esxi_guest リソースの定義

esxi_guest で、仮想マシンリソースのプロパティを定義します。

  • ovf_source に先程ダウンロードした VM イメージを指定します
  • esxi_guestdisk_storenetwork_interfaces.virtual_network は環境ごとに異なります
  • その他スペックについては環境に合わせて調整してください
    • guestos には、ESXi や Fusion 使用する OS の識別子をこの辺とかを参考に指定します
      (FCOS の OVF テンプレートが RHEL 扱いとなっており、ESXi が警告を出すので上書きしてます)
main.tf
locals {
  ovf_source       = "/path/to/fedora-coreos-32.20201004.3.0-vmware.x86_64.ova"
  ignition_content = "/path/to/ignition.yaml"
  guest_num_vcpu   = 2
  guest_memory_gb  = 4
  guest_disk_gb    = 30
}

data "ct_config" "ignition" {
  content      = local.ignition_content
  strict       = true
  pretty_print = false
}

resource "esxi_guest" "fcos_guest" {
  ovf_source = local.ovf_source
  guestos    = "fedora-64"

  guest_name = "fcos-guest"
  power      = "on"

  numvcpus       = local.guest_num_vcpu
  memsize        = max(local.guest_memory_gb * 1024, 512)
  disk_store     = "datastore1"
  boot_disk_size = max(local.guest_disk_gb, 20)
  network_interfaces {
    virtual_network = "VM Network"
  }

  guestinfo = {
    "ignition.config.data"          = base64gzip(data.ct_config.ignition.rendered)
    "ignition.config.data.encoding" = "gzip+base64"
  }
}

Ignition テンプレートの実装

Ignition には post-install.service として open-vm-tools をインストールさせるように仕組みます2

ignition.yaml

ignition.yaml
variant: fcos
version: 1.1.0
passwd:
  users:
    - name: test_user
      ssh_authorized_keys:
        - (snip)
      home_dir: /home/test_user
      shell: /bin/bash
      groups: [ docker, wheel ]
storage:
  files:
    - path: /etc/ssh/sshd_config.d/10-customize.conf
      contents:
        inline: |
          Port 40022
          PasswordAuthentication no
          PermitEmptyPasswords no
          PermitRootLogin no
      mode: 0644
systemd:
  units:
    - name: post-install.service
      enabled: true
      contents: |
        [Unit]
        Description=Post Installation
        ConditionFirstBoot=yes
        Wants=network-online.target
        After=network-online.target
        After=multi-user.target
        Before=boot-complete.target
        [Service]
        Type=oneshot
        TimeoutStartSec=0
        ExecCondition=/usr/bin/test ! -f /etc/package-installer.done
        ExecStart=/usr/bin/rpm-ostree install open-vm-tools
        ExecStartPost=/usr/bin/touch /etc/package-installer.done
        ExecStartPost=/usr/bin/systemctl --no-block reboot
        [Install]
        WantedBy=multi-user.target
        RequiredBy=boot-complete.target


Output

outputs.tf
output "ip_address" {
  value = esxi_guest.fcos_guest.ip_address
}

実行

terraform apply すると、 ESXi 上に OVF テンプレートがアップロードされ、仮想マシンがデプロイされます。
仮想マシンの起動後も Ignition によるセットアップが続行し、再起動後に Terraform 側もデプロイが完了します。

環境やタイミングにもよりますが、デプロイ完了直後は Output から IP アドレスは取得出来ないことが多いです。
これは、open-vm-tools がゲスト情報を取得するのにラグがあり、ESXi に反映されるまでの時間と Terraform のデプロイ完了とのタイミングを合わせられないためです。

$ terraform apply

(snip)

esxi_guest.fcos_guest: Creation complete after 3m22s [id=14]

Apply complete! Resources: 1 added, 0 changed, 0 destroyed.

Outputs:

ip_address =

しばらくしてから terraform refresh する事で Output に反映させます。

$ terraform refresh
data.ct_config.ignition: Refreshing state... [id=2548703694]
esxi_guest.fcos_guest: Refreshing state... [id=14]

Outputs:

ip_address = xxx.xxx.xxx.xxx

ここから IP アドレスなどの情報を用いて SSH させる事が可能なので、Docker コンテナを配備したり、 rke_cluster で Kubernetes クラスタを構築するなど、他の Provisioner に繋げる事が可能です。

まとめ(利点と欠点)

ESXi 自体は、ハードウェア要件さえ合えばどんなマシンにでもインストール出来て無償で利用できるので(最近 Raspberry Pi 4 でも使える Arm 版が出ましたね)、これと Terraform を組み合わせてあらゆる環境の VM の IaC 化が捗るのはとてもおいしいなと思います。

欠点は、ESXi 1台につきプロバイダの設定が 1つ必要となってしまう事で、例えば Kubernetes クラスタ用に同じ構成の VM を複数の ESXi サーバにまとめてデプロイしようとすると、Module をひたすら複製して Proxy Configuration Block を濫用することになります。

理想は for_each を使って表現できれば良かったのですが、Provider 周りは Terraform 実行中に動的に決定出来ないというのが現状の動作のようです。

とは言え、Terraform を使ってオンプレ環境の VM を低コストに管理出来るようになって、個人的には満足しています。
Qiita にこのプロバイダに関する記事が無かったので、もし知らない方が居たら是非試してみてください。

entertvl
投稿は気まぐれ
Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away