Vagrantを用いて書籍のプログラムのネットワーク構成環境を整える
動機
ソースコードで体感するネットワークの仕組み ~手を動かしながら基礎からTCP/IPの実装までがわかるの本を読んでいるが、サンプルコード動かすのに、Vagrant用いて試行錯誤的にネットワーク構成してみた。
- ホストOS .. macOS X
- ゲストOS(複数台とも) .. ubuntu16.04
第2章 仮想IPホストプログラム
事前にサンプルプログラム1をダウンロードしておく。
Vagrantでは、NATのネットワーク(デフォルトのネットワークアドレスは10.0.2.0/24
)がデフォルトで構成されていて、10.0.2.2
がルータとして、すでに配置されているので、一番単純に構成するならば、
Vagrant.configure("2") do |config|
config.vm.box = "ubuntu/trusty64"
config.vm.synced_folder ".", "/home/vagrant/test"
config.vm.provider :virtualbox do |vb|
# change 10.0.2.0/24 with what you want
# See also https://www.virtualbox.org/manual/ch09.html#changenat
vb.customize ['modifyvm', :id, '--natnet1', '192.168.111.0/24']
end
end
となる。vb.customize ..
の部分は、デフォルトの10.0.2.0/24
ネットワークを変更しに行っている:
$ route
Kernel IP routing table
Destination Gateway Genmask Flags Metric Ref Use Iface
default 192.168.111.2 0.0.0.0 UG 0 0 0 eth0
192.168.111.0 * 255.255.255.0 U 0 0 0 eth0
IP-TTL=64
device=eth0
# ホストOS: `ip a`のeth0ネットワークインターフェース。
vmac=08:00:27:16:16:86
vip=192.168.111.15
vmask=255.255.255.0
# `route | grep default` or `netstat -rn`でGenmaskが0.0.0.0のやつ or `ip route` のdefaultの行
gateway=192.168.111.2
で「とりあえずは」OK。(./MyEth.iniはサンプルプログラムの構成ファイル)
ゲスト側OS(ubuntu)で、ping 8.8.8.8
をうつと、192.168.111.2
を経由して、8.8.8.8(googleのDNS)に疎通する2
自力でroutingできるようにする
課題点
上で基本的にOKだと思うんだけど、複数台のゲストOSに対しては、この構成は本質的に問題がある。というのは、NATのネットワークはゲストOSごとにネットワークを構成するので、
ゲストOSは複数台構成しても同じIPアドレスになってしまっているから。http://zorinos.seesaa.net/article/450304938.html のNATの図が非常にわかりやすい。
やりたいこととしては、client PCでping 8.8.8.8
すると、master PC(デフォルトゲートウェイとして機能)の192.168.111.2
を経由して3、8.8.8.8
に疎通させたい。
そのためには以下のような構成(内部ネットワーク)にする。
Vagrant.configure("2") do |config|
config.vm.define "master" do |conf|
conf.vm.box = "ubuntu/trusty64"
conf.vm.network "private_network", ip: "192.168.111.2", virtualbox__intnet: "mynet"
end
config.vm.define "client" do |conf|
conf.vm.box = "ubuntu/trusty64"
conf.vm.network "private_network", ip: "192.168.111.100", virtualbox__intnet: "mynet"
conf.vm.synced_folder ".", "/home/vagrant/test"
end
end
Note) 複数のゲストOSにvirtualbox__intnet
で同名を指定すると、内部ネットワークが構成できる。このネットワークはホストOS(MacOS X)から見えない。
ホストOS(macOS X)からifconfig
してもvboxnetのnetwork interfaceが見えないこことで確認可能だ。4
この後、clientのPC(192.168.111.100
)に対して、192.168.111.2
をデフォルトゲートウェイとするために、masterのマシンを自力でrouterにする必要がある。
(clientのPCは複数台構成可能で、そうしたい場合は、Vagrantfileでclient0
, client1
として、ipアドレスを一意にした上で、client
の設定と同じように書けば良さそう。
$ vagrant ssh client
$ traceroute 8.8.8.8
traceroute to 8.8.8.8 (8.8.8.8), 30 hops max, 60 byte packets
1 10.0.2.2 (10.0.2.2) 0.298 ms 0.819 ms 0.553 ms
2 192.168.150.1 (192.168.150.1) 58.173 ms 58.104 ms 59.045 ms
...
10 108.170.238.85 (108.170.238.85) 7.513 ms 72.14.236.129 (72.14.236.129) 7.435 ms 209.85.143.49 (209.85.143.49) 7.364 ms
11 google-public-dns-a.google.com (8.8.8.8) 7.398 ms 7.326 ms 7.916 ms
ということで10.0.2.2
のrouterがdefault gatewayになっている。route
コマンドでもわかるけど。(VM同士はpingで疎通可能になっている)
今の状態から、sudo route add default gw 192.168.111.2 && sudo route del default gw 10.0.2.2
としてdefault gatewayを変更しても、192.168.111.100
のPC(master)には、routing設定がされていないため、routingできない。(つまり、ping 8.8.8.8
が応答しない)
そこで、自力でmasterのPCをroutingできるようにしよう。
ルータ化する
とは言っても基本的には、http://maruchan-shiro123.hatenablog.com/entry/2015/04/05/181854 の通りにすれば良い。いくつか変更した点をば。
-
SNATの部分は、
sudo iptables -t nat -A POSTROUTING -o eth0 -s 192.168.111.0/24 -j MASQUERADE
として、sオプションを明示的にしるしたほうが良さそう。 -
client側のPCのデフォルトゲートウェイを変更する。つまり、
Vagrant.configure("2") do |config|
# snip
config.vm.define "client" do |conf|
conf.vm.box = "ubuntu/trusty64"
conf.vm.network "private_network", ip: "192.168.111.100", virtualbox__intnet: "mynet"
conf.vm.synced_folder "../eth", "/home/vagrant/test"
# see also https://www.vagrantup.com/docs/networking/public_network.html#default-router
gw = "192.168.111.2"
conf.vm.provision "shell",
run: "always",
inline: "route add default gw #{gw}"
conf.vm.provision "shell",
run: "always",
inline: "eval `route -n | awk '{ if ($8 ==\"eth0\" && $2 != \"0.0.0.0\") print \"route del default gw \" $2; }'`"
end
# snip
end
と変更する。
Note) route add default gw ...
とかはVMの再起動時に情報失われるので、run: "always"
としている。
以上のように設定すると、clientでのping 8.8.8.8
がgatewayの192.168.111.2
を経由して通る。traceroute 8.8.8.8
で確認すると、
traceroute to 8.8.8.8 (8.8.8.8), 30 hops max, 60 byte packets
1 192.168.111.2 (192.168.111.2) 0.278 ms 0.209 ms 0.168 ms
2 * * *
3 * * *
4 ... プロバイダのipアドレス
...
11 google-public-dns-a.google.com (8.8.8.8) 18.878 ms 19.249 ms 12.319 ms
みたいな感じになる。5
Note)
2,3が* * *
は、本当は、
2 10.0.2.2 (10.0.2.2) 0.217 ms 0.178 ms 0.058 ms
3 ルータ名 (192.168.10.221) 2.500 ms 2.952 ms 3.110 ms
みたいな感じなんだけど、フォワードの方向しかping許していないので、アスタリスク表示になる。
確認取れたので、
IP-TTL=64
device=eth1
# `ip a`でeth1インタフェースを確認して所用のMACアドレスに変更する。
vmac=08:00:27:e0:6a:24
vip=192.168.111.100
vmask=255.255.255.0
gateway=192.168.111.2
でプログラムを動かすと良い。
第3章: UDP通信に対応させ、DHCPクライアント機能を実装しよう
これは、素直に
Vagrant.configure("2") do |config|
config.vm.box = "ubuntu/trusty64"
# If err, see also the issue #3083, https://github.com/hashicorp/vagrant/issues/3083
config.vm.network :private_network, type: "dhcp", ip: "192.168.111.0"
config.vm.synced_folder ".", "/home/vagrant/test"
end
で良いと思う6。
sudo grep -R "DHCPOFFER" /var/log/*
すると、DHCP serverの在り処が192.168.111.2
とわかる。
ホストOSでifconfig
とすると、192.168.111.1
となっているのがわかる。
$ ifconfig
vboxnet0: flags=8943<UP,BROADCAST,RUNNING,PROMISC,SIMPLEX,MULTICAST> mtu 1500
ether 0a:00:27:00:00:00
inet 192.168.111.1 netmask 0xffffff00 broadcast 192.168.111.255
ゲストOSのデフォルトゲートウェイはroute
で確認すると、10.0.2.2
となっている。
TODO) 今回は必要なかったが、ついでにDHCPサーバーを自力で構成するのもやってみたい
第4章: TCPの基本機能を追加しよう
これは、第2章のネットワーク構成と全く同じなので、そのままでよさそう。
感想
そもそも、ネットワーク自体しっかり理解していない部分も多かったので、結構時間がかかってしまったが、結果的には、自力でのネットワーク構築、nat, iptablesとかがわかって得るものが多いと感じた。
-
http://gihyo.jp/book/2018/978-4-7741-9744-9/support#supportDownload にある ↩
-
traceroute 8.8.8.8
で詳細を確かめられる ↩ -
この後、natネットワークのルータ
10.0.2.2
を経由する。その後、ホストOS(MAC OS X)の "en0: Wi-Fi (AirPort)"のネットワークのルータを経由する。 ↩ -
virtualbox__intnet
なしだと、clientのネットワークがhostonly networkになるので、ホストOS(macOS X)からifconfig
すると、vboxnet
のネットワークインターフェースがあらわれると思います。 ↩ -
todo: iptablesの設定を変更すれば良さそう ↩
-
自分は途中で、
A host only network interface you're attempting to configure via DHCP
の文言のエラーが出てしまったので、https://github.com/hashicorp/vagrant/issues/3083 みて解決した ↩