SDN開発エンジニアを目指した活動ブログ

〜SDNなオープンソース製品を実際に使って試してみる〜

Docker環境で、MPLS-VPNネットワークを体験してみる

今回は、巷で流行りのDockerのネタです。
以前より、Dockerを活用すれば、SDN技術要素を習得するための自前SDNラボ環境を簡易に構築することが可能となるので、ぜひ習得しておきたい技術だと考えておりました。
そんな折に、たまたま、過去の沖縄オープンラボラトリのイベント企画で、第2回ハンズオンセミナー(SDN編)が開催されたことに気がつきました。ハンズオンのタイトルは、すばり「SDN編/Dockerで箱庭実験ネットワークを作ろう」とのこと。公開情報が、こちらです。www.okinawaopenlabs.org

というこので、ここでのハンズオン資料などを参考にさせていただきながら、自前SDNラボ環境を構築してみます。

▪️まずは、SDNラボ環境ネタをどうするか...

あまり在り来たりな素材だとモチベーションが停滞してしまいます。
そこで、Docker活用事例として、過去に前例のないSDN技術要素ということで、SDNと親和性が高いMPLSネットワーク環境を構築したいと思います。さらに、RyuBGPSpeakerやLagopusSwitchといったオープンソースを活用することも視野に入れて、SDNラボ環境を検討していきます。あと、以前、SlideShareで公開したmpBGP/MPLS-VPNプロトコル動作を簡単に体験できる環境も考慮に入れたいところです。

www.slideshare.net

▪️Docker-simpleRouter環境構築メモ

これまでのブログ記事でも題材に取り上げてきたBGP版OpenFlow簡易ルータ(通称:simpleRouter)をベースにDocker化に着手することとしました。github.com

まずは、UbuntuへのDockerインストールですが、こちらは、前出のハンズオンを思いっきり参考にさせて頂きました。(^_^;)

$ git clone https://github.com/ttsubo/docker-simpleRouter.git
$ cd docker-simpleRouter
$ ./simpleRouter.sh install
... snip
ubuntu:14.04.2: The image you are pulling has been verified. Important: image verification is a tech preview feature and should not be relied on to provide security.
Digest: sha256:cc15bd0f821cdecf7d7346211fbb4f9c4a0f32d29259f1fe57c87cabb9ce26b4
Status: Downloaded newer image for ubuntu:14.04.2

インストール後は、一度ログアウトして再ログインします。
(dockerグループへの所属を反映させるため)

$ docker version
Client version: 1.6.0
Client API version: 1.18
Go version (client): go1.4.2
Git commit (client): 4749651
OS/Arch (client): linux/amd64
Server version: 1.6.0
Server API version: 1.18
Go version (server): go1.4.2
Git commit (server): 4749651
OS/Arch (server): linux/amd64

Docker-Hubから、Dockerイメージを取得します。
まずは、simpleRouteイメージ本体から...
こちらは、BGP面を構成するBGPルータ想定したDockerイメージになります。

$ docker pull ttsubo/simple-router:latest
...snip
Digest: sha256:aecd207cc4390b345b6840db45099253edd4c8b8a8330ecee0ecd6f8a1f97c61
Status: Downloaded newer image for ttsubo/simple-router:latest

つぎに、pc-termイメージを取得します。
こちらは、BGP面に接続するPC端末を想定したDockerイメージになります。

$ docker pull ttsubo/pc-term:latest
...snip
Digest: sha256:6924f979906b3576ead6fff55020516f303e9fd83ba33d8d38f040cd9621ef7e
Status: Downloaded newer image for ttsubo/pc-term:latest

最後に、test-serverイメージを取得します。
こちらは、BGPルータ監視用に活用します。

$ docker pull ttsubo/test-server:latest
...snip
Digest: sha256:0f916b800b4fae5bfa8973366588299cfeab75ceae628ed020adba225e146d90
Status: Downloaded newer image for ttsubo/test-server:latest

