情報畑でつかまえてロゴ
本サイトは NTTテクノロスが旬の IT をキーワードに
IT 部門が今知っておきたい最新テクノロジーに関する情報をお届けするサイトです

OpenStack Neutronが作るNWの実体を追ってみよう

OpenStack neutronが作るNWの実体を、実際の画面、コマンドを交えて紹介します。

本記事に関するお問い合わせ先はこちら

皆様、こんにちは!

皆様の中に、OpenStack環境の構築が上手く行かないという方、いらっしゃいませんか?
「手順通りにパッケージを入れて、設定ファイルを作成してみたけど、ちゃんと動かないんだよなぁ」と躓いている方、少なくないのではないでしょうか。

私も初めてOpenStackを構築したときは四苦八苦しました。
Virtual Box上で作ったのですが、適切なNW設計が分からなかったり、nova bootで作ったインスタンスがすぐにエラーになったりと、いろいろ苦労した思い出があります。
その中でも一番大変だったのは、作ったインスタンスに疎通できないという問題でした。
ようやく作成に成功したインスタンスに、Floating IPを付けて、セキュリティグループもpingとsshを許可して、いざアクセス!と思ったら、届かない。。。

こういう時は、どこまでは疎通ができているのかと切り分けるのが常套手段です。が、OpenStack Neutronが作るNWは、tapデバイスがどうこう、namespaceがどうこうと、けっこう複雑な構成をしています。OpenStackを初めて触る方にとって「どこまで疎通できているか確認」は辛いものがありますよね。

そこで今回は、そんなお悩みをお持ちの皆様に向けて、OpenStack Neutronが作るNWの実体を追ってみたいと思います!

今回の環境は、公式サイトの手順 https://docs.openstack.org/mitaka/ja/install-guide-ubuntu/ の通りに構築しました。
・Ubuntu 14.04
・OpenStack Mitaka
・ハイパーバイザーはKVM
・Neutron ML2プラグインはLinux Bridge
・ネットワーク構成は、ネットワークオプション 2: セルフサービスネットワーク
という構成です。
この環境で、OpenStack操作でNW、インスタンス作成、Floating IP付与をすると、Floating IP向け通信がどのような経路で実現されているのかを確認してみます。
今回の内容が皆様の課題解決のお役に立てば幸いです。
(※OpenStackのバージョンはいささか古いですが、今回お伝えする内容は最新版でも通用します)

今回の環境の、ノードとNWは以下の通りです。
管理ネットワーク、プロバイダーネットワークの意味は、https://docs.openstack.org/mitaka/ja/install-guide-ubuntu/environment-networking.html をご参照ください。
node-network.png

この環境に、公式サイトの手順通りにOpenStack Mitakaを導入し、OpenStackのコマンドで仮想リソースを作りました。
作った仮想リソースは以下の通りです。provider network, selfservice networkの意味は、 https://docs.openstack.org/mitaka/ja/install-guide-ubuntu/launch-instance.html をご参照ください。
・仮想NWが2つ
 ・provider network
  ・CIDR: 10.123.123.0/24
  ・主なポート:
   10.123.123.102: 仮想ルータのゲートウェイポート
 ・selfservice network
  ・CIDR: 172.16.1.0/24
  ・主なポート:
   172.16.1.1: 仮想ルータのインタフェースのポート
   172.16.1.3: インスタンスのポート
・仮想ルータが1つ
 ・ゲートウェイはprovider network
 ・インタフェースにselfservice networkを持つ
・インスタンスが1つ
 ・イメージはCirros
 ・接続NWはselfservice network
 ・セキュリティグループはICMP(ping)とSSHを許可
 ・Floating IPあり。10.123.123.104
 ・配置先はCompute Node 1

さらにここで、今回のポート、仮想ルータ、インスタンスのidも書いておきます。何故かと申しますと、これから追っていく「OpenStakが作るリソースの実体」の名前と関連しているためです!

・仮想ルータのゲートウェイポート(10.123.123.102)のid:
 cb7d0d9a-3d21-49b4-bd1c-eca02895b05d
・仮想ルータのインタフェースのポート(172.16.1.1)のid:
 37720f0a-f07b-45c6-a07b-cfb26a947fa8
・インスタンスのポート(172.16.1.3)のid:
 3c338602-d806-488a-ae66-c4c8f8d13b9b
・仮想ルータのid:
 9bebc2e0-15de-48ef-991f-9659978384ba
・インスタンスのid:
 9fa7eaa3-71b4-475d-9f21-eb52f941b537

以上を図にしますと以下の通りです。
virtual-resources.png

さて、作ったインスタンスのFloating IP(10.123.123.104)にアクセスしてみると・・・
ping.png

pingも
ssh.png

sshもできました!(インスタンス内では、ちゃんとポート172.16.1.3を認識してますね!)
ではでは、上記の通信を実現している実体を追ってみましょう。
・・・とその前に、OpenStackのマニュアル( https://docs.openstack.org/mitaka/ja/networking-guide/deploy-lb-selfservice.html#architecture )にアーキテクチャ図があるので、まずはこれを見てみましょう。
architecture.png

・・・複雑ですね。でもご安心ください!これからこれを紐解いていきますよ~


まずは、上(Floating IP)から行くよりも下(インスタンス)から見ていくほうが理解しやすいので、
インスタンスが認識しているNICの実体(場所はCompute Node)を見てみましょう。

KVM環境においては、OpenStackはlibvirtを使ってインスタンスを定義します。その定義情報(xmlファイル)は、/var/lib/nova/instances/[インスタンスのid]/libvirt.xml にあります(※)。
(※これはデフォルトのファイルパスです。ファイルパスは、nova.confのstate_path設定値/instances、あるいはinstances_path設定値で決定されます)
そのxmlファイルの中に、インスタンスのNIC情報が書かれています。
今回のインスタンスでは、xmlファイルは
/var/lib/nova/instances/9fa7eaa3-71b4-475d-9f21-eb52f941b537/libvirt.xml で、
その中に
<interface type="bridge">
 <mac address="fa:16:3e:a7:f7:5a"/>
 <model type="virtio"/>
 <source bridge="brqe6e37ba0-3b"/>
 <target dev="tap3c338602-d8"/>
</interface>
と書かれていました。デバイスはtap3c338602-d8で、そのブリッジはbrqe6e37ba0-3bと定義されています。
また、tap3c338602-d8は、インスタンスのポートのid(3c338602-d806-488a-ae66-c4c8f8d13b9b)の先頭11文字を使っていることも分かりますね。

インスタンス側のNICは分かりました。
次に、それとCompute NodeのNICとの紐付けを見てみましょう。
紐付けは、Linux Bridgeを使って実現しています。
Linux Bridgeの状態は、brctl showコマンドで分かります。
compute-brctl.png

同じく、tap3c338602-d8とbrqe6e37ba0-3bがありますね。
さらに、ブリッジbrqe6e37ba0-3bのインタフェースには、vxlan-41が見えています。
これは、OpenStack Neutronが作成したVXLANトンネルのインタフェースです。
tap3c338602-d8の通信は、このvxlan-41が経由しているということですね。

次に、vxlan-41の実体を確認します。
ipコマンドで見てみると、Compute Nodeの物理NICであるeth0の上に出来たものだと分かります。
compute-vxlan.png

では、どこでeth0と決まったのでしょうか。
その答えは、neutronの設定値です。
設定ファイル/etc/neutron/plugins/ml2/linuxbridge_agent.ini で、以下のようにlocal_ipを設定しています。
[vxlan]
...
local_ip = 192.168.0.105
今回の環境は、192.168.0.105がeth0のアドレスなので、eth0上に出来たというわけです。

ここまでで、インスタンスからCompute Nodeの物理NICまでの繋がりは見えました。
引き続いて、仮想ルータ(その実体はController Nodeにあります)経由で外部に繋がる部分までを追います。

Controller NodeのLinux Bridgeを見てみましょう。

controller-brctl-1.png

Compute Nodeと同じく、vxlan-41がありますね。
その実体も同じく物理 NICの上に出来たものであり、物理NICはneutronの設定値で決まります。
controller-vxlan.png

Controller Nodeの設定値は以下の通り。192.168.0.104はController Nodeのeth1です。
@/etc/neutron/plugins/ml2/linuxbridge_agent.ini
[vxlan]
...
local_ip = 192.168.0.104
Compute Node, Controller Nodeの、192.168.0.0/24のネットワーク(管理ネットワーク)上でVXLANトンネルが張られていることが分かりました。

次に、Controller Nodeで、vxlan-41が繋がったブリッジの別のインタフェースであるtap37720f0a-f0を見てみましょう。これは、仮想ルータのインタフェースポート(172.16.1.1)の実体の一部です。(ポートのidをご確認ください)
tap37720f0a-f0の繋がり先を見てみましょう。
実はここからは、仮想ルータのネットワーク名前空間に繋がっています。
Controller Nodeには、仮想ルータのidを含むネットワーク名前空間(qrouter-9bebc2e0-15de-48ef-991f-9659978384ba)があります。なお、Controller Nodeに仮想ルータの名前空間が出来る理由は、Controller Nodeでneutron-l3-agentが起動しているからです。
controller-ip-netns.png

tap37720f0a-f0は、仮想ルータの名前空間のNICとveth pairを組んでいます。
まずは通常の名前空間で、tap37720f0a-f0のインデックスとpair先インデックスを確認します。
controller-ip-link-1.png

tap37720f0a-f0のインデックスは13で、pair先インデックスは2ですね。

では次に、仮想ルータの名前空間に入ります。
コマンドは ip netns exec qrouter-9bebc2e0-15de-48ef-991f-9659978384ba /bin/bash です。(exitで元に戻ります)
入った先で、tap37720f0a-f0のpair先インデックスである2のNICと、そのpair先インデックスを確認します。
controller-ip-link-2.png

2番目のNICはqr-37720f0a-f0で、そのpair先は13= tap37720f0a-f0と確認できました。

次は仮想ルータの名前空間内を見ていきましょう。
controller-ip-link-3.png

この名前空間内で、デフォルトルートはqg-cb7d0d9a-3d経由となっていますね。
さらにqg-cb7d0d9a-3dのpair先は14となっています。

では、qg-cb7d0d9a-3dのpair先を見つけましょう。
仮想ルータの名前空間を抜けて、Controller Nodeの14番目のNICを見てみます。
controller-ip-link-4.png

14番目はtapcb7d0d9a-3dですね。

では、Controller NodeのLinux Bridgeに戻ってみましょう。
controller-brctl-2.png

tapcb7d0d9a-3dのブリッジ接続先に、物理NICのeth2がありました!
eth2を決定しているのは、例によってneutronの設定値です。
neutronのflat_network、つまり物理的なネットワークと同じネットワークを設定する箇所として、以下の2点を設定しています。

@/etc/neutron/plugins/ml2/ml2_conf.ini
[ml2_type_flat]
flat_networks = provider
↑ここでflat_networksの名前を設定して、
↓ここでその名前と物理NICの紐付けを設定しています。
@/etc/neutron/plugins/ml2/linuxbridge_agent.ini
[linux_bridge]
physical_interface_mappings = provider:eth2

さて、ようやくController Nodeの物理NICや外部ネットワークまでの繋がりが確認できました。
最後に、Floating IPの実体を見てみましょう。
公式サイト
https://docs.openstack.org/mitaka/ja/networking-guide/deploy-lb-selfservice.html#north-south-scenario-2-instance-with-a-floating-ipv4-address
には、
For IPv4, the router performs DNAT on the packet which changes the destination IP address to the instance IP address on the self-service network and sends it to the gateway IP address on the self-service network via the self-service interface (6).
とあります。つまり、仮想ルータがDNATしているということですね。
では、先ほど入った仮想ルータの名前空間に再度入りましょう。
その中で、iptablesで設定されたNATを見てみます。
controller-iptables.png

そのものずばりな設定が見えますね。
Chain neutron-l3-agent-OUTPUT (1 references)
target prot opt source destination
DNAT all -- anywhere 10.123.123.104 to:172.16.1.3

つまり、Floating IP(10.123.123.104)向けのパケットを、インスタンスのアドレス(172.16.1.3)にNATせよ、という設定です。
これが、Floating IP経由でインスタンスにアクセスができる理由ということですね!

ここに至るまでに、いろいろなデバイスが登場しましたね。
もし皆様の環境でインスタンスへの疎通が上手く行かないことがあれば、今回の内容をなぞって頂き、さらに各デバイスでtcpdump -i <デバイス名>を実行してみて、どこまで疎通できているのかを見て頂ければ、切り分けが進むのではないかと思います!
参考として、tapcb7d0d9a-3dのtcpdumpは以下で確認できます。(この裏でfloating ip向けにpingを実行しています)
controller-tcpdump.png


今回の内容は以上です。
NTTテクノクロスは、OpenStack関連の様々なノウハウを持っており
構築から運用まで様々なサポートサービスを行っております。
今回の記事に関してご質問のある方や、OpenStackの導入や運用にご興味のある方は、ぜひこちらからお問い合わせください。



OpenStack のワードマークは、米国とその他の国における OpenStack Foundation の登録商標/サービスマークまたは商標/サービスマークのいずれかであり、 OpenStack Foundation の許諾の下に使用されています。
NTTテクノクロスは、OpenStack Foundation や OpenStack コミュニティの関連会社ではなく、公認や出資も受けていません。
その他会社名、製品名などの固有名詞は、一般に該当する会社もしくは組織の商標または登録商標です。

連載シリーズ
テクノロジーコラム
著者プロフィール
笠原 裕樹
笠原 裕樹