この記事はLinux Advent Calendar 2014の9日目の記事です。
ネットワークを使う機能でなにかしらテストしたいときに複数のクライアントが欲しい時がありますよね。大量アクセスをしたい場合はjmeterとかありますが、クライアントのIPアドレスも複数あったほうが良いケースもあると思います。kvm等でクライアントを複数作ってbridgeするという方法もありますが、それはちょっと重量級なのでもうちょい手軽な方法がないかなーというところです。 そこでお手軽な方法はなにかというところでネットワークネームスペース(netns)を使って見たいと思います。
ネットワークネームスペースとはなんぞや?という方はten_forwardさんがgihyo.jpで連載している「LXCで学ぶコンテナ入門 -軽量仮想化環境を実現する技術」の「第6回 Linuxカーネルのコンテナ機能[5] ─ネットワーク」が参考になると思います。
まず名称を決めたいと思います。ネットワークネームスペースに参加している方をゲスト、デフォルトのネットワークネームスペースに参加している方をホストと呼んでいきます。 ちなみに、テストした環境はkvmのゲストなので適当な図で書くと↓のような感じになってます。
kvm host ----------------|---- -------------------- hostbr0 -------------------- host-veth ---------|----------- guest-veth 192.168.11.3/24 | 192.168.122.149/24 | 192.168.122.150/24
kvmのネットワークは192.168.122.0/24です。hostbr0はkvmゲストで作ったbridgeです。host-vethとguest-vethはvethでこの2個はペアになってます。
今回やりたいのはクライアントに対してIPアドレスを個別に振りたいのでNATではなくてbridgeを使います。 では、まずはbridgeを作ります。
hostbr0というbridge作成。
[root@dockertest ~]# ip link add hostbr0 type bridge
bridgeをlink upします。
[root@dockertest ~]# ip link set hostbr0 up
物理nicもlink upします。
[root@dockertest ~]# ip link set ens3 up
作成したbridgeにnic追加します。brctl addifと同じです。
[root@dockertest ~]# ip link set dev ens3 master hostbr0
bridgeの確認してみます。
[root@dockertest ~]# bridge link show 2: ens3 state UP : <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 master hostbr0 state forwarding priority 32 cost 19
bridgeにipアドレス設定
[root@dockertest ~]# ip addr add 192.168.122.149/24 dev hostbr0
デフォルトルートの設定
[root@dockertest ~]# ip route add default via 192.168.122.1
[root@dockertest ~]# ping -c4 192.168.11.3 PING 192.168.11.3 (192.168.11.3) 56(84) bytes of data. 64 bytes from 192.168.11.3: icmp_seq=1 ttl=64 time=0.558 ms 64 bytes from 192.168.11.3: icmp_seq=2 ttl=64 time=0.361 ms 64 bytes from 192.168.11.3: icmp_seq=3 ttl=64 time=0.411 ms 64 bytes from 192.168.11.3: icmp_seq=4 ttl=64 time=0.370 ms
ここまででnamespaceを特に設定していないLinux環境にてbrdigeの設定ができたので、次にネットワークネームスペースを作り、テスト用クライアントにIPアドレスを降ってみたいと思います。
最初にvethを作成します。guest-vethがこれから作るネームスペースに入ります。
[root@dockertest ~]# ip link add host-veth type veth peer name guest-veth
host-vethをhostbr0に追加します。
root@dockertest ~]# ip link set dev host-veth master hostbr0
追加できたことを確認しましょう。
[root@dockertest ~]# bridge link show 2: ens3 state UP : <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 master hostbr0 state forwarding priority 32 cost 19 6: host-veth state DOWN : <BROADCAST,MULTICAST> mtu 1500 master hostbr0 state disabled priority 32 cost 2
ネットワークネームスペースの確認。何も表示されないのでデフォルト以外はありません。
[root@dockertest ~]# ip netns
testnsというネームスペースを作ります。
[root@dockertest ~]# ip netns add testns
guest-vethをtestnsに所属させます。
[root@dockertest ~]# ip link set guest-veth netns testns
testnsにguest-vethが存在するか確認。
root@dockertest ~]# ip netns exec testns ip link 1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN mode DEFAULT group default link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 5: guest-veth: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000 link/ether 22:e4:31:f1:a8:f9 brd ff:ff:ff:ff:ff:ff
ipコマンドでnetnsを指定しながら操作するのが面倒なのでネットワークネームスペースをtestnsに指定してbashを起動します。
[root@dockertest ~]# ip netns exec testns bash
本当にtestnsに入っているか確認。ちゃんとtestnsにいます。
[root@dockertest ~]# ip a 1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 5: guest-veth: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN group default qlen 1000 link/ether 22:e4:31:f1:a8:f9 brd ff:ff:ff:ff:ff:ff
guest-vethにipを振ります。
[root@dockertest ~]# ip addr add 192.168.122.150/24 dev guest-veth
guest-vethをlink up。
[root@dockertest ~]# ip link set guest-veth up
デフォルトゲートウェイを設定。
[root@dockertest ~]# ip route add default via 192.168.122.1
tesutnsの環境からhostbr0に対してpingを実行
[root@dockertest ~]# ping -c 2 192.168.122.149 PING 192.168.122.149 (192.168.122.149) 56(84) bytes of data. 64 bytes from 192.168.122.149: icmp_seq=1 ttl=64 time=0.147 ms 64 bytes from 192.168.122.149: icmp_seq=2 ttl=64 time=0.061 ms --- 192.168.122.149 ping statistics --- 2 packets transmitted, 2 received, 0% packet loss, time 1000ms rtt min/avg/max/mdev = 0.061/0.104/0.147/0.043 ms
[root@dockertest ~]# ping -c 2 192.168.11.3 PING 192.168.11.3 (192.168.11.3) 56(84) bytes of data. 64 bytes from 192.168.11.3: icmp_seq=1 ttl=64 time=0.630 ms 64 bytes from 192.168.11.3: icmp_seq=2 ttl=64 time=0.342 ms --- 192.168.11.3 ping statistics --- 2 packets transmitted, 2 received, 0% packet loss, time 1001ms
そうしたらkvmホスト側でhttpサーバを起動してみてアクセスログでどのIPからリクエストが来たか確認しましょう。
まずはデフォルトネームスペース側から。IPは192.168.122.149になるはずです。
[root@dockertest ~]# ip -4 a l 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever 3: docker0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default inet 172.17.42.1/16 scope global docker0 valid_lft forever preferred_lft forever 4: hostbr0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue state UP group default inet 192.168.122.149/24 scope global hostbr0 valid_lft forever preferred_lft forever [root@dockertest ~]# curl http://192.168.11.3:8080/index.html hello, world
サーバ側のログで192.168.122.149からのアクセスが確認できます。
masami@saga:~/test$ python3 -m http.server 8080 Serving HTTP on 0.0.0.0 port 8080 ... 192.168.122.149 - - [07/Dec/2014 12:08:36] "GET /index.html HTTP/1.1" 200 -
次にtesnsから実行します。
[root@dockertest ~]# ip netns exec testns bash [root@dockertest ~]# ip -4 a l 5: guest-veth: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000 inet 192.168.122.150/24 scope global guest-veth valid_lft forever preferred_lft forever [root@dockertest ~]# curl http://192.168.11.3:8080/index2.html hello, world
サーバ側のログでindex2.htmlへ192.168.122.150からアクセスが来てますね。期待通りです( ´∀`)bグッ!
masami@saga:~/test$ python3 -m http.server 8080 Serving HTTP on 0.0.0.0 port 8080 ... 192.168.122.149 - - [07/Dec/2014 12:08:36] "GET /index.html HTTP/1.1" 200 - 192.168.122.150 - - [07/Dec/2014 12:10:41] "GET /index2.html HTTP/1.1" 200 -
ipコマンドとネットワークネームスペースを使うことで比較的簡単にクライアントを作れました。
p.s. Linux Kernel側でのnamespaceの実装についてはこちらに資料を上げてあります。
- 作者: 小俣 光之
- 出版社/メーカー: 技術評論社
- 発売日: 2011/07/09
- メディア: 単行本(ソフトカバー)
- 購入: 4人 クリック: 130回
- この商品を含むブログ (9件) を見る