Dockerイメージの取得が完了したので、いちおう内容を確認しておきます。

$ docker images
REPOSITORY             TAG                 IMAGE ID            CREATED             VIRTUAL SIZE
ttsubo/simple-router   latest              d713bbabb51a        23 hours ago        844.7 MB
ttsubo/test-server     latest              fc3db66f9ef8        25 hours ago        506.8 MB
ttsubo/pc-term         latest              7559c9022200        26 hours ago        253.6 MB
ubuntu                 14.04.2             07f8e8c5e660        5 days ago          188.3 MB

以上で、環境構築は終了です。

▪️早速、Dockerを動かしてみる

Docker環境の起動用スクリプトを実行するだけです。
5分程度待つと、9つのDockerコンテナが自動生成されて必要なトポロジ情報も設定されます。

$ ./simpleRouter.sh start
76472b045e38724cb0dd5c4dcaeb8df79a50248147ddaed01aedbbe076f7549e
[sudo] password for tsubo: 
a6cf21d3fcf0114350e767e51d42febaf8ab2d5e86e12cfcca1bcf366ce6ac26
92ec4528d4a87fae3d609f889a8890935569d47078c6a35168fd9038668b0fec
cb110daaf7bfe2e2b18f5e217591cee8cca5804f886c3060532b5dc0e740589e
4d597bb57e13f35965d91e6924ca5e1a7464a7b61adaadc15fb920395d640245
7ea4819f81212a6d96fe5fce4bec8f7f13f5c36a52218c6072adcf909de913c2
b73eb44a1998606122666cbc6fd1849ebc27acfc8f1634dbd34c5f4e9222a5f8
45e6942c3516d869ce54786db9dcbeb69cfafb87e62672ff215cc6562dd4004d
237a076d04f90253cef3533ad06d98beb2186e4110fa71dacdb8ab6b0dfce46f
####################
start BGP1 ...
####################
2015-05-06 07:53:43,601 - ryu.base.app_manager - INFO - loading app openflowRouter.py
2015-05-06 07:53:43,936 - ryu.base.app_manager - INFO - loading app ryu.controller.ofp_handler
2015-05-06 07:53:43,941 - ryu.base.app_manager - INFO - creating context wsgi
2015-05-06 07:53:43,941 - ryu.base.app_manager - INFO - instantiating app None of SimpleMonitor
2015-05-06 07:53:43,954 - ryu.base.app_manager - INFO - creating context monitor
2015-05-06 07:53:43,955 - ryu.base.app_manager - INFO - instantiating app None of SimpleBGPSpeaker
2015-05-06 07:53:43,956 - ryu.base.app_manager - INFO - creating context bgps
2015-05-06 07:53:43,956 - ryu.base.app_manager - INFO - instantiating app openflowRouter.py of OpenflowRouter
2015-05-06 07:53:43,961 - ryu.base.app_manager - INFO - instantiating app ryu.controller.ofp_handler of OFPHandler
2015-05-06 07:53:43,964 - ryu.lib.hub - INFO - (79) wsgi starting up on http://0.0.0.0:8080/
2015-05-06 07:53:46,470 - ryu.lib.hub - INFO - (79) accepted ('127.0.0.1', 57391)
2015-05-06 07:53:46,490 - bgpspeaker.api.base - INFO - API method core.start called with args: {'router_id': '10.0.1.1', 'label_range': (100, 199), 'waiter': <ryu.lib.hub.Event object at 0x7f40af45a090>, 'local_as': 65011, 'bgp_server_port': 179, 'refresh_max_eor_time': 0, 'refresh_stalepath_time': 0}
2015-05-06 07:53:46,775 - ryu.lib.hub - INFO - 127.0.0.1 - - [06/May/2015 07:53:46] "POST /openflow/0000000000000001/bgp HTTP/1.1" 200 260 0.302049
2015-05-06 07:53:51,971 - ryu.lib.hub - INFO - (79) accepted ('127.0.0.1', 57392)
2015-05-06 07:53:51,977 - bgpspeaker.api.base - INFO - API method neighbor.create called with args: {'connect_mode': 'both', 'remote_as': 65010, 'cap_mbgp_vpnv6': False, 'cap_mbgp_vpnv4': True, 'cap_mbgp_ipv6': False, 'is_next_hop_self': True, 'cap_mbgp_ipv4': True, 'multi_exit_disc': 100, 'is_route_server_client': False, 'peer_next_hop': None, 'password': None, 'ip_address': '192.168.101.101'}
2015-05-06 07:53:51,981 - ryu.lib.hub - INFO - 127.0.0.1 - - [06/May/2015 07:53:51] "POST /openflow/0000000000000001/interface HTTP/1.1" 200 459 0.007098
.
..snip

