この記事はCyberAgent エンジニア Advent Calendar 2015の8日目の記事です
こんにちは!サイバーエジェント アドテクスタジオ新卒の黒崎 (@kuro_m88) と申します。Dynalystというチームに配属され、一人前のサーバサイドエンジニアになるべく修行をしています(`・ω・´)最近はScalaを書くことが多くて、Sparkで大量のログを集計するバッチの開発をしています。ほぼ100%AWSで構成されているプロダクトなので業務でネットワークの運用もしませんし、構成の事を意識する事はあまりありません。
そんな中でネットワークの事が知りたくなったのは、広告の配信に関わる開発をしてみて、広告の配信の仕組み自体も技術的にめちゃくちゃ面白いんですが、それと同時に自分たちのサーバから広告が表示される端末までの間がどうなってるのか気になってしまったのがきっかけです。学んでいくにはやはり手を動かすのが一番ですよねo(((^^)))o
ということで手軽にネットワーク(特にルーティング)について勉強できそうな環境を作ったので、その紹介をします
今回Dockerを使ったのは、気軽に実験しようと思うと実機はもちろん用意できませんし、ノートPCでVMを立てるにしてもメモリの都合上ルータを10台立てるとかは厳しいけど、最近流行りのコンテナならいけそうな気がしたからです。
仮想マシンを用意する
Ubuntu15.10を使いました。
私の場合はノートPC上にvagrantでVMを用意しました。
VMに割り当てるリソースは、CPU 1~2コア、メモリは1GBあれば足りると思います。
VMに割り当てるリソースは、CPU 1~2コア、メモリは1GBあれば足りると思います。
dockerをインストール
vagrant@vagrant-ubuntu-wily-64:~$ wget -qO- https://get.docker.com/ | sh
バージョンはサーバ、クライアントともに1.9.1でした。
open vSwitchをパッケージからインストールします。
vagrant@vagrant-ubuntu-wily-64:~$ sudo aptitude install openvswitch-common openvswitch-switch
バージョンは2.4.0が入りました。
これだけで環境構築は終わりです。簡単ですね!
こんな感じのネットワークを構築します。
vyOSというオープンソースのルータOSがあって、今回はこれを利用しています。
DockerコンテナはDocker Hubに用意しました。
vyOSが動くDockerコンテナの作り方がきになる方はこちらをご覧ください!
4台欲しいので、vyOSのコンテナを名前を変えて4個作ります。
NICは手動で追加するので、--net=noneをつけます。
vagrant@vagrant-ubuntu-wily-64:~$ sudo docker run -d --name router1 --net=none --privileged -v /lib/modules:/lib/modules kurochan/vyos:1.1.6 /sbin/initvagrant@vagrant-ubuntu-wily-64:~$ sudo docker run -d --name router2 --net=none --privileged -v /lib/modules:/lib/modules kurochan/vyos:1.1.6 /sbin/initvagrant@vagrant-ubuntu-wily-64:~$ sudo docker run -d --name router3 --net=none --privileged -v /lib/modules:/lib/modules kurochan/vyos:1.1.6 /sbin/initvagrant@vagrant-ubuntu-wily-64:~$ sudo docker run -d --name router4 --net=none --privileged -v /lib/modules:/lib/modules kurochan/vyos:1.1.6 /sbin/init
vagrant@vagrant-ubuntu-wily-64:~$ sudo docker psCONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES99a121b7984a kurochan/vyos:1.1.6 "/sbin/init" 2 seconds ago Up 2 seconds router43599cf751e0c kurochan/vyos:1.1.6 "/sbin/init" 8 seconds ago Up 8 seconds router3035e17a8fd43 kurochan/vyos:1.1.6 "/sbin/init" 15 seconds ago Up 14 seconds router266bb97a046c5 kurochan/vyos:1.1.6 "/sbin/init" 21 seconds ago Up 20 seconds router1
スイッチを用意する
ルータのNIC同士を接続するために、スイッチを用意します。
物理機材であれば1つのスイッチに接続してVLANでセグメントを分けたりするのかなと思いますが、仮想スイッチなので、セグメントの数だけ用意してしまいます。
vagrant@vagrant-ubuntu-wily-64:~$ sudo ovs-vsctl add-br switch1vagrant@vagrant-ubuntu-wily-64:~$ sudo ovs-vsctl add-br switch2vagrant@vagrant-ubuntu-wily-64:~$ sudo ovs-vsctl add-br switch3vagrant@vagrant-ubuntu-wily-64:~$ sudo ovs-vsctl add-br switch4
ルータ同士を接続する
さて、ルータとスイッチ用意できましたが、まだルータは接続はおろかNICすら持っていないので何もできません。
ここでopen vSwitchのパッケージに含まれている、ovs-dockerというコマンドを使います。
このコマンド、実体としては約300行程度のシェルスクリプトなのですがとても便利で、Dockerコンテナに対してNICを追加すると同時にIPアドレスとサブネットマスクが設定できて、さらにはvSwitchに接続するところまでできます。
このコマンド、実体としては約300行程度のシェルスクリプトなのですがとても便利で、Dockerコンテナに対してNICを追加すると同時にIPアドレスとサブネットマスクが設定できて、さらにはvSwitchに接続するところまでできます。
各ルータにスイッチとの接続の設定をしていきます。
vagrant@vagrant-ubuntu-wily-64:~$ sudo ovs-docker add-port switch1 eth0 router1 --ipaddress=10.0.1.1/24vagrant@vagrant-ubuntu-wily-64:~$ sudo ovs-docker add-port switch2 eth1 router1 --ipaddress=10.0.2.1/24vagrant@vagrant-ubuntu-wily-64:~$ sudo ovs-docker add-port switch1 eth0 router2 --ipaddress=10.0.1.2/24vagrant@vagrant-ubuntu-wily-64:~$ sudo ovs-docker add-port switch3 eth1 router2 --ipaddress=10.0.3.1/24vagrant@vagrant-ubuntu-wily-64:~$ sudo ovs-docker add-port switch2 eth0 router3 --ipaddress=10.0.2.2/24vagrant@vagrant-ubuntu-wily-64:~$ sudo ovs-docker add-port switch4 eth1 router3 --ipaddress=10.0.4.1/24vagrant@vagrant-ubuntu-wily-64:~$ sudo ovs-docker add-port switch3 eth0 router4 --ipaddress=10.0.3.2/24vagrant@vagrant-ubuntu-wily-64:~$ sudo ovs-docker add-port switch4 eth1 router4 --ipaddress=10.0.4.2/24
間違えてNICを追加してしまった場合はdel-portサブコマンドでNICの削除ができます。
router1からrouter2(10.0.1.2)に向けてpingを打つには、
vagrant@vagrant-ubuntu-wily-64:~$ sudo docker exec -it router1 ping -c 2 10.0.1.2PING 10.0.1.2 (10.0.1.2) 56(84) bytes of data.64 bytes from 10.0.1.2: icmp_req=1 ttl=64 time=0.227 ms64 bytes from 10.0.1.2: icmp_req=2 ttl=64 time=0.058 ms
pingが通りましたね!
では、router1からrouter4(10.0.3.2)にpingを打ってみましょう。
vagrant@vagrant-ubuntu-wily-64:~$ sudo docker exec -it router1 ping -c 2 10.0.3.2connect: Network is unreachable
pingが通りませんね(´・ω・`)
関係をまとめると、以下のようになります。
router1 => router2(10.0.1.2): orouter1 => router3(10.0.2.2): orouter1 => router4(10.0.3.2): xrouter2 => router3(10.0.4.1): xrouter2 => router4(10.0.3.2): orouter3 => router4(10.0.4.2): o
現状ではお隣さんにしかpingが飛ばないようです
ルータ同士はお互いに経路を知らないため、何かしらの方法で教えてあげないといけません。
はじめてのルーティングと言えばstaticルーティングをしてみるのが一般的だと思うのですが、今回は省略します。
ちなみにstaticルーティングは新卒研修でひたすら入力して散々な目に遭いました…手作業って事故ると大変ですよね(´;ω;`)
ちなみにstaticルーティングは新卒研修でひたすら入力して散々な目に遭いました…手作業って事故ると大変ですよね(´;ω;`)
今回はOSPFというプロトコルを使うように各ルータに設定を打ち込んでいきます!
ルータはコンテナなのでdocker execコマンドを使って、コンテナ内で直接vbashというシェルを立ち上げることで設定をします。
最後に設定を反映させるためにcommitしてから設定が消えないようにsaveするのが大切です。
router1に設定するときの例です。
ルータはコンテナなのでdocker execコマンドを使って、コンテナ内で直接vbashというシェルを立ち上げることで設定をします。
最後に設定を反映させるためにcommitしてから設定が消えないようにsaveするのが大切です。
router1に設定するときの例です。
vagrant@vagrant-ubuntu-wily-64:~$ sudo docker exec -it router1 /bin/vbashvbash-4.1# su - vyosvyos@vyos:~$ configure[edit]vyos@vyos# set interfaces loopback lo address 1.1.1.1/32[edit]vyos@vyos# set protocols ospf area 0 network 10.0.0.0/16[edit]vyos@vyos# set protocols ospf parameters router-id 1.1.1.1[edit]vyos@vyos# commit[edit]vyos@vyos# saveSaving configuration to '/config/config.boot'...Done[edit]vyos@vyos# exitexitvyos@vyos:~$ exitlogoutvbash-4.1# exitexit
以下、同様にして他のルータにも設定を入れますが、長くなってしまうのでsetコマンドの部分だけを列挙します。
router1
router1
set interfaces loopback lo address 1.1.1.1/32set protocols ospf area 0 network 10.0.0.0/16set protocols ospf parameters router-id 1.1.1.1
router2
set interfaces loopback lo address 2.2.2.2/32set protocols ospf area 0 network 10.0.0.0/16set protocols ospf parameters router-id 2.2.2.2
router3
set interfaces loopback lo address 3.3.3.3/32set protocols ospf area 0 network 10.0.0.0/16set protocols ospf parameters router-id 3.3.3.3
router4
set interfaces loopback lo address 4.4.4.4/32set protocols ospf area 0 network 10.0.0.0/16set protocols ospf parameters router-id 4.4.4.4
ルーティングテーブルを見てみる
OSPFを使ってルータ同士が経路を交換し始めていれば、ルーティングテーブルになにかが表示されているはずです。
show ip routeコマンドで確認できるようなので、確認してみましょう。
OSPFを使ってルータ同士が経路を交換し始めていれば、ルーティングテーブルになにかが表示されているはずです。
show ip routeコマンドで確認できるようなので、確認してみましょう。
vagrant@vagrant-ubuntu-wily-64:~$ sudo docker exec -it router1 /bin/vbashvbash-4.1# su - vyosvyos@vyos:~$ show ip routeWARNING: terminal is not fully functionalCodes: K - kernel route, C - connected, S - static, R - RIP, O - OSPF,I - ISIS, B - BGP, > - selected route, * - FIB routeC>* 1.1.1.1/32 is directly connected, loO 10.0.1.0/24 [110/10] is directly connected, eth0, 00:05:53C>* 10.0.1.0/24 is directly connected, eth0O 10.0.2.0/24 [110/10] is directly connected, eth1, 00:05:53C>* 10.0.2.0/24 is directly connected, eth1O>* 10.0.3.0/24 [110/20] via 10.0.1.2, eth0, 00:02:23O>* 10.0.4.0/24 [110/20] via 10.0.2.2, eth1, 00:01:33C>* 127.0.0.0/8 is directly connected, lo
それっぽい項目が表示されていますね。
再びpingを打ってみる
再びpingを打ってみる
さきほどpingを打って返ってこなかったケースで試してみます。
vagrant@vagrant-ubuntu-wily-64:~$ sudo docker exec -it router1 ping -c 2 10.0.3.2PING 10.0.3.2 (10.0.3.2) 56(84) bytes of data.64 bytes from 10.0.3.2: icmp_req=1 ttl=63 time=0.363 ms64 bytes from 10.0.3.2: icmp_req=2 ttl=63 time=0.091 ms
おっ!今度はpingが帰ってきました!
念のためさきほどと同じ組み合わせをやってみましょう。
router1 => router2(10.0.1.2): orouter1 => router3(10.0.2.2): orouter1 => router4(10.0.3.2): orouter2 => router3(10.0.4.1): orouter2 => router4(10.0.3.2): orouter3 => router4(10.0.4.2): o
経路が交換できているため、pingが通りました!
もう一台ルーターが追加されると、どんな変化があるのか試してみたいと思います。
構成はこんな感じにします。
以下のコマンドで追加 & 接続ができます。router4のNICも1つ増えます。
vagrant@vagrant-ubuntu-wily-64:~$ sudo docker run -d --name router5 --net=none --privileged -v /lib/modules:/lib/modules kurochan/vyos:1.1.6 /sbin/initvagrant@vagrant-ubuntu-wily-64:~$ sudo ovs-vsctl add-br switch5vagrant@vagrant-ubuntu-wily-64:~$ sudo ovs-docker add-port switch5 eth2 router4 --ipaddress=10.0.5.1/24vagrant@vagrant-ubuntu-wily-64:~$ sudo ovs-docker add-port switch5 eth0 router5 --ipaddress=10.0.5.2/24
コンテナだとすぐ構成が変えられて色々試しやすいですね!
router5
set interfaces loopback lo address 5.5.5.5/32set protocols ospf area 0 network 10.0.0.0/16set protocols ospf parameters router-id 5.5.5.5set protocols ospf default-information originate always
最後に1行だけ他と違う設定を入れてみます。
router1から経路を確認してみると、
vyos@vyos:~$ show ip routeWARNING: terminal is not fully functionalCodes: K - kernel route, C - connected, S - static, R - RIP, O - OSPF, I - ISIS, B - BGP, > - selected route, * - FIB routeO>* 0.0.0.0/0 [110/1] via 10.0.1.2, eth0, 00:01:46 * via 10.0.2.2, eth1, 00:01:46C>* 1.1.1.1/32 is directly connected, loO 10.0.1.0/24 [110/10] is directly connected, eth0, 01:07:55C>* 10.0.1.0/24 is directly connected, eth0O 10.0.2.0/24 [110/10] is directly connected, eth1, 01:07:55C>* 10.0.2.0/24 is directly connected, eth1O>* 10.0.3.0/24 [110/20] via 10.0.1.2, eth0, 01:04:25O>* 10.0.4.0/24 [110/20] via 10.0.2.2, eth1, 01:03:35O>* 10.0.5.0/24 [110/30] via 10.0.1.2, eth0, 00:42:41 * via 10.0.2.2, eth1, 00:42:41C>* 127.0.0.0/8 is directly connected, lo
10.0.5.0/24への経路が増えましたね!
0.0.0.0/0への経路も増えました。デフォルトルートが広報されたようです。
0.0.0.0/0への経路も増えました。デフォルトルートが広報されたようです。
同じ宛先への経路が2つ並んで表示されているのはrouter1からrouter5へのコストが等しい経路が2つあるからです。
デフォルトルートが広報されているので、ルーティングテーブルにマッチしないパケットはすべてrouter5へ吸い込まれます。
router1からネットワーク内に存在しないIPアドレスに向けてtracerouteすると
vyos@vyos:~$ traceroute 10.0.123.123traceroute to 10.0.123.123 (10.0.123.123), 30 hops max, 60 byte packets 1 10.0.2.2 (10.0.2.2) 0.072 ms 0.025 ms 0.014 ms 2 10.0.4.2 (10.0.4.2) 0.055 ms 0.023 ms 0.023 ms 3 10.0.5.2 (10.0.5.2) 0.047 ms !N 0.033 ms !N *
確かにrouter5へ向かっていますね!
最後に
かなり端折って書いてしまいましたが、Dockerで基礎的なネットワークを構築してみた紹介でした。本当はBGPというプロトコルの勉強をして記事にしたかったのですが、検証が間に合わず、、、
ここから先は冬休み?の宿題にしたいと思います(´・ω:;.:…
明日はk_enokiさんです!