はじめまして、新卒エンジニアの大久保です。 セプテーニ・オリジナルに配属されて技術研修や課題も一段落しようやく会社の業務にも慣れてきたといった感じです。
今回、プロジェクトで本番環境と同じ開発環境をチームで共有するために Vagrant を使ったのですが、 ネットワーク周りが曖昧だったので勉強も兼ねて本記事でまとめたいと思います。
はじめに本記事は以下の環境で動作確認を行っております。
Virtual Box : 4.3.12
Vagrant : 1.6.2
Vagrantのネットワークについて
Vagrantのネットワークはシンプルに作られています。
物理的なネットワークを想像していただければわかるように、実際のネットワークはスイッチングハブやルータなどネットワークを構成するさまざまな機器を意識しなければいけません。
仮に仮想マシンでもそれらのネットワーク構成を意識しなければならないとしたら、簡単に仮想マシンを使うことはできないでしょう。
そこで仮想化ソフトウェア(VitualBox)では簡単にネットワークの構成を設定することができる以下の様なネットワーク機能が提供されています。
ホストオンリーアダプタ
仮想ネットワークインターフェイスを作成し、ホストOSとゲストOSの間での閉じたネットワークを形成できる。ゲストOSとホストOSでのみの通信なのでゲストOS間の通信などはできない。
NAT
ゲストOSからホストOSを介して外部のネットワークに接続することができる。外部ネットワークからゲストOSへはアクセスできないため、ゲストOSのセキュリティ上の安全を保つことができる。
ブリッジアダプタ
ゲストOSがホストOSと同じネットワークを使用できる。ホストOSとは別の独立したマシンのようにネットーワーク上では存在する。外部ネットワークにさらされる状況もホストOSと同じなためセキュリティを考慮する必要がある。
これらのVitualBoxのネットワーク機能をVagrantでは目的に応じてより簡単に利用することができます。 機能には大きく3つあります。
プライベートネットワーク | ホストOSとゲストOS間でのみ通信が行える |
ポートフォワーディング | ホストOSへの特定のポートを使った接続をゲストOSに転送する |
パブリックネットワーク | 同一ネットワーク内のどの端末からでもゲストOSと通信が行える |
プライベートネットワーク
[caption id="attachment_979" align="alignnone" width="500"] プライベートネットワークのイメージ図[/caption]プライベートネットワークの設定を行えば、ホストOSとゲストOS間のみで有効なネットワークを構築することができます。
普通にローカルで開発を進める場合はこの設定のみでも十分かもしれません。特に設定しなければ標準で「ホストオンリーアダプタ」での接続になります。
では実際にターミナル上で試してみましょう。
まず何の設定も行っていないゲストOSのネットワーク環境は以下の様な状態です。
[vagrant@localhost ~]$ ifconfig eth0 Link encap:Ethernet HWaddr **:**:**:**:**:** inet addr:10.0.2.15 Bcast:10.0.2.255 Mask:255.255.255.0 inet6 addr: fe80::a00:27ff:fe62:52b8/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:651 errors:0 dropped:0 overruns:0 frame:0 TX packets:388 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:61970 (60.5 KiB) TX bytes:50131 (48.9 KiB) lo Link encap:Local Loopback inet addr:127.0.0.1 Mask:255.0.0.0 inet6 addr: ::1/128 Scope:Host UP LOOPBACK RUNNING MTU:16436 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:0 (0.0 b) TX bytes:0 (0.0 b)
プライベートネットワークを設定するためにVagrantfileを以下のようにします。
VAGRANTFILE_API_VERSION = "2" Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| config.vm.box = "test_box" config.vm.network "private_network", ip: "192.168.33.10" end
設定を反映させるためにVagrantを再起動してもう一度ゲストOSを確認してみましょう。
[vagrant@localhost ~]$ ifconfig eth0 Link encap:Ethernet HWaddr **:**:**:**:**:** inet addr:10.0.2.15 Bcast:10.0.2.255 Mask:255.255.255.0 inet6 addr: fe80::a00:27ff:fe62:52b8/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:410 errors:0 dropped:0 overruns:0 frame:0 TX packets:283 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:43124 (42.1 KiB) TX bytes:34174 (33.3 KiB) eth1 Link encap:Ethernet HWaddr **:**:**:**:**:** inet addr:192.168.33.10 Bcast:192.168.33.255 Mask:255.255.255.0 inet6 addr: fe80::a00:27ff:fe46:91a0/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:1 errors:0 dropped:0 overruns:0 frame:0 TX packets:8 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:167 (167.0 b) TX bytes:552 (552.0 b) lo Link encap:Local Loopback inet addr:127.0.0.1 Mask:255.0.0.0 inet6 addr: ::1/128 Scope:Host UP LOOPBACK RUNNING MTU:16436 Metric:1 RX packets:0 errors:0 dropped:0 overruns:0 frame:0 TX packets:0 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:0 RX bytes:0 (0.0 b) TX bytes:0 (0.0 b)
Vagrantfileで設定したIP(192.168.33.10)で新たな仮想ネットワークインターフェイス(eth1)が追加されていることがわかります。 実際にホストOSとゲストOS間でPingも双方向で通ることが確認できます。
・ホストOSからゲストOS(192.168.33.10)へのping
$ ping 192.168.33.10 PING 192.168.33.10 (192.168.33.10): 56 data bytes 64 bytes from 192.168.33.10: icmp_seq=0 ttl=64 time=0.423 ms
・ゲストOSからホストOS(192.168.43.153)へのping
[vagrant@localhost ~]$ ping 192.168.43.153 PING 192.168.0.4 (192.168.0.4) 56(84) bytes of data. 64 bytes from 192.168.0.4: icmp_seq=1 ttl=63 time=0.221 ms
また、Vagrantfileのネットワーク設定にvirtualbox__intnetを指定することでゲストOS同士の仮想内部ネットワークを構築することもできます。
以下では2つのゲストOS(test_aとtest_b)を用意して動作を確認しています。
・ゲストOS:test_aのVagrantfile
VAGRANTFILE_API_VERSION = "2" Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| config.vm.box = "test_box" config.vm.network "private_network", ip: "192.168.33.50", virtualbox__intnet: "test_net" end
・ゲストOS:test_bのVagrantfile
VAGRANTFILE_API_VERSION = "2" Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| config.vm.box = "test_box" config.vm.network "private_network", ip: "192.168.33.60", virtualbox__intnet: "test_net" end
virtualbox__intnetによってゲストOSが接続可能な内部仮想ネットワークを構築し、そこに接続されているゲストOS同士では通信が行えるようになります。
Pingによって通信が確立できていることも確認できます。
・test_bからtest_a(192.168.33.50)へのping
[vagrant@vagrant-centos65 ~]$ ping 192.168.33.50 PING 192.168.33.50 (192.168.33.50) 56(84) bytes of data. 64 bytes from 192.168.33.50: icmp_seq=1 ttl=64 time=2.50 ms
・test_aからtest_b(192.168.33.60)へのping
[vagrant@vagrant-centos65 ~]$ ping 192.168.33.60 PING 192.168.33.60 (192.168.33.60) 56(84) bytes of data. 64 bytes from 192.168.33.60: icmp_seq=1 ttl=64 time=0.722 ms
内部仮想ネットワークのイメージは以下のようになります。
[caption id="attachment_978" align="alignnone" width="500"]仮想内部ネットワークのイメージ図[/caption]
この仮想ネットワークはホストOS上に構築され、外部ネットワークからアクセスすることはできません。
またこの設定をすると「ホストオンリーアダプタ」ではなくなるためホストOSとの通信もできなくなります。
ポートフォワーディング
VagrantではデフォルトでNAT接続が行われます。これによってゲストOSはホストOSを介して外部のネットワークにアクセスできます。ですがネットワーク自体は別のため外部ネットワークからゲストOSにアクセスすることはできません。
ポートフォワーディングでは、ホストOSの特定のポートへのアクセスをゲストOSへ転送します。これによって外部ネットワークから実質的にゲストOSへのアクセスを可能にすることができます。
[caption id="attachment_977" align="alignnone" width="500"]ポートフォワーディングのイメージ図[/caption]
実際に試してみましょう。
ポートフォワーディングのVagrantfileは以下のような設定になります。
VAGRANTFILE_API_VERSION = "2" Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| config.vm.box = "testpack" config.vm.network "forwarded_port", guest: 80, host: 8080 end
networkに"forwarded_port"を設定しゲストOS(転送先)のポートとホストOS(転送元)のポートを指定するだけでポートフォワーディングの設定を有効にできます。
この設定でVagrantを再起動することで、ホストOSのポート8080へのアクセスがゲストOSのポート80へ転送されるようになります。
$ lsof -i :8080 COMMAND PID USER FD TYPE DEVICE SIZE/OFF NODE NAME VBoxHeadl 98320 y_okubo 26u IPv4 0xa79e6f4cf52d0eed 0t0 TCP *:http-alt (LISTEN)
lsofコマンドで調べてみると実際にホストOSのポート8080がLISTENになっていることが確認できます。
ゲストOSのポート80でWebサーバを起動していれば、
http://localhost:8080/
にアクセスすることでサーバーにアクセスすることができます。
また、ホストOSの属しているネットワーク上の他のPCからも
http://[ホストOSのIP]:8080/
でゲストOSに直接アクセスすることができます。
パプリックネットワーク
これは先に説明したVirtualBoxのブリッジアダプタに相当するものです。ホストOSと同じネットワーク上にあたかも独立しているかのように存在し、ネットワーク上の外部機器と通信を行うことができます。
[caption id="attachment_974" align="alignnone" width="500"]パブリックネットワークのイメージ図[/caption]
パプリックネットワークのVagratfileは以下のようになります。
VAGRANTFILE_API_VERSION = "2" Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| config.vm.box = "test_box" config.vm.network :public_network, :bridge => "en0: Wi-Fi (AirPort)" end
networkに"public_network"を設定し、bridgeにWi-Fiを設定しています。
この状態でVagrantを起動することでパブリックネットワークを自動で構築してくれます。
またbridgeを設定しなかった場合はVagrantの起動時にどのネットワークインターフェイスを使用するかを対話的に訊いてくれるので、そこで選択することも可能です。
ゲストOSに新たに追加されたネットワークは以下で確認することができます。
[vagrant@vagrant-centos65 ~]$ ifconfig eth1 eth1 Link encap:Ethernet HWaddr **:**:**:**:**:** inet addr:192.168.43.31 Bcast:192.168.43.255 Mask:255.255.255.0 inet6 addr: fe80::a00:27ff:fec7:dd9e/64 Scope:Link UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1 RX packets:83 errors:0 dropped:0 overruns:0 frame:0 TX packets:64 errors:0 dropped:0 overruns:0 carrier:0 collisions:0 txqueuelen:1000 RX bytes:9756 (9.5 KiB) TX bytes:16264 (15.8 KiB)
ゲストOSへは192.168.43.31でアクセスすることができます。このIPはDHCPによって割り当てられたものです。
パブリックネットワークはホストOS上の仮想マシンをネットワーク上で独立したマシンのように扱うことができます。そのためクローズドなネットワーク内であれば自由度が高く何かと便利な設定だと言えます。ですがその分セキュリティリスクは高くなるため、公衆無線LANなどで接続する場合は使えないでしょう。
※VagratfileでIPを指定することでDHCPではなく固定IPを割り当てることができる仕様があるらしいです。自分の環境でも試した結果、確かにeth1に固定IPが割り当てられることは確認できました。ですがそのIPに対して外部ネットワークからアクセスすることはできず、動作を検証することはできませんでした。
まとめ
VagrantではVagrantfileの設定を変更することでプライベートネットワーク、ポートフォワーディング、パブリックネットワークの各設定を容易に変更することができます。またネットワーク構成に関してはどれか一つしか使えないというわけではなく、[プライベートネットワーク+ポートフォワーディング]など環境に応じて柔軟に対応することができます。
ネットワークの設定に関しては他にも細かい設定ができるようなので、公式ドキュメントなどを読んでみるのもいいかもしれません。
感想
Vagrantのネットワーク設定はVagrantfileを変更することで容易に構成を変更することができるため、ネットワークの周りをあまり意識することなく設定することができます。この機能は便利なのですが、今回ネットワーク周りを調べながらネットワークについて理解せずに機能を使っている部分が多々あるなと感じました。
最近の便利なツールはどんどん活用しながらも基礎をしっかり身につけたエンジニアに慣れるように頑張っていきたいと思った次第です。
今後ともエンジニアブログを投稿していこうと思っているのでよろしくお願いします。
以上、最後までお読みいただきありがとうございました。