Vagrantでは1つのVagrantfileから複数の仮想マシンを起動することができます。この機能を利用すると複数台の仮想マシンのクラスタで構成されるような環境も簡単に構築することができて便利です。
dummy boxで複数VMを作成
複数VMを1つのVagrantfileから作成できるのは便利ですが、dummy boxを利用している場合プロバイダの設定など同じ設定を何度も書いてしまうとVagrantfileが冗長になってしまいます。
例えば、vm01, vm02の2台のVMを起動するVagrantfileはvagrant-cloudstackでは以下のようになります。
vm01, vm02それぞれにプロバイダ・テンプレート・スペックの設定が書かれており非常に長くなっています。vm01, vm02で実際に違いがあるのは名前とポートフォワーディングのポートだけですが把握するのは困難です。
Dotenv.load
Vagrant.configure("2") do |config|
config.ssh.username = "#{ENV['VAGRANT_SSH_USERNAME']}"
config.ssh.private_key_path = "#{ENV['VAGRANT_SSH_PRIVATE_KEY']}"
config.vm.box = "dummy"
config.vm.box_url = "https://github.com/klarna/vagrant-cloudstack/raw/master/dummy.box"
config.vm.define "vm01", primary: true do |vm01|
vm01.vm.provider :cloudstack do |cloudstack, override|
cloudstack.host = "compute.jp-east.idcfcloud.com"
cloudstack.path = "/client/api"
cloudstack.port = "443"
cloudstack.scheme = "https"
cloudstack.api_key = "#{ENV['CLOUDSTACK_API_KEY']}"
cloudstack.secret_key = "#{ENV['CLOUDSTACK_SECRET_KEY']}"
cloudstack.zone_name = "tesla"
cloudstack.template_name = "CentOS 6.5 64-bit for Vagrant"
cloudstack.service_offering_name = "light.S1"
cloudstack.network_type = "Advanced"
cloudstack.network_name = "network1"
cloudstack.name = "vm01"
cloudstack.pf_ip_address_id = "#{ENV['CLOUDSTACK_PF_IP_ADDRESS_ID']}"
cloudstack.pf_public_port = "2201"
override.ssh.port = "2201"
cloudstack.pf_private_port = "22"
cloudstack.keypair = "#{ENV['CLOUDSTACK_SSH_KEYPAIR']}"
end
end
config.vm.define "vm02" do |vm02|
vm02.vm.provider :cloudstack do |cloudstack, override|
cloudstack.host = "compute.jp-east.idcfcloud.com"
cloudstack.path = "/client/api"
cloudstack.port = "443"
cloudstack.scheme = "https"
cloudstack.api_key = "#{ENV['CLOUDSTACK_API_KEY']}"
cloudstack.secret_key = "#{ENV['CLOUDSTACK_SECRET_KEY']}"
cloudstack.zone_name = "tesla"
cloudstack.template_name = "CentOS 6.5 64-bit for Vagrant"
cloudstack.service_offering_name = "light.S1"
cloudstack.network_type = "Advanced"
cloudstack.network_name = "network1"
cloudstack.name = "vm02"
cloudstack.pf_ip_address_id = "#{ENV['CLOUDSTACK_PF_IP_ADDRESS_ID']}"
cloudstack.pf_public_port = "2202"
override.ssh.port = "2202"
cloudstack.pf_private_port = "22"
cloudstack.keypair = "#{ENV['CLOUDSTACK_SSH_KEYPAIR']}"
end
end
end
CLOUDSTACK_API_KEY = 'YOUR_API_KEY'
CLOUDSTACK_SECRET_KEY = 'YOUR_SECRET_KEY'
CLOUDSTACK_PF_IP_ADDRESS_ID = 'YOUR_IP_ADDRESS_ID'
CLOUDSTACK_SSH_KEYPAIR = 'YOUR_KEYPAIR_NAME'
VAGRANT_SSH_USERNAME = 'vagrant'
VAGRANT_SSH_PRIVATE_KEY = 'YOUR_SSH_KEY_PATH'
up, ssh, destroyといったコマンドは基本的に1台の場合と同じです。SSHする際にはVM名を指定します。修正したVagrantfileについてもコマンドは同じなので以降コマンドについての説明は割愛します。
$ vagrant up --provider=cloudstack
$ vagrant ssh vm01
$ vagrant ssh vm02
$ vagrant destroy
共通部分をまとめてみる
vm01とvm02のプロバイダ・テンプレート・スペックは共通なのでまとめてみます。
vm01、vm02の個別の設定が分離されて大分読みやすくなりました。
Dotenv.load
Vagrant.configure("2") do |config|
config.ssh.username = "#{ENV['VAGRANT_SSH_USERNAME']}"
config.ssh.private_key_path = "#{ENV['VAGRANT_SSH_PRIVATE_KEY']}"
config.vm.box = "dummy"
config.vm.box_url = "https://github.com/klarna/vagrant-cloudstack/raw/master/dummy.box"
config.vm.provider :cloudstack do |cloudstack|
cloudstack.host = "compute.jp-east.idcfcloud.com"
cloudstack.path = "/client/api"
cloudstack.port = "443"
cloudstack.scheme = "https"
cloudstack.api_key = "#{ENV['CLOUDSTACK_API_KEY']}"
cloudstack.secret_key = "#{ENV['CLOUDSTACK_SECRET_KEY']}"
cloudstack.zone_name = "tesla"
cloudstack.template_name = "CentOS 6.5 64-bit for Vagrant"
cloudstack.service_offering_name = "light.S1"
cloudstack.network_type = "Advanced"
cloudstack.network_name = "network1"
end
config.vm.define "vm01", primary: true do |vm01|
vm01.vm.provider :cloudstack do |cloudstack, override|
cloudstack.name = "vm01"
cloudstack.pf_ip_address_id = "#{ENV['CLOUDSTACK_PF_IP_ADDRESS_ID']}"
cloudstack.pf_public_port = "2201"
override.ssh.port = "2201"
cloudstack.pf_private_port = "22"
cloudstack.keypair = "#{ENV['CLOUDSTACK_SSH_KEYPAIR']}"
end
end
config.vm.define "vm02" do |vm02|
vm02.vm.provider :cloudstack do |cloudstack, override|
cloudstack.name = "vm02"
cloudstack.pf_ip_address_id = "#{ENV['CLOUDSTACK_PF_IP_ADDRESS_ID']}"
cloudstack.pf_public_port = "2202"
override.ssh.port = "2202"
cloudstack.pf_private_port = "22"
cloudstack.keypair = "#{ENV['CLOUDSTACK_SSH_KEYPAIR']}"
end
end
end
Boxの作成
共通部分をまとめることで大分読みやすくなりました。この共通部分をよく見てみると、プロバイダやテンプレート・スペックといった設定は他のVagrantfileでも使えそうです。そこでこの設定をBox化し再利用できるようにしてみます。
ここでは「idcfcloud_centos_6.5」というBoxを作成します。
まず、Box作成用にディレクトリを作成しておきます。どこでも良いのですが今回はVagrantfileと同じディレクトリにボックス名と同じ名前のディレクトリを作ります。
$ mkdir idcfcloud_centos_6.5
作成したディレクトリの中に以下の2つのファイルを作成します。
Vagrantfileでは先ほどまとめた共通部分の設定内容を指定しています。
Vagrant.configure("2") do |config|
config.vm.provider :cloudstack do |cloudstack|
cloudstack.host = "compute.jp-east.idcfcloud.com"
cloudstack.path = "/client/api"
cloudstack.port = "443"
cloudstack.scheme = "https"
cloudstack.api_key = "#{ENV['CLOUDSTACK_API_KEY']}"
cloudstack.secret_key = "#{ENV['CLOUDSTACK_SECRET_KEY']}"
cloudstack.zone_name = "tesla"
cloudstack.template_name = "CentOS 6.5 64-bit for Vagrant"
cloudstack.service_offering_name = "light.S1"
cloudstack.network_type = "Advanced"
cloudstack.network_name = "network1"
end
end
{
"provider": "cloudstack"
}
作成できたら以下のコマンドで固めてBoxにします。
$ cd idcfcloud_centos_6.5
$ tar cfvz idcfcloud_centos_6.5.box Vagrantfile metadata.json
うまく作成できたらBoxの追加を行います。
$ vagrant box add --name idcfcloud_centos_6.5 idcfcloud_centos_6.5.box
成功すると以下のようなメッセージが表示されます。
==> box: Successfully added box 'idcfcloud_centos_6.5' (v0) for 'cloudstack'!
Boxを使って複数VMを作成する
作成したBoxを利用してVagrantfileを書き直してみます。dummy boxを作成したBoxに書き換え、Boxに記述した共通部分を削除すればOKです。
最初のVagrantfileと比べると大分すっきりしました。Boxの設定はVM毎にできるのでBoxさえ作成しておけば異なる構成のVMからなるクラスタも簡単に記述できます。
Dotenv.load
Vagrant.configure("2") do |config|
config.ssh.username = "#{ENV['VAGRANT_SSH_USERNAME']}"
config.ssh.private_key_path = "#{ENV['VAGRANT_SSH_PRIVATE_KEY']}"
config.vm.box = "idcfcloud_centos_6.5"
config.vm.define "vm01", primary: true do |vm01|
vm01.vm.provider :cloudstack do |cloudstack, override|
cloudstack.name = "vm01"
cloudstack.pf_ip_address_id = "#{ENV['CLOUDSTACK_PF_IP_ADDRESS_ID']}"
cloudstack.pf_public_port = "2201"
override.ssh.port = "2201"
cloudstack.pf_private_port = "22"
cloudstack.keypair = "#{ENV['CLOUDSTACK_SSH_KEYPAIR']}"
end
end
config.vm.define "vm02" do |vm02|
vm02.vm.provider :cloudstack do |cloudstack, override|
cloudstack.name = "vm02"
cloudstack.pf_ip_address_id = "#{ENV['CLOUDSTACK_PF_IP_ADDRESS_ID']}"
cloudstack.pf_public_port = "2202"
override.ssh.port = "2202"
cloudstack.pf_private_port = "22"
cloudstack.keypair = "#{ENV['CLOUDSTACK_SSH_KEYPAIR']}"
end
end
end
まとめ
Boxを使用すると複数台の仮想マシンを1つのVagrantfileから作成する場合にも簡潔な記述で済ますことができます。作成したBoxは他のVagrantfileで再利用できるのでよく使う設定についてはBoxを作成しておくと管理が楽になると思います。
資料
今回作成したVagrantfile等は以下にあります。