Septeni Engineer's Blog

セプテーニエンジニアが綴る技術ブログ

Vagrantのネットワーク周りのあれこれ

はじめまして、新卒エンジニアの大久保です。 セプテーニ・オリジナルに配属されて技術研修や課題も一段落しようやく会社の業務にも慣れてきたといった感じです。

今回、プロジェクトで本番環境と同じ開発環境をチームで共有するために Vagrant を使ったのですが、 ネットワーク周りが曖昧だったので勉強も兼ねて本記事でまとめたいと思います。

はじめに本記事は以下の環境で動作確認を行っております。

Virtual Box : 4.3.12

Vagrant : 1.6.2

 

Vagrantのネットワークについて

f:id:s_hayase:20150722145830p:plain
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"]f:id:s_hayase:20150722145812p:plain プライベートネットワークのイメージ図[/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"]f:id:s_hayase:20150722145827p:plain仮想内部ネットワークのイメージ図[/caption]
この仮想ネットワークはホストOS上に構築され、外部ネットワークからアクセスすることはできません。
またこの設定をすると「ホストオンリーアダプタ」ではなくなるためホストOSとの通信もできなくなります


ポートフォワーディング

VagrantではデフォルトでNAT接続が行われます。これによってゲストOSはホストOSを介して外部のネットワークにアクセスできます。

ですがネットワーク自体は別のため外部ネットワークからゲストOSにアクセスすることはできません。

ポートフォワーディングでは、ホストOSの特定のポートへのアクセスをゲストOSへ転送します。これによって外部ネットワークから実質的にゲストOSへのアクセスを可能にすることができます。
[caption id="attachment_977" align="alignnone" width="500"]f:id:s_hayase:20150722145822p:plainポートフォワーディングのイメージ図[/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"]f:id:s_hayase:20150722150101p:plainパブリックネットワークのイメージ図[/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を変更することで容易に構成を変更することができるため、ネットワークの周りをあまり意識することなく設定することができます。
この機能は便利なのですが、今回ネットワーク周りを調べながらネットワークについて理解せずに機能を使っている部分が多々あるなと感じました。
最近の便利なツールはどんどん活用しながらも基礎をしっかり身につけたエンジニアに慣れるように頑張っていきたいと思った次第です。
今後ともエンジニアブログを投稿していこうと思っているのでよろしくお願いします。

以上、最後までお読みいただきありがとうございました。