はじめに
この記事は 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 仮想マシンを直接デプロイできるプロバイダです。
何をしてくれるのかと言うと:
- VMware ESXi を導入したサーバに対し
- このプロバイダを介して直接 SSH 接続し
-
vim-cmd
などのコマンドを実行して仮想マシン諸々の管理をしてくれます
このプロバイダの利点は __vSphere を介さずに動作するため、ESXi 単体で(無償ライセンスの範疇で)利用できる__という点です。
プロバイダの性質的には terraform-provider-libvirt
と似ていると思います。
ただ、気を付けなければいけない点として、ESXi サーバの SSH 接続が有効でなければ使用できないので、安全性を含めて使用には注意が必要だと思います。
もう少し詳細な解説
通常、無償ライセンスで ESXi を使うには少し苦労する点があります。
ESXi 自体は有償・無償のライセンスがあり、無償版では API による仮想マシンなどのリソースの新規作成などが制限されているため、
単体で仮想マシンを作成するには Web の GUI クライアントか、直接 SSH 接続したうえで vim-cmd
や esxcli
などを叩く必要があります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-cmd
や esxcli
を SSH 接続して代わりに実行してくれるので、
API を介さずに ESXi 単体で仮想マシンやネットワークの構成を自動化出来るような仕組みになっています。
さらに詳細な使い方は README や Wiki を一読しましょう。
というわけで、この記事では実際に 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 も依存関係に追加します。
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 クライアント上でリソースの作成権限があるユーザ情報を入力してください
provider "esxi" {
esxi_hostname = "esxi.example.com"
esxi_username = "username"
esxi_password = "password"
}
provider "ct" {}
esxi_guest リソースの定義
esxi_guest
で、仮想マシンリソースのプロパティを定義します。
-
ovf_source
に先程ダウンロードした VM イメージを指定します -
esxi_guest
のdisk_store
やnetwork_interfaces.virtual_network
は環境ごとに異なります - その他スペックについては環境に合わせて調整してください
-
guestos
には、ESXi や Fusion 使用する OS の識別子をこの辺とかを参考に指定します
(FCOS の OVF テンプレートが RHEL 扱いとなっており、ESXi が警告を出すので上書きしてます)
-
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
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
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 にこのプロバイダに関する記事が無かったので、もし知らない方が居たら是非試してみてください。