Mac
OSX
vagrant

Vagrantで複数環境を立ち上げる際、IPアドレスの割当やポートフォワードを全て自動化する

More than 3 years have passed since last update.

以前の記事で Vagrant+Docker(Provider)を使って複数の環境を立ち上げた が、管理するVagrantfileが増えて行くにつれ、各環境のIPアドレスや設定したポートが分からなくなり、新しい環境を立ち上げる際にポートやIPアドレスがブッキングすることが出てきた。

この問題を解消するべく、どうにかVagrantの機能を使って、IPアドレスの管理とポートフォワードを自動化する方法を試したのでメモ。


環境


  • Mac OSX Yosemite 10.10.2

  • Vagrant 1.7.2

  • VirtualBox 4.3.26


やりたいこと


  • Vagrantfile毎にIPアドレスを自動で割り振りたい

  • ポートフォワードも自動で設定したい


  • /etc/hosts にホスト名は自動で設定したい

  • NFSを使って共有ディレクトリをマウントしたい


Vagrantfileの設定


IPアドレス割り当ての自動化

VMのネットワーク設定をプライベートネットワークとし、type: "dhcp" とすることでDHCPによるIPアドレスの割り当てができる。

デフォルトのネットワークアドレスが微妙だったので、ソースコードを読んでみたところ DHCPのネットワークアドレスや、IPアドレスの割当範囲も設定できる ようだったので、こちらも設定。

node.vm.network :private_network, id: "default-network", type: "dhcp", ip: "192.168.34.0"

192.168.34.xxx のネットワークで自動割り当てがされるように。

もし割当範囲を変えたい場合、dhcp_lower: "192.168.34.10", dchp_upper: "192.168.34.50" といった具合に設定を追加すればよい。


ポートフォワードの自動化

コレはとても簡単。

ポートフォワードの設定に auto_correct: true を設定するだけ。

config.vm.network :forwarded_port, guest: 22, host: 2222, id: "ssh", auto_correct: true

これでSSH用のポートがぶつかったら、Vagrantがよしなにしてくれる


/etc/hosts ファイルの自動更新

これは以前も使っていた vagrant-hostupdater プラグインで対応出来ると思ったら、このプラグインはDHCPでの割り当てには対応していないということが判明。

急遽代替プラグインを探していたら、vagrant-hostmanger というプラグインを発見。

このプラグインはIPリゾルバにクロージャを設定することができ、VMから割り当てられたIPアドレスを無理矢理引っ張ってくることが出来るという優れもの。

以下のような記述を加えることで、無事 /etc/hosts も自動更新ができるように。

config.hostmanager.enabled = true

config.hostmanager.manage_host = true
config.hostmanager.ip_resolver = proc do |vm, resolving_vm|
ip_address = ''
if hostname = (vm.ssh_info && vm.ssh_info[:host])
vm.communicate.execute("/sbin/ifconfig eth1 | grep 'inet addr' | tail -n 1 | egrep -o '[0-9\.]+' | head -n 1 2>&1") do |type, contents|
ip_address = contents.split("\n").first
end
end
ip_address
end

上記のIPアドレスを取得している箇所 vm.communicate.execute("/sbin/ifconfig eth1 | grep 'inet addr' | tail -n 1 | egrep -o '[0-9\.]+' | head -n 1 2>&1") は、ゲストマシンの種類や環境によって変わると思うので、参考までに。

vm.communicate というメソッドが便利で、システムコールで vagrant ssh -c ... で実行しようとしてた部分を割とシンプルに記載できた。


NFSでのディレクトリ共有

これは現状のVagrantだと複数環境でNFSマウントを利用しようとすると、最後に起動した環境しか正しくディレクトリがマウントされないという状態に陥るため、Vagrant側から/etc/exportsを変更することをやめ、手動で/etc/exportsを設定するように している。

というわけで現時点では手動管理とし、/etc/exports にDHCPのネットワークを追記。

/srv -network 192.168.34.0 -mask 255.255.255.0 -alldirs -mapall=501:20

VagrantfileにもSynced Folderを設定

config.vm.synced_folder "/srv", "/var/www/html/", type: "nfs", nfs_export: false, mount_options: ["nolock", "vers=3", "udp"]

問題なく /srv 以下のディレクトリがNFSでマウントできることを確認。


できあがったVagrantfile

こんな感じになった。

Vagrant.configure(2) do |config|

config.hostmanager.enabled = true
config.hostmanager.manage_host = true

config.vm.define "development.local" do |node|
node.vm.box = "dduportal/boot2docker"

node.vm.network :private_network, id: "default-network", type: "dhcp", ip: "192.168.34.1", dhcp_lower: "192.168.34.3", dhcp_upper: "192.168.34.254"
node.vm.network :forwarded_port, guest: 22, host: 2222, id: 'ssh', auto_correct: true

node.hostmanager.ip_resolver = proc do |vm, resolving_vm|
ip_address = ''
if hostname = (vm.ssh_info && vm.ssh_info[:host])
vm.communicate.execute("/sbin/ifconfig eth1 | grep 'inet addr' | tail -n 1 | egrep -o '[0-9\.]+' | head -n 1 2>&1") do |type, contents|
ip_address = contents.split("\n").first
end
end
ip_address
end

node.hostmanager.aliases = ["development.local"]
node.ssh.insert_key = false

node.vm.synced_folder "/srv", "/var/www/html/", type: "nfs", nfs_export: false, mount_options: ["nolock", "vers=3", "udp"]
end
end


問題点

Macなどホストマシンを再起動した場合に1つの問題が発生。

全てのVMのIPアドレスが、DHCPにより 起動順に再度割り当てられてしまう ため、IPアドレスに対するホスト名の記述が被ってしまう。

## vagrant-hostmanager-start id: {id}

192.168.34.3 test1.local
## vagrant-hostmanager-end

## vagrant-hostmanager-start id: {id}
192.168.34.3 test2.local
## vagrant-hostmanager-end

これは vagrant-hostmanager が仮想マシンの updestroy の時にのみ /ect/hosts ファイルを書き換える動作を行うため、再起動後に各マシンを vagrant up しないと、最新の情報に書き換えてくれないからだ。

しかしこの状態だと、例えば開発環境(プロキシVM用のVagrantfile)が10個あったとすると、再起動後に全ての環境をいちいち vagrant up しないと、どこかでホストのIPアドレスがぶつかる可能性があり、とても面倒。

結局のところ、これを解決できるプラグインを発見することはできなかったこと、vagrant-hostmanager は既に開発がストップしており、作者がPullRequestにも反応していない状況から自分でやるしかないと判断し、プラグインを改造してみた。


改造版vagrant-hostmanager

下記のリポジトリに公開した。

改造版vagrant-hostmanager

注意

ダウンロードしただけでは利用できないので、自前でGemとしてBuildして、ローカルからインストールする必要があるので注意。


改造内容

改造版では、以下のオプションをサポートした。

vagrant hostmanager --cleanhost

--cleanhost オプションを付けて実行することで、vagrant-hostmanager が登録したホスト設定を一括してクリアするように。

こうすることでマシンの再起動後に上記コマンドを1回実行すれば、その後は必要なマシンだけを vagrant up できる。/etc/hosts に設定されたIPアドレスが被っているかを気にする必要は無くなる。

また、本家では vagrant reload の際には /etc/hosts の書き換えをしてくれなかったので、vagrant reload の際にも書き換えをするようにフックを追加してみた。

一応、機を見てPullRequestしてみようと思うけれど、作者が放置気味なので、改造しつつ自前でビルドして使っていくのが一番良いのかもしれない。