ダブル VLAN

私は、新しい OpenStack クラウドのセットアップをするため、カナダのブリティッシュコロンビア州ケロウナの現地にいた。デプロイ作業は完全に自動化されていた。Cobbler が物理マシンに OS をデプロイし、それを起動し、その後は Puppet が引き継いだ。私は練習で幾度もデプロイシナリオを実行してきたし、もちろん全て正常であった。

ケロウナの最終日、私はホテルから電話会議に参加していた。その裏で、私は新しいクラウドをいじっていた。私はインスタンスを1つ起動し、ログインした。全ては正常に思えた。退屈しのぎに、私は ps axu を実行したところ、突然そのインスタンスがロックアップしてしまった。

これは単なる1回限りの問題と思ったので、私はインスタンスを削除して、新しいインスタンスを起動した。その後電話会議は終了し、私はデータセンターを離れた。

データセンターで、私はいくつかの仕事を済ませると、ロックアップのことを思い出した。私は新しいインスタンスにログインし、再度 ps aux を実行した。コマンドは機能した。ふぅ。私はもう一度試してみることにした。今度はロックアップした。何だこれは?

何度か問題が再現した後、私はこのクラウドが実は問題を抱えているという不幸な結論に至った。更に悪いことに、私がケロウナから出発する時間になっており、カルガリーに戻らなければならなかった。

どこかであなたはこのような障害調査を行ったことがあるだろうか?インスタンスはコマンドを打つ度に全くランダムにロックアップしてしまう。元になったイメージの問題か?No-全てのイメージで同じ問題が発生する。コンピュートノードの問題か?No-全てのノードで発生する。インスタンスはロックアップしたのか?No!新しいSSH接続は問題なく機能する!

我々は助けを求めた。ネットワークエンジニアは、これは MTU の問題ではないかというのだ。素晴らしい!MTU! 事態は動き始めた! MTU とは何で、何故それが問題になるのだろうか?

MTU とは最大転送単位(Maximum Transmission Unit)である。これは、各パケットに対してそのインターフェースが受け取る最大バイト数を指定する。もし2つのインターフェースが異なる MTU であった場合、バイトは尻切れトンボとなって変なことが起こり始める…例えばセッションのランダムなロックアップとか。

[注記]注記

すべてのパケットサイズが 1500 に収まるわけではない。SSH 経由の ls コマンド実行は 1500 バイト未満のサイズのパケット1つで収まるかもしれない。しかし、 ps aux のように多大な出力を行うコマンドを実行する場合、1500 バイトのパケットが複数必要とある。

OK。では MTU の問題はどこから来るのか?なぜ我々は他のデプロイでこの問題に遭遇しなかったのか?この状況は何が新しいのか?えっと、新しいデータセンター、新しい上位リンク、新しいスイッチ、スイッチの新機種、新しいサーバー、サーバーの新機種…つまり、基本的に全てが新しいものだった。素晴らしい。我々は様々な領域で MTU の増加を試してみた。スイッチ、コンピュータのNIC、インスタンスの仮想NIC、データセンターの上位リンク用のインターフェースのMTUまでいじってみた。いくつかの変更ではうまくいったが、他はダメだった。やはり、この線の障害対策はうまくいってないようだった。我々はこれらの領域のMTUは変更すべきではないようだ。

結局、我々のネットワーク管理者(Alvao)と私自身は4つのターミナルウィンドウ、1本の鉛筆と紙切れを持って座った。1つのウインドウで我々は ping を実行した。2つ目のウインドウではクラウドコントローラー上の tcpdump、3つ目ではコンピュートノード上の tcpdump、4つ目ではインスタンス上の tcpdump を実行した。前提として、このクラウドはマルチノード、非マルチホスト構成である。

1つのクラウドコントローラーが全コンピュートノードのゲートウェイの役割を果たしていた。ネットワーク設定には VlanManager が使われていた。これは、クラウドコントローラーと全コンピュートノードで、各 OpenStack プロジェクトが異なる VLAN を持つことを意味する。パケットサイズ変更のため、ping の -s オプションを使用していた。パケットが全て戻ってくる時もあれば、パケットが出ていったきり全く戻って来ない時もあれば、パケットはランダムな場所で止まってしまう時もある、という状況だった。tcpdump を変更し、パケットの16進ダンプを表示するようにした。外部、コントローラー、コンピュート、インスタンスのあらゆる組み合わせの間で ping を実行した。

遂に、Alvaro が何かを掴んだ。外部からのパケットがクラウドコントローラーを叩いた際、パケットは VLAN で設定されるべきではない。我々はこれが正しいことを検証した。パケットがクラウドコントローラーからコンピュートノードに行く際、パケットはインスタンス宛の場合にのみ VLAN を持つべきである。これもまた正しかった。ping のレスポンスがインスタンスから送られる際、パケットは VLAN 中にいるべきである。OK。クラウドコントローラーからパブリックインターネットにパケットが戻る際、パケットには VLAN を持つべきではない。NG。うぉっ。まるで パケットの VLAN 部分が削除されていないように見える。

これでは意味が無かった。

このアイデアが我々の頭を駆け巡る間、私はコンピュートノード上でコマンドをランダムに叩いていた。

$ ip a
…
10: vlan100@vlan20: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc noqueue master br100 state UP
…

「Alvaro、VLAN 上に VLAN って作れるのかい?」

「もしやったら、パケットに余計に4バイト追加になるよ…」

やっと事の全容が判明した…

$ grep vlan_interface /etc/nova/nova.conf
vlan_interface=vlan20

nova.conf 中で、vlan_interface は OpenStack が全ての VLAN をアタッチすべきインターフェースがどれかを指定する。正しい設定はこうだった: vlan_interface=bond0

これはサーバーの冗長化された(bonded)NIC であるべきだからだ。

vlan20 はデータセンターが外向けのパブリックなインターネットアクセス用に我々に付与した VLAN である。これは正しい VLAN で bond0 にアタッチされている。

ミスにより、私は全てのテナント VLAN を bond0 の代わりに vlan20 にアタッチするよう OpenStack を設定した。それによって1つの VLAN が別の VLAN の上に積み重なり、各パケットに余分に4バイトが追加され、送信されるパケットサイズが 1504 バイトになる原因となった。これがパケットサイズ 1500 のみ許容するインターフェースに到達した際、問題の原因となったのだった!

全力でこの問題を修正した結果、全てが正常に動作するようになった。



loading table of contents...