Dockerコンテナを確認してみます

$ docker ps
CONTAINER ID        IMAGE                         COMMAND             CREATED             STATUS              PORTS               NAMES
237a076d04f9        ttsubo/test-server:latest     "/bin/bash"         7 minutes ago       Up 7 minutes                            TestServer          
45e6942c3516        ttsubo/simple-router:latest   "/bin/bash"         7 minutes ago       Up 7 minutes                            BGP6                
b73eb44a1998        ttsubo/simple-router:latest   "/bin/bash"         7 minutes ago       Up 7 minutes                            BGP5                
7ea4819f8121        ttsubo/simple-router:latest   "/bin/bash"         7 minutes ago       Up 7 minutes                            BGP4                
4d597bb57e13        ttsubo/simple-router:latest   "/bin/bash"         7 minutes ago       Up 7 minutes                            BGP3                
cb110daaf7bf        ttsubo/simple-router:latest   "/bin/bash"         7 minutes ago       Up 7 minutes                            BGP2                
92ec4528d4a8        ttsubo/simple-router:latest   "/bin/bash"         7 minutes ago       Up 7 minutes                            BGP1                
a6cf21d3fcf0        ttsubo/pc-term:latest         "/bin/bash"         7 minutes ago       Up 7 minutes                            pc2                 
76472b045e38        ttsubo/pc-term:latest         "/bin/bash"         7 minutes ago       Up 7 minutes                            pc1

Dockerコンテナが正しく動作すると、こんな感じのトポロジ構成が自動構築されます。
f:id:ttsubo:20150506172710j:plain

▪️基本動作を確認してみる

Docker起動が完了したら、新たなターミナルからDockerコンテナにアクセスしてみます。
以降、Docker環境を起動したターミナルを使用してしまうとデバック情報などの標準出力が割り込まれてしまい可読性が低下してしまいます。ご注意ください。
まずは、PC1のコンテナに入ってみて、PC2に宛にping疎通を行ってみます。

$ docker exec -it pc1 bash
root@pc1:/# ping 192.168.2.101
PING 192.168.2.101 (192.168.2.101) 56(84) bytes of data.
64 bytes from 192.168.2.101: icmp_seq=1 ttl=64 time=38.1 ms
64 bytes from 192.168.2.101: icmp_seq=2 ttl=64 time=51.8 ms
64 bytes from 192.168.2.101: icmp_seq=3 ttl=64 time=30.2 ms
64 bytes from 192.168.2.101: icmp_seq=4 ttl=64 time=40.4 ms
64 bytes from 192.168.2.101: icmp_seq=5 ttl=64 time=30.2 ms
^C
--- 192.168.2.101 ping statistics ---
5 packets transmitted, 5 received, 0% packet loss, time 4007ms
rtt min/avg/max/mdev = 30.230/38.175/51.809/7.965 ms

次に、PC1が直結されたBGP3のコンテナに入ってみて、show-ribを確認してみます。
PC2宛の通信は、ネクストホップとしてBGP1経由のルーティング経路が選定されている様子が確認できます。

$ docker exec -it BGP3 bash
root@BGP3:~# cd simpleRouter/rest-client/
root@BGP3:~/simpleRouter/rest-client# ./get_rib.sh 
======================================================================
get_rib
======================================================================
/openflow/0000000000000001/rib
----------
reply: 'HTTP/1.1 200 OK\r\n'
header: Content-Type: application/json; charset=UTF-8
header: Content-Length: 459
header: Date: Wed, 06 May 2015 08:06:01 GMT
+++++++++++++++++++++++++++++++
2015/05/06 08:06:01 : Show rib 
+++++++++++++++++++++++++++++++
Status codes: * valid, > best
Origin codes: i - IGP, e - EGP, ? - incomplete
     Network                          Labels   Next Hop             Reason          Metric LocPrf Path
 *>  65010:101:192.168.2.101/32       [600]    192.168.105.101      Only Path       100    100    65010 ?
 *>  65010:101:192.168.1.102/32       [300]    0.0.0.0              Only Path                     ?

さらに、BGP1をコンテナ停止させてみて、直後に、PC1のコンテナから再度、ping疎通を実行してみます。すると、しばらくの間は、ping疎通が失敗してしまいますが、数十秒後に、ping疎通が成功するようになります。

$ docker kill BGP1
BGP1
$ docker exec -it pc1 bash
root@pc1:/# ping 192.168.2.101
PING 192.168.2.101 (192.168.2.101) 56(84) bytes of data.
64 bytes from 192.168.2.101: icmp_seq=33 ttl=64 time=35.9 ms
64 bytes from 192.168.2.101: icmp_seq=34 ttl=64 time=38.8 ms
64 bytes from 192.168.2.101: icmp_seq=35 ttl=64 time=37.4 ms
64 bytes from 192.168.2.101: icmp_seq=36 ttl=64 time=34.7 ms
64 bytes from 192.168.2.101: icmp_seq=37 ttl=64 time=36.0 ms
^C
--- 192.168.2.101 ping statistics ---
37 packets transmitted, 5 received, 86% packet loss, time 36080ms
rtt min/avg/max/mdev = 34.770/36.627/38.837/1.401 ms
root@pc1:/# exit

再度、BGP3のコンテナからshow-ribを確認してみます。
PC2宛の通信は、ネクストホップとしてBGP2経由のルーティング経路が選定されている様子が確認できます。

$ docker exec -it BGP3 bash
root@BGP3:~# cd simpleRouter/rest-client/
root@BGP3:~/simpleRouter/rest-client# ./get_rib.sh 
======================================================================
get_rib
======================================================================
/openflow/0000000000000001/rib
----------
reply: 'HTTP/1.1 200 OK\r\n'
header: Content-Type: application/json; charset=UTF-8
header: Content-Length: 459
header: Date: Wed, 06 May 2015 08:12:31 GMT
+++++++++++++++++++++++++++++++
2015/05/06 08:12:31 : Show rib 
+++++++++++++++++++++++++++++++
Status codes: * valid, > best
Origin codes: i - IGP, e - EGP, ? - incomplete
     Network                          Labels   Next Hop             Reason          Metric LocPrf Path
 *>  65010:101:192.168.2.101/32       [600]    192.168.106.101      Only Path       200    100    65010 ?
 *>  65010:101:192.168.1.102/32       [300]    0.0.0.0              Only Path                     ?

ひととおり、MPLS-VPNが正しく動作していることが確認できたので、Docker環境を停止します。
このあたりの操作感については、Immutable Infrastructureな体験が実感できて、ナイスです。

$ ./simpleRouter.sh stop
...snip

▪️おわりに

今回は、Docker環境を活用すれば、面倒な設定手順をスキップしてお手軽に、MPLS-VPNが体験できることが確認できました。