技業LOG
みなさんご存じの通り、昨今のインターネットやVPNサービスでは高い可用性が求められています。しかし機械はいずれ故障するものなので、仮にネットワーク機器(以下NW機器)に障害が発生した際は迅速に復旧作業を行う必要があります。
しかし、NW機器の復旧は時間がかかります。
- 障害事実の認知
- 障害箇所の特定
- 復旧手順の決定
- 復旧作業の準備
- 復旧作業の実施
- 復旧の確認
とりあえず思いついただけで6個も手順がありました。
遅くなる要因としては、どうしても上記の項目毎に人間が介入し判断するところにあります。NWと一言でいっても、障害ポイントによって構成が異なるので、それに応じた対処がもとめられます。そしてNWの運用期間と複雑性はまず間違いなく比例します。
現地のデータセンターへ出動せず、リモート接続で予備系に切り替えるにしても、やはり上記のステップを踏みつつ、判断・実施するため時間がかかります。
NWプロトコルで勝手に迂回してくれる冗長NWは別としても、
static(静的経路制御)構成を余儀なくされるNWについては、上記の復旧手順を素早く実施したいものです。
テレメトリーデータ(死活監視のためのSNMPやSyslogなど)を収集・管理して、構成管理ツール(ansibleなど)と組み合わせれば自動化できそうですね。
しかしこのシステム、構成要素と検討項目が多すぎてコストはともかく、時間がとてもかかりそうですね。いつできあがるんでしょうか。
もっとお手軽で時間もコストもかからない方法がよいですね。
そこで、NW機器の標準機能として利用できるスクリプト機能を利用して障害から復旧までを自動化することにしました。
今回の例ではJuniper社のJUNOScriptを利用しています。
- ※シスコ社であればEEM(Embedded Event Manager)に相当
本機能はルーター内で実行できるベンダーが提供するスクリプト機能です。
例えば、特定の事象が発生した場合、あらかじめ決められた動作を実行することができます。もう少し自動復旧のイメージを具体的に記述すると、Link障害を検知したsnmpを契機としてIFポートの開放・閉塞を制御することができます。
ルーター内だけで完結しているなら、比較的簡単にできそうな気がしてきました。
スクリプトを利用した自動復旧には、下記のメリットがあります。
- 安価な機器でも標準で利用できる
→追加投資がほとんど不要
→調達期間もゼロ - 構成要素が運用機と予備機の2台だけ
→特別なエージェントもワークフローエンジンも不要
→集中管理する必要がないので、システム(運用機・予備機)単位にスタンドアロンで動作する
上記で述べたように、JUNOScriptを用いた自動化では“契機(トリガ)”と“動作(アクション)”を定義する必要があります。
アクションを定義するには、SLAXと呼ばれるXML形式ファイルに動作(例えばIFポートを閉塞する)を定義する必要があります。また、Config上において、どの事象(特定のsnmp結果等)をトリガとして、どのSLAXを実行するか、を設定します。
トリガとアクションのスクリプトを記述する前に、復旧対象装置の状態と自動復旧要件を整理します。
構成図
■復旧対象装置の状態
- 複数のユーザー回線を1台でL3終端する収容装置(ルーターもしくはL3SW)
- 冗長化されたIFポートの先にいる上位ルーターからフルルートを受信している
- 配下には動的経路制御が設定されたIFと静的経路制御が設定されたIFが同居している
- 配下の物理IFは、さらに論理IFに分かれ、複数のユーザー回線をVLANで多重収容している
- 本収容装置の障害にそなえて、同一物理構成・同一Configの予備機がコールドスタンバイ(わたり以外のすべてのIFポートが閉塞されており、NW内に同一Configのノードが同時に存在しないようにしている。電源はON。)
■自動復旧要件
- 配下のユーザー回線を収容する物理IFのうち、静的経路制御が設定されたIFがLinkDownした際に運用機から予備機に切り替える
- 運用機が再起動した際に運用機から予備機に切り替える
- ※上位ルーターに接続しているIFと、配下の動的経路制御が設定されているIFはL3で迂回が可能であるため、要件に入れない
自動復旧要件を満たすSLAXを設定します。
運用機から予備機に切り替えるためには予備機が運用機の異常を検知する必要があります。
先述したとおり、JUNOScriptはルーター内に閉じた機能なので、両ルーターをまたぐ(認識する)設定はできません。ですので、運用機と予備機の“わたりIF”を作り、“わたりIF”がLinkDownすることで、予備機は運用機が閉塞したことを認識できるようにします。
上記を踏まえて、必要となるSLAXはざっくりと2つあります。
運用機:AllShutdown.slax
すべてのIFポートを閉塞する動作を記述したSLAX
・すべてのIFポートを閉塞することで・・・
わたりIFポートがLinkDownし、予備機が運用機に昇格する契機を与える
予備機が運用機に昇格した際に、NW内に同一Configを持つノードが存在しないようにする
予備機:AllOpen.slax
すべてのIFポートを開放する
次に、JUNOSのConfig上でトリガの指定とアクションのSLAXを選択します
運用機:
トリガとしたいIFポートがLinkDownを検知したらAllShutdown.slaxを実行する
予備機:
わたりIFポートがLinkDownを検知したらAllOpen.slaxを実行する
上記の設定で、任意のIFポートに障害が発生した際に、自動で運用機から予備機に切り替えることができるはずです。
しかし、実はこの設定では動的経路設定(ここではBGPとする)で接続しているユーザー回線に無用な通信断を与えてしまいます。障害発生時にL3で迂回済みであるはずのBGPユーザーが、なぜ通信断になるのでしょうか。
原因は、BGPの特性とAllOpen.slaxにあります。
BGPの迂回動作を順を追って記載します。
- ※Main系:ユーザーノードに対して優先度の高い経路を配信するルーター
- ※Back系:ユーザーノードに対して優先度の低い経路を配信するルーター
- Main系運用機ルーターに障害が発生。ユーザーノードはBack系運用機ルーターから受信したBPG経路を優先。
- JUNOScriptにより、Main系予備機のすべてのIFポートがLinkUp。
・上位ルーター向けのIFポートがBGP接続を開始。フルルートの経路交換が始まる。
と同時に
・配下のユーザーノード向けBGP接続を開始。ユーザーノードはMain系予備機ルーターから受信したBGP経路を優先。
結果、ルーターが上位ルーターから受信したフルルートの経路交換が完了するより先に、優先度の高い経路としてMain系予備機ルーターを選択してしまうため、ルーターは転送先がなく破棄してしまうワケです。
- ※フルルートのインストールが完了していなければ、通常はMain系予備機ルーターからユーザーノードへBGPの経路配信は始まりませんが、ルーターが経路を生成している場合は、インストール完了の有無にかかわらず経路配信が始まってしまいます。
動的経路制御が設定されているルーターに対して、AllOpen.slaxはまずいですよね。
皆さんお気づきの通り、上位ルーター向けのIFポートのみを開放しフルルートのインストール完了後、配下のユーザーノード向けIFポートを開放する必要があります。
具体的には下記の2つです。
- 配下のIFポートを開放するトリガを上位のBGP Peer確立に設定する。
- 上位IFポート開放と配下IFポート開放の間に、フルルートインストールを待つためのsleepを設ける。
sleep時間は、対象となるルーターの性能と想定される経路負荷を考慮してチューニング。
※じつはここが一番大変かも。
→AllOpenPlus.slax
さらに改良点と注意点をいくつかあげると下記の通りです。
- 再起動した際、最終的に運用機も予備機もLinkUpしてしまいますので、再起動後を検知したらすべてのIFを閉塞する。
- わたりIFポートのみの障害に備えて、LAGにしておく。
- 運用機と予備機に同じSLAXとConfigを用意し、運用機用と予備機用をConfigのactivate/deactivateでコントロールすることで、Config差分が最小限に。
- JUNOS Config上でトリガとしてIFポートを指定する際、物理IFの中に論理IFとしてVLAN多重している場合は、
正規表現となるので、必ずIF名の最後に$をつけること。これ重要。
(筆者はそれを知らずにge-1/0/0.10を削除した結果、ge-1/0/0にマッチしてAllShutdown.slaxが発動しました・・・)
slax一部抜粋
AllShutdown.slax
IF xe-0/0/0を閉塞する
<interface>{ <name> "xe-0/0/0"; <disable>; }
AllOpenPlus1.slax
IF xe-1/0/0を開放する
<interface>{ <name>"xe-0/0/0"; <disable delete = "delete">; }
AllOpenPlus2.slax
60秒の待機後、IF ge-1/0/0を開放する
expr jcs:sleep(60); <interface>{ <name>"ge-1/0/0"; <disable delete = "delete">; }
JUNOSでのトリガ指定とslaxの指定
■わたりIF(ae0)がLinkDownしたらAllOpenPlus1.slax(上位ルーター向けIFの開放が記載されている)を実行
policy UpperLinkOpen { events snmp_trap_link_down; attributes-match { snmp_trap_link_down.interface-name matches ae0; } then { event-script AllOpenPlus1.slax { arguments { silent 1; } } } }
■BGPのPeerが確立したら、AllOpenPlus2.slax(ユーザー回線を収容している配下のIFの開放が記載されている)を実行
policy LowerLinkOpen { events rpd_bgp_neighbor_state_changed; within 1 { trigger on 1; } attributes-match { rpd_bgp_neighbor_state_changed.new-state matches Established; } then { event-script AllOpenPlus2.slax { arguments { silent 1; } } raise-trap; } }
JUNOSでのトリガ指定とslaxの指定
■配下のIF(ge-1/0/0)がLinkDownしたら、AllShutdown.slaxを実行
policy AllLinkShutdown1 { events snmp_trap_link_down; attributes-match { snmp_trap_link_down.interface-name matches "ge-1/0/0$"; } then { event-script AllShutdown.slax { arguments { silent 1; } } } }
一部本番環境の導入から時間が経ち、デメリットもみえてきました。
デメリット
- ■運用機予備機のセットが増えてくると管理が大変。(とにかく保守部門からのウケがよくない・・・)
・物理IFに対する工事の際、トリガに指定されていないかを都度確認し、該当していればトリガ設定をdeactivateするなどの手間が増える。
・予備機が運用機に昇格した際、Config内の設定も運用機用、予備機用と、設定を逆にするオペレーションが発生する。 - ■障害検知をLinkDownのsnmpに依存しているため、検知できる障害が限定的
- ■スクリプトである以上、自動迂回完了時間は設定のCommit時間(運用機の閉塞時間+予備機の開放時間)に依存するため、過度な高速切替の要求は酷。
・Configが肥大化してCommit時間が増加すると、切替時間も比例して伸びる。
・フルルートインストール完了のsleepを考慮するとさらに時間が必要。
とはいえ、局所的な利用に限れば強力なツールであり、お手軽に始められることも非常に魅力的です。
NWの規模が固定かつ限定的なシーンでは有用ではないでしょうか。
筆者が導入した対象のルーター(NW)は今後さらに高収容、大容量化していくことが予想されます。上記のデメリットを克服するため、HW内の構成要素(ラインカードやルーティングエンジンなど)の冗長化/仮想化された製品の導入や、構成管理システムとの連携など根本的に見直しを図る予定です。
しかしながら、先述したフルルートのインストール問題などは以前ルーター内のスクリプトの力を必要としており、今回得られたノウハウを継承、応用していく予定です。
おすすめ記事
お気軽にご相談ください
- ※Juniper NetworksおよびJunosは、米国およびその他の国における Juniper Networks, Inc.の登録商標です。