コンテナに関係する主要な機能2つの説明が済んだので、今回はLXCで使われることが多いネットワーク関連の機能を紹介しましょう。
コンテナとネットワーク名前空間
コンテナでのネットワークの使用と密接に関係するのが第2回で紹介したネットワーク名前空間です。
コンテナでネットワークを使用する場合、一般的にはネットワーク名前空間を作成します。そして、ホスト上に存在するネットワークインターフェースを、作成したネットワーク名前空間に割り当てます。そうすると、ホストや他のコンテナからは見えない、コンテナからだけ見えるネットワークインターフェースとなります。
もちろん、ネットワーク名前空間を作らなくてもコンテナは作れます。しかし、システムコンテナを使う場合、最近はupstartやsystemdといったソケットを使用するinitが使われることが多いので、ネットワーク名前空間をホストと分けておくのが普通です。
特にUpstartの場合はネットワーク名前空間がホストと独立していないと、コンテナで実行した命令がホスト側のinitで受信されてしまうことになるので、LXCのマニュアルにも注意書きがあります。
アプリケーションコンテナの場合は、initを使いませんから、ホストと同じネットワーク名前空間を使用することは考えられます。
ホストのインターフェースの使用
コンテナ用にネットワーク名前空間を作成した場合でも、ホスト上で認識されている物理的なネットワークインターフェースをコンテナに割り当てて使用できます。ただし、その場合はそのインターフェースを使用していないことが条件になります。
つまり同一のホスト上でコンテナを多数起動する場合は、コンテナの数だけホスト上で使っていないインターフェースが必要になります。起動するコンテナの数が少ない場合は、このようにホスト上のインターフェースが直接使えます。しかし、常にコンテナの数だけインターフェースを準備できるケースはあまり一般的ではないので、通常はコンテナでは以下で紹介するような、Linuxカーネルに実装されている仮想的に作成するインターフェースを使い、コンテナにネットワークインターフェースを割り当てます。
veth
vethは元々OpenVZ/Virtuozzoに実装されていた仮想的なネットワークインターフェースです。vethはレイヤー2の仮想ネットワークインターフェースで、vethインターフェースを作成すると、2つのインターフェースがペアで作成され、この2つのインターフェース間で通信が行えます。つまりレイヤー2のトンネリングです。
この作成された2つのインターフェースの片方をホストのネットワーク名前空間に割り当て、片方をコンテナのネットワーク名前空間に割り当てます。図1のように、ホスト側のインターフェースはホスト上に作成したブリッジに接続すると、ホスト外との通信ができるようになります。コンテナ側のインターフェースはコンテナ内で見るとeth0のような通常のネットワークインターフェースとして見えます。
vethを使う時はこのようにホスト上にブリッジを作りますので、ブリッジ上でNATすることも、ホストと同じネットワークに属することも可能で、柔軟に構成できます。
第2回でもネットワーク名前空間を作成しました。しかし作成しただけ終わりましたので、ここでvethインターフェースとネットワーク名前空間を作成して、どう組み合わせて使うのかも体験してみましょう。
ここではiproute2に含まれるip
コマンドを使ってvethインターフェースの作成とネットワーク名前空間を操作してみます。
まずはvethペアを作ってみます。ホスト側をveth0-host
、コンテナ側をveth0-ct
としましょう。
インターフェースがペアで生成されていますね。まだネットワーク名前空間は作っていませんが、ここで試しにアドレスを割り当ててみましょう。
アドレスを割り当てて、インターフェースを有効化しました。ここでping
を実行してみましょう。
veth0-host
からveth0-ct
にping
を実行してみましたが、反応はありません。
ここでネットワーク名前空間の出番です。ip
コマンドでnetns01
という名前のネットワーク名前空間を作ってみましょう。
netns01
という名前でネットワーク名前空間が作成されました。veth0-ct
をnetns01
に移動させてみましょう。
移動コマンドを実行した後は、ホスト上で実行したip link
コマンドにはveth0-ct
は出てきません。では名前空間netns01
内で確認してみます。ip netns exec (名前空間名)
で指定したネットワーク名前空間内でコマンドが実行できます。
ご覧のようにnetns01
名前空間へのインターフェースveth0-ct
の移動が確認できました。ここで再度veth0-ct
にIPアドレスを設定して有効化してみましょう。
無事veth0-ct
にIPアドレスが割り当てられ有効になりました。ここで再度ホストからping
を実行してみましょう。
先ほどと違ってping
に対して反応がありました。そうです、 vethはペアがお互いに異なるネットワーク名前空間に存在しなければ通信ができません 。
名前空間内のveth0-ct
からホスト上のveth0-host
に対してping
を実行しても、同様に反応があります。
あとはnetns01
内でルーティングの設定を行ったり、ホスト上で必要な設定を行えば、名前空間内から外部に対して通信ができるようになります。
macvlan
ホストと同じネットワークにコンテナを接続する場合、macvlanというインターフェースが使えます。
macvlanは、既に存在するeth0
のような物理的なインターフェースに、新たにMACアドレスを持つ仮想的なインターフェースを作ります。言ってみれば、1つのインターフェースに複数のMACアドレスを割り当てられる機能です。そして、新たに割り当てたMACアドレスを持つ仮想的なインターフェースが作成されます。
LinuxではIPエイリアスと言って、1つのインターフェースに複数のIPアドレスを割り当てることができます。しかし、この機能ではMACアドレスは全て同じになり、DHCPでアドレスを割り当てることはできません。
一方、macvlanはMACアドレスを持ちますので、DHCPでアドレスを割り当てることが可能です。
macvlanが設定されたインターフェースでは、本来のMACアドレス宛のパケットを受信する以外に、macvlanインターフェースに割り当てられたMACアドレス宛のパケットも受信することで、この機能を実現しているようです。
仮想インターフェースとは言っても、実際の受信処理は物理的なインターフェースのドライバ経由で行われますので、vethに比べるとオーバーヘッドが少なく、パフォーマンスが良い傾向にあります。
ではさっそくmacvlanインターフェースを作成してみましょう。
以上のようなインターフェースeth0
上にmacvlan0
というインターフェースを作成します。
macvlan0
インターフェースが作成されました。作成時に指定しているmode bridge
の部分は後で説明します。
それではDHCPでIPアドレスを割り当ててみましょう。
ご覧のようにIPアドレスが割り当たりましたね。
macvlanインターフェースとホストインターフェース間の通信
macvlanインターフェースは実装の仕組み上、macvlanインターフェースとmacvlanインターフェースを割り当てたインターフェース(前述の例だとeth0
)の間の通信はできませんので注意が必要です。
コンテナとホスト間で通信が必要な場合には使えません。
macvlanのモード
macvlanインターフェースはいくつかのモードを持ちます。
先の例でmacvlanインターフェースを作成する際にmode bridge
としました。これはmacvlanのモードをbridge
モードに設定しています。
以下で簡単にmacvlanが持つモードを紹介します。なお、それぞれのモードの実際の動きはLXCの設定や動きを紹介する際に紹介したいと思いますので、ここでは簡単に各モードについて説明するのにとどめます。
privateモード
mode private
と設定すると、同じインターフェースに複数のmacvlanインターフェースを割り当てた場合、そのインターフェース同士の通信はできません。
たとえば、eth0
に接続するmacvlanインターフェースとしてmacvlan0
とmacvlan1
インターフェースをprivateモードで作成した場合、macvlan0
とmacvlan1
の間の通信はできません。
同じインターフェースに接続するmacvlanインターフェースを多数作成して、それぞれをコンテナに割り当てた場合、コンテナ同士の通信ができませんので注意が必要です。
bridgeモード
先の例でmode bridge
と設定したモードがこのbridgeモードです。bridgeモードで設定すると、privateモードと異なり、同じインターフェースに割り当てたmacvlanインターフェース同士の通信が可能になります。この場合のmacvlanインターフェース同士の通信は直接行われ、外部には送出されませ
ん。
vepaモード
vepaモードはbridgeモードのように、同じインターフェースに接続したmacvlanインターフェース同士の通信が可能なモードです。
しかしbridgeモードとは違い、macvlanインターフェース間のパケットは、一旦macvlanインターフェースが接続されるホストのインターフェースが接続している外部のスイッチなどに送出されます。
この外部のスイッチがVEPAをサポートしている場合、スイッチに届いたmacvlanインターフェース同士のパケットは、再度macvlanインターフェースを接続したホストのインターフェースに戻されて、目的のmacvlanインターフェースに届きます。このような機能をVEPAといいます。
つまりコンテナのホストがVEPA対応のネットワーク機器に接続されている場合に使用するモードです。
passthruモード
KVMで使われる機能に、macvlanをベースとしたmacvtapという機能があります。passthruモードはこのmacvtapを使った場合の仮想マシンに割り当てたインターフェースの制限を回避するために作られた機能のようです。
このモードはLXCから使えませんのでここでは説明しません(※)。
まとめ
今回はLinuxカーネルに実装されているコンテナに関連するネットワーク機能を2つ紹介しました。いずれもこれまでのカーネルの機能と同様に、コンテナ専用の機能というわけではありませんが、vethは元々コンテナでの利用を念頭に開発された機能で、コンテナ用と言ってもよい機能です。
さて、今回を含めて5回に渡ってコンテナで使われるLinuxカーネルの機能を紹介してきました。次からはいよいよLXCの説明に入っていきたいと思います。
LXC日本語ページの移行
第2回でLXC公式ページの日本語サイトを紹介しましたが、メンテナのStéphane Graberさんが作業をしてくださり、公式ページのサイト上に日本語ページを置けることになりました。新しい日本語ページはこちらになります。
まだ移行作業中ですが、リリース情報なども日本語に翻訳して公開していきますので、チェックしてみてください。