Edited at

TerraformでvSphereのVMを作成する

More than 1 year has passed since last update.

今回は完全オンプレです。

あんまり需要はないと思われますが全然情報が転がってなかったので公開します。

たぶんオンプレだとVMWare使ってる人多いですよね。

今回はうちがvsphereを使っていて環境構築するのにこれを操作するチームがボトルネックになってるのを解消したいがためにTerraformを使いました。


Terraform

vSphereのプロバイダがデフォルトで用意されています。

非常に便利です。

ただしほぼインスタンスの管理以外には使えません。

対応してるのフォルダとVMとファイルと仮想ディスクだけだし。


構成

├── README.md

├── chef # Chef関連のファイルを置いてます
│   └── attributes # ChefのAttributesをJSONファイルで格納する場所
│   └── default.json
├── modules # Module置き場
│   └── instance # インスタンス(これしか管理してない)
│   ├── instance.tf # 一番キモ
│   ├── outputs.tf
│   ├── variables.tf # 変わりそうにない変数定義はここで。適当にファイル分割してます。
│   ├── variables_chef.tf
│   └── variables_network.tf
├── sample.tf # サンプルのVMインスタンス
├── variables.tf # 共通の変数定義
└── vsphere.tf # vsphereの変数定義


設定


vsphere.tf

別にファイル名は何でもいいんですが。

とりあえずvcenterに接続するための情報をここで定義しときます。

別に分割しなくても1ファイルで管理しても構いません。


vsphere.tf

variable "vsphere_user" { }

variable "vsphere_password" { }

variable "vsphere_server" { }

provider "vsphere" {
user = "${var.vsphere_user}"
password = "${var.vsphere_password}"
vsphere_server = "${var.vsphere_server}"

allow_unverified_ssl = true
}


ここら辺の接続情報は多少センシティブなので実行するサーバの環境変数で値を定義してます。


sample.tf

module "SAMPLE01" {

source = "./modules/instance"
vm_name = "SAMPLE01"
cpu = 1
memory = 512
front_ip = "192.168.9.10"
front_label = "${var.network_front["ap"]}"
back_ip = "192.168.10.10"
back_label = "${var.network_back["ap"]}"
storage = "${var.datastore["storage1"]}"
}

これが作成するVMの定義です。

大体ほとんど同じような記述になるので、Moduleを使って共通化しています。

必要なところだけ変数にして渡してる感じです。

ネットワークインターフェースを2つ固定で付けるようにしています。


Module

VMインスタンスの定義自体大量に同じようなのが量産されるのでModuleを使いました。

Moduleについては公式ドキュメントを見てください。

コアな部分はこのinstance.tfが担っています。


instance.tf

resource "vsphere_virtual_machine" "vm" {

name = "${var.vm_name}"
vcpu = "${var.cpu}"
memory = "${var.memory}"

datacenter = "${var.vcenter["datacenter"]}"
cluster = "${var.vcenter["cluster"]}"
dns_servers = "${var.dns}"
time_zone = "${var.server["timezone"]}"
domain = "${var.server["domain"]}"

network_interface {
ipv4_address = "${var.front_ip}"
label = "${var.front_label}"
ipv4_gateway = "${var.network["gateway_fr"]}"
ipv4_prefix_length = "${var.network["prefix_len"]}"
}
network_interface {
ipv4_address = "${var.back_ip}"
label = "${var.back_label}"
ipv4_prefix_length = "${var.network["prefix_len"]}"
}

disk {
template = "${var.vcenter["template"]}"
datastore = "${var.storage}"
bootable = true
type = "thin"
}

# Provisioning
## Chef Bootstrap
provisioner "chef" {
attributes_json = "${file(var.chef_options["attribute_file"])}"
run_list = "${var.chef_run_list}"

# Static Configs
node_name = "${self.name}"
environment = "${var.chef_server["environment"]}"
server_url = "${var.chef_server["url"]}"
user_name = "${var.chef_server["user"]}"
user_key = "${file(var.chef_server["key"])}"
ssl_verify_mode = "${var.chef_options["ssl_verify"]}"
http_proxy = "${var.chef_options["proxy"]}"
https_proxy = "${var.chef_options["proxy"]}"
version = "${var.chef_options["version"]}"
client_options = "${var.chef_other_option}"
secret_key = "${file(var.chef_options["data_bag_secret"])}"
log_to_file = true
recreate_client = true
}

# ssh connection
connection {
type = "ssh"
host = "${self.network_interface.1.ipv4_address}"
user = "hoge"
private_key = "${file(var.server["ssh_key"])}"
}
}

variable "vm_name" {}
variable "cpu" {
default = 2
}
variable "memory" {
default = 2048
}
variable "front_ip" {}
variable "back_ip" {}
variable "front_label" {}
variable "back_label" {}
variable "storage" {}


variables*.tfに色々変数定義してます。

ほとんどどのサーバも変わらないはずなのでサーバによって変わるものはsample.tfで渡すようにしています。


diskについて

ここはtemplateが鬼門でした。

vsphereのテンプレート使えると思ってたんだけどなぜかNot Foundで使えず…。

指定の仕方知ってる人いたら教えてください。

TEMPLATE01みたいなリファレンスインスタンス作ってそいつの名前を指定するようにしました。


connectionについて

これがクッソ便利でした。

provisionerはこのサンプルではchefしかないのですが、それ以外のremote-execとかで他の管理サーバーとかに情報をプッシュしたい場合とかにユーザーとか鍵は同じままでhostだけ変えたいって場合、冗長に書かなくていいんです。

書いたところだけ上書き。

provisioner 'remote-exec' {

host "another-server"
}

connection {
host "default-server"
user "default-user"
}


provisioner chefについて

今回ネットワークインターフェースを2本にしてたせいで設定間違えてChefの認証が最後だけ通らないとかハマりまくってたんですが、結局そこのIPが違うってのに気付いて解決しました。

まあ普通はハマらないッス。


運用環境

VM増やしたいときはsample.tfに新しくmodule追加したりファイル増やしたりして追加します。

provisionerとかほとんどAttributesとrun_listくらいしか変わらないのでこれでいいんです。

これでVM作るのが楽になりました。

ありがとうございます。