LXCで学ぶコンテナ入門 -軽量仮想化環境を実現する技術

第6回 Linuxカーネルのコンテナ機能[5] ─ネットワーク

この記事を読むのに必要な時間:およそ 5.5 分

コンテナに関係する主要な機能2つの説明が済んだので,今回はLXCで使われることが多いネットワーク関連の機能を紹介しましょう。

コンテナとネットワーク名前空間

コンテナでのネットワークの使用と密接に関係するのが第2回で紹介したネットワーク名前空間です。

コンテナでネットワークを使用する場合,一般的にはネットワーク名前空間を作成します。そして,ホスト上に存在するネットワークインターフェースを,作成したネットワーク名前空間に割り当てます。そうすると,ホストや他のコンテナからは見えない,コンテナからだけ見えるネットワークインターフェースとなります。

もちろん,ネットワーク名前空間を作らなくてもコンテナは作れます。しかし,システムコンテナを使う場合,最近はupstartやsystemdといったソケットを使用するinitが使われることが多いので,ネットワーク名前空間をホストと分けておくのが普通です。

特にUpstartの場合はネットワーク名前空間がホストと独立していないと,コンテナで実行した命令がホスト側のinitで受信されてしまうことになるので,LXCのマニュアルにも注意書きがあります。

アプリケーションコンテナの場合は,initを使いませんから,ホストと同じネットワーク名前空間を使用することは考えられます。

ホストのインターフェースの使用

コンテナ用にネットワーク名前空間を作成した場合でも,ホスト上で認識されている物理的なネットワークインターフェースをコンテナに割り当てて使用できます。ただし,その場合はそのインターフェースを使用していないことが条件になります。

つまり同一のホスト上でコンテナを多数起動する場合は,コンテナの数だけホスト上で使っていないインターフェースが必要になります。起動するコンテナの数が少ない場合は,このようにホスト上のインターフェースが直接使えます。しかし,常にコンテナの数だけインターフェースを準備できるケースはあまり一般的ではないので,通常はコンテナでは以下で紹介するような,Linuxカーネルに実装されている仮想的に作成するインターフェースを使い,コンテナにネットワークインターフェースを割り当てます。

veth

vethは元々OpenVZ/Virtuozzoに実装されていた仮想的なネットワークインターフェースです。vethはレイヤー2の仮想ネットワークインターフェースで,vethインターフェースを作成すると,2つのインターフェースがペアで作成され,この2つのインターフェース間で通信が行えます。つまりレイヤー2のトンネリングです。

この作成された2つのインターフェースの片方をホストのネットワーク名前空間に割り当て,片方をコンテナのネットワーク名前空間に割り当てます。図1のように,ホスト側のインターフェースはホスト上に作成したブリッジに接続すると,ホスト外との通信ができるようになります。コンテナ側のインターフェースはコンテナ内で見るとeth0のような通常のネットワークインターフェースとして見えます。

図1 vethインターフェースの接続例

図1 vethインターフェースの接続例

vethを使う時はこのようにホスト上にブリッジを作りますので,ブリッジ上でNATすることも,ホストと同じネットワークに属することも可能で,柔軟に構成できます。

第2回でもネットワーク名前空間を作成しました。しかし作成しただけ終わりましたので,ここでvethインターフェースとネットワーク名前空間を作成して,どう組み合わせて使うのかも体験してみましょう。

ここではiproute2に含まれるipコマンドを使ってvethインターフェースの作成とネットワーク名前空間を操作してみます。

まずはvethペアを作ってみます。ホスト側をveth0-hostコンテナ側をveth0-ctとしましょう。

$ sudo ip link add name veth0-host type veth peer name veth0-ct (vethペアの作成)
$ sudo ip link show
  :(略)
3: veth0-ct: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN qlen 1000
    link/ether be:82:25:d8:94:30 brd ff:ff:ff:ff:ff:ff
4: veth0-host: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN qlen 1000
    link/ether 12:e5:61:4b:42:ba brd ff:ff:ff:ff:ff:ff

インターフェースがペアで生成されていますね。まだネットワーク名前空間は作っていませんが,ここで試しにアドレスを割り当ててみましょう。

$ sudo ip addr add 10.10.10.10/24 dev veth0-host (veth0-hostにアドレス設定)
$ sudo ip addr add 10.10.10.11/24 dev veth0-ct (veth0-ctにアドレス設定)
$ sudo ip link set up veth0-host (veth0-hostをup)
$ sudo ip link set up veth0-ct (veth0-ctをup)
$ sudo ip addr show
  :(略)
3: veth0-ct: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether be:82:25:d8:94:30 brd ff:ff:ff:ff:ff:ff
    inet 10.10.10.11/24 scope global veth0-ct
       valid_lft forever preferred_lft forever
    inet6 fe80::bc82:25ff:fed8:9430/64 scope link 
       valid_lft forever preferred_lft forever
4: veth0-host: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether 12:e5:61:4b:42:ba brd ff:ff:ff:ff:ff:ff
    inet 10.10.10.10/24 scope global veth0-host
       valid_lft forever preferred_lft forever
    inet6 fe80::10e5:61ff:fe4b:42ba/64 scope link 
       valid_lft forever preferred_lft forever

アドレスを割り当てて,インターフェースを有効化しました。ここでpingを実行してみましょう。

$ ping -I veth0-host 10.10.10.11
PING 10.10.10.11 (10.10.10.11) from 10.10.10.11 veth0-host: 56(84) bytes of data.
From 10.10.10.10 icmp_seq=1 Destination Host Unreachable
From 10.10.10.10 icmp_seq=2 Destination Host Unreachable
From 10.10.10.10 icmp_seq=3 Destination Host Unreachable

veth0-hostからveth0-ctpingを実行してみましたが,反応はありません。

ここでネットワーク名前空間の出番です。ipコマンドでnetns01という名前のネットワーク名前空間を作ってみましょう。

$ sudo ip netns add netns01 (ネットワーク名前空間の追加)
$ sudo ip netns list (ネットワーク名前空間の確認)
netns01

netns01という名前でネットワーク名前空間が作成されました。veth0-ctnetns01に移動させてみましょう。

$ sudo ip link set veth0-ct netns netns01 (veth0-ctをnetns01に移動)
$ sudo ip link show | grep veth0
4: veth0-host: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc pfifo_fast state DOWN qlen 1000

移動コマンドを実行した後は,ホスト上で実行したip linkコマンドにはveth0-ctは出てきません。では名前空間netns01内で確認してみます。ip netns exec (名前空間名)で指定したネットワーク名前空間内でコマンドが実行できます。

$ sudo ip netns exec netns01 ip link show
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN 
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
3: veth0-ct: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN qlen 1000
    link/ether be:82:25:d8:94:30 brd ff:ff:ff:ff:ff:ff

ご覧のようにnetns01名前空間へのインターフェースveth0-ctの移動が確認できました。ここで再度veth0-ctにIPアドレスを設定して有効化してみましょう。

$ sudo ip netns exec netns01 ip addr add 10.10.10.11/24 dev veth0-ct
$ sudo ip netns exec netns01 ip link set veth0-ct up
$ sudo ip netns exec netns01 ip addr show
1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN 
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
3: veth0-ct: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP qlen 1000
    link/ether be:82:25:d8:94:30 brd ff:ff:ff:ff:ff:ff
    inet 10.10.10.11/24 scope global veth0-ct
       valid_lft forever preferred_lft forever
    inet6 fe80::bc82:25ff:fed8:9430/64 scope link 
       valid_lft forever preferred_lft forever

無事veth0-ctにIPアドレスが割り当てられ有効になりました。ここで再度ホストからpingを実行してみましょう。

$ ping -I veth0-host 10.10.10.11
PING 10.10.10.11 (10.10.10.11) from 10.10.10.10 veth0-host: 56(84) bytes of data.
64 bytes from 10.10.10.11: icmp_req=1 ttl=64 time=0.134 ms
64 bytes from 10.10.10.11: icmp_req=2 ttl=64 time=0.098 ms
64 bytes from 10.10.10.11: icmp_req=3 ttl=64 time=0.097 ms
  :(略)

先ほどと違ってpingに対して反応がありました。そうです, vethはペアがお互いに異なるネットワーク名前空間に存在しなければ通信ができません

名前空間内のveth0-ctからホスト上のveth0-hostに対してpingを実行しても,同様に反応があります。

$ sudo ip netns exec netns01 ping 10.10.10.10
PING 10.10.10.10 (10.10.10.10) 56(84) bytes of data.
64 bytes from 10.10.10.10: icmp_req=1 ttl=64 time=0.069 ms
64 bytes from 10.10.10.10: icmp_req=2 ttl=64 time=0.068 ms
64 bytes from 10.10.10.10: icmp_req=3 ttl=64 time=0.075 ms

あとはnetns01内でルーティングの設定を行ったり,ホスト上で必要な設定を行えば,名前空間内から外部に対して通信ができるようになります。

著者プロフィール

加藤泰文(かとうやすふみ)

2009年頃にLinuxカーネルのcgroup機能に興味を持って以来,Linuxのコンテナ関連の最新情報を追っかけたり,コンテナの勉強会を開いたりして勉強しています。英語力のない自分用にLXCのmanページを日本語訳していたところ,あっさり本家にマージされてしまい,それ以来日本語訳のパッチを送り続けています。

Plamo Linuxメンテナ。ファーストサーバ株式会社所属。

Twitter:@ten_forward
技術系のブログ:http://d.hatena.ne.jp/defiant/

コメント

コメントの記入