以前の記事で 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 が仮想マシンの up
と destroy
の時にのみ /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してみようと思うけれど、作者が放置気味なので、改造しつつ自前でビルドして使っていくのが一番良いのかもしれない。