2016年12月20日火曜日

LIO Cluster [LIO, DRBD, Pacemaker による冗長化 iSCSI Target] (その16)障害テスト計画


障害テストを実施するにあたり、その計画を立てようという話です。関連する運用設計についても触れてみたいと思います。

今回のような HA クラスタの場合、フェイルオーバが発生し、障害原因が取り除かれた後、スイッチバックさせるべきかどうか、という問題があります。
できるだけサービスを停止させたくない、ということであればスイッチバックさせたくない、という方向に話が進みます。
運用が楽な方がいいということであれば、1号機が常に Active 機であるという運用設計を採用し、スイッチバックさせておくべきであるということに落ち着きやすいです。分かりやすい(常に1号機でサービスが稼働している)ことが大切で、未然に事故を防ぐことにつながります。テスト工数も単純に半分で済みます。
どちらがいい、悪いではなく、どちらに決めるか、という問題です。
スイッチバックさせるためには、スイッチバック中のサービス停止が問題となります。
今回の構成では、2秒ほどでスイッチバックできるので、サービス利用が一番少ない時間帯にスイッチバックさせれば影響はほとんどない、ということでいいと思います。
2秒ほどのサービス停止に関する調整が簡単に許されないのであれば、もっともっと、ずーと高価なストレージを採用すべきです。コントローラのスイッチオーバが2秒で完了するストレージがあればいいですが、よく知りません。

今回は、1号機が常に Active 機である、という運用設計を採用したとして話を進めます。
2号機でサービスが提供されている状態は、仮復旧しているだけで障害が継続している状態ということになります。
構築編では特に話を出しませんでしたが、1号機(iscsitgt01a)で優先的にリソースが起動される設定を入れてあります。

1号機(iscsitgt01a)の障害が回復した場合に自動フェイルバックする設定を入れるべきかどうかについては、入れないこととします。
障害の原因が分からないままに、正しい対応ができている確信がないままに自動復旧させるのは危険だからです。状態によってはデータを失ってしまいます。
ボンディングの設定については、プライマリスレーブが有効なときはいつでもアクティブなスレーブとなる設定となっています。Red Hat 社のマニュアルにあるとおりの設定です。何度もフェイルオーバが発生する状況(いわゆる往復ビンタ状態)に陥った場合、サービス遅延やサービス停止にはなってもデータロストにはならないという判断が働いているのだと思います。テストで問題が発生しない限りは、Red Hat 社の判断を尊重し、ボンディングについては自動フェイルバックする設定のままとします。
自動復旧は期待しない、という運用に決めたので、OS 起動時に pacemaker.service を自動起動させる設定も入れないこととします。
クラスタの起動は、オペレータが明示的にサービス起動させる運用とします。
自動復旧させないということは、障害が発生して以降は必ず冗長性が失われているということになりますので、障害発生時には直ちに駆けつけて復旧を急ぐ必要があります。
運用ポリシーとしては、4時間以内に駆けつけなのか、翌営業日対応なのか、というあたりが選択肢となるのだと思われます。

運用設計として、定期点検を実施するかどうか、という話があります。
スタンバイ機が故障していることに気づかないまま運用を続けていると危険です。
スタンバイ機が故障していないことをどのように確認するかですが、スイッチオーバさせてみるのが手っ取り早く、確実な方法です。
スイッチオーバ中のサービス停止が問題となるのは障害復旧時と同じです。
スイッチオーバさせてしまったがゆえに障害が発生してしまった、という事態も想定されます。
コントロールされている時間帯に発生させてしまった方がマシだと考えるべきか、寝ている子は起こすべきでないと考えるべきか、難しい問題です。
スイッチオーバさせないで点検する方法があるかどうかですが、どこまでやれて、どこまで妥協するのか、という話になるものと思います。
定期点検はしないケースの方が多いと思われるので、一旦この問題は保留します。

運用設計として、パッチ適用をどうするのか、という問題もあります。
こちらは、ストレージという点から考えると、閉じたネットワーク空間内に配置されるということもあり、問題が発生しない限り適用しない、ということになると思われます。

データのバックアップについては、今回は上位層で考えるということで割り切りたいと思います。もう1セット LIO Cluster を構築し、バックアップ領域とするなどの対応を考えていただければと思います。仮想環境であれば、Active 機の仮想マシンを丸ごとバックアップすればいいです。
LIO Cluster を3セット用意して Oracle RAC の ASM 用ストレージとするというのはよい考えだと思います。それを更に2セット用意して一方をデータベース用、もう一方をバックアップ用という構成も素敵です。本当に大切なデータについては十二重化くらいまでは考えておくべきです。今回構築した LIO Cluster は非常にシンプルな機能しか実装しておらず、スナップショット機能やバックアップ機能などはあえて実装していません。これらの実装を始めると、汎用性が無くなっていくこともありますが、フェイルオーバ時間が2秒に収まらなくなっていく方が問題と捉えています。高級ストレージは当然これらの機能を有していますが、それらに依存するとベンダーロックインな実装になってしまう点も考慮しておく必要があります。バックアップ対象がある程度の大きさを超えた場合、ストレージの機能を利用しないとバックアップが一定時間内に終了しない、といったことになりますが、そうでない限りは、できるだけストレージの機能に依存する実装は避けるべきだと考えております。
クラウド時代を見越した実装を考えると、ストレージについては、今までの常識にとらわれない考え方をしなければならないケースが増えると思います。スケールアップ型のストレージは高機能ですが、半端なく高価です。スケールアウト型は、安い機材を多数組み合わせることで信頼性と性能を向上させます。レイテンシの向上は最初から諦めたスループット重視のスケールアウト型 (AWS の S3 等) の方が普及していますが、これらは高価なストレージの代替にはなりえない点が残念です。今回紹介する構成が、レイテンシの向上も見越したスケールアウト型ストレージの土台となれば幸いです。iSCSI イニシエータ側で LVM を使って束ねて使う、というのがもう1つのおすすめ構成となります。

OS 部分のバックアップについては、取得しておくことにします。バックアップが使えることの確認、リストア・リカバリ手順を整えておく必要があります。バックアップの有効期限についても考慮する必要があり、バックアップ後の設定変更に対応できるのかどうかも問題となります。
お奨めはできませんが、今回の構成程度であれば再構築でも十分短時間でできる、という判断もありだと思います。初期構築とスタンバイ機のみの復旧構築では手順が異なる部分も存在するので、事前に確認しておく必要があります。


どのような障害試験を行うかですが、全ての障害ケースをテストするのは実質的に不可能です。そこで、ある程度の絞り込みを行う必要があります。

一つ目の原則として、二重障害は考慮しない、というものがあります。
二重障害、三重障害等を考え始めると、テストケースが爆発的に増えていきます。
今回は HA 構成ということで2ノードしか存在しておらず、2ノードとも障害が発生してしまえば無力ですので、この原則は比較的お客様の了解を得やすいものと思われます。

ハードウェアを破壊してしまう可能性のあるテストは実施しない、という原則もお客様の了解を得やすい部類だと思います。わざと壊したらサポートを受けられないのでコストに響きます。

ソフト的に破壊してしまう可能性のあるテストは実施しない、という原則はどうでしょうか。バックアップ、リカバリ試験を兼ねて、実施すべきと考える場合と、テスト工数削減のために実施しないケースがあると思います。
実施すべきだと思います。

全損からの復旧試験は必ず実施し、部分破損からの復旧試験はある程度妥協する、という考え方があります。
障害対応として一番困惑するのは、部分的に壊れているケースです。一部が壊れた場合であっても、全部が壊れたものとみなして対応する、というのは整理としては非常に分かりやすいです。Stonith などは、下手に壊れた状態で放置するよりも積極的に壊れた側を強制停止させてしまおうという発送の下で考えだされた技術です。
LIO のリソースエージェントを改修しました(2016/12/10) が、LIO はカーネルモジュールとして実装されている関係で LIO のサービスを kill するといった対応ができないため、制御不能に陥って kill したい場合には、カーネルを停止させる処理を追加しました。OS 丸ごと停止させるのは乱暴な処置ですので、/etc/ha.d/noreboot というファイルが存在している場合には、単にエラーとなるようにしています。今回の運用であれば、2号機側に /etc/ha.d/noreboot ファイルを作成しておきます。

障害の原因として考えられるのは、ハードウェア故障、操作ミス、ソフトウェア・バグ、誤作動などが挙げられます。
ソフトウェアのバグや誤作動をソフトウェアでカバーするのは非常に難しいですが、カーネルパニックが発生した場合や、ビジーループによりひどい処理遅延が発生した場合にフェイルオーバさせることで対処できる場合もあります。
今回の構成では、ソフトウェア watchdog を仕込んでいるので、運が良ければ自動的にフェイルオーバします。運悪くフェイルオーバしない場合でも、別途監視していて障害を検知できた場合は、手動でフェイルオーバさせることで仮復旧できることもあります。これらの事象をわざと発生させることや再現させることは非常に難しいのでテスト範囲から除外します。
ハードウェア故障については、ハードウェア固有の検知機構が必要です。ハードウェア故障により、後述する障害ケースが引き起こされる場合についてのみテストすることとします。
操作ミスについては、やりがちなミスはテストしておくべきだと思いますが、「rm /」等を実行してしまった、というケースまでやるのはやりすぎだと思います。全損からの復旧試験に含まれているという整理でいいと思います。
全損からの復旧が必要とならないケースについて、クラスタ操作時にやりがちなミスをテストしておけば十分と考えます。

※ うっかり「rm /」を実行してしまうことがあるのか、という問いに対し、「ある」と答えておきます。過去に実施した数千行の手順の中からできるだけ単純化して説明すると、VAR1VAR2 がうっかり未定義の状態で「rm $VAR1/$VAR2」を貼り付けて実行してしまうということをやったことがあります。手順書を作ってその確認をしているときでしたが、開発機で、かつ、バックアップが存在したので最悪の事態に発展するところまではいきませんでした。お客様からは「次からは気を付けてね」と言われるレベルで済みました。今考えても背筋が凍りつく思いがします。この日以来、「su」コマンドは使わずに、できるだけ「sudo」コマンドを使うようになりました。スクリプト内でrm $VAR1/$VAR2」という表現になりそうなときはrm $VAR1$VAR2」に変更し、VAR1 の定義で末尾に「/」を含ませるように心がけています。


具体的な障害ケースは以下の分類で考えることにします。Active 機側で発生する場合、Stand-by 機側で発生する場合、等の分類は省略しています。

◆ノード障害
・シャットダウン
・カーネルパニック
・電源断
・DRBD 特有のスプリットブレイン障害

◆プロセス障害
・Corosync プロセス障害
・Pacemaker プロセス障害
・DRBD プロセス障害 (カーネルモジュールなので難しい)
・LIO プロセス障害 (カーネルモジュールなので難しい)
・Corosync 誤操作
・Pacemaker 誤操作
・LVM 誤操作
・DRBD 誤操作
・LIO 誤操作
・Corosync ポート閉塞
・DRBD ポート閉塞
・LIO ポート閉塞

◆ネットワーク障害
・スイッチ障害
・ポート障害
・インターコネクト障害

◆ストレージ障害
・ローカルハードディスク障害

※ ローカルストレージの RAID 障害は試験範囲外とします。ハードウェアに適した方法で実行しておいた方が良いですが、サポートとの関係で難しい場合もあるかと思われます。

※ ストレージ障害については、共有ディスクに対するパス障害などもありますが、今回の構成では共有ストレージが存在しません。ローカルストレージを読み書きしている DRBD が疑似的な共有ストレージとなっています。

2016年12月19日月曜日

VMware NSX @SoftLayer - その16 【ESXi 6.5 と NSX 6.2.4】


ESXi 6.5 が登場したので、NSX 6.2.4 をインストールして動かしてみようとしましたが、インストールに失敗します。同じ設計で、6.0u2 にすると動きます。
Host Client の完成度もまだまだで、仮想マシンの DVD ドライブのメディアを入れ替えただけで Reload となってしまいます。

Nested 環境も試してみましたが、NSX がインストールできないのはもとより、VMwareTools すら動きません。こちらはサポート範囲外なので文句は言えませんが。

NSX は、VMware 社の主力製品の1つであり、万全のテストを実施してくれているはずですが、ESXi 6.5 にインストールすらできないというのは…。

とりあえず、6.5u1 待ちです。

2016年12月18日日曜日

LIO Cluster [LIO, DRBD, Pacemaker による冗長化 iSCSI Target] (その15)障害テスト環境


LIO Cluster の障害テストを始めるに当たり、どのような環境でテストすべきかについて、思いつくままに述べていきます。

当然のことながら、今後一番利用されるケースを想定した環境を準備したいと思います。

ストレージに関する来年のトレンドは、オールフラッシュ化だと勝手に判断しています。
HDD と SSD の性能差は歴然としており、SSD の信頼性が上がってきたことから、オールフラッシュ化に取り組まれている方も多いと思います。一度オールフラッシュ・ストレージを利用すると、HDD には戻れなくなります。ただ、いかんせん、価格がまだまだ高すぎます。ストレージ専用機でオールフラッシュ化すると、すぐに億単位の見積もりができてしまいます。20~30TB 位の容量を確保し、バックアップを取得し、バックアップを遠隔地にレプリケーションしたい、等ということを考えるとそうなります。本番環境やステージング環境であれば、このような額の投資もありうるものと思われますが、開発環境や検証環境では、なかなか難しいものと思われます。

そこで、LIO Cluster の登場です。
ESXi の共有ディスクとして利用できます。VAAI がサポートされています。弊社の ESXi の共有ディスクは、LIO Cluster にしています。WSFC の共有ディスクとしても利用できます。SCSI3 Persistent Reservation 機能がサポートされています。データベースを冗長化する際の共有ディスクとしても利用できます。


検証環境は機能を満たす範囲で、安ければ安いほどいいということで、弊社の検証環境は、以下のような構成にしています。

サーバ: Fujitsu Primergy TX1310 M1、3万円ほど
CPU: Pentium G3420 (2C2T)
Memory: 4GB
RAID コントローラ: Adaptec、3万円ほど
SSD: Crucial 525GB × 4台、5万円ほど
NIC: X540-T2 (10Gbps 2ポート)、3万円ほど

計 14万円ほど ×2

このスペックのサーバを2台用意し、LIO Cluster にしています。

ESXi をインストールするサーバは以下のスペックを8台用意しています。

サーバ: Fujitsu Primergy TX1310 M1、3万円ほど
CPU: Xeon E3-1231V3 (4C8T)、3万円ほど  (ESXi インストール時にのみグラフィックカードを別途利用)
Memory: 32GB、3万円ほど
NIC: X540-T2 (1Gbps 4ポート)、1万円ほど

計 10万円ほど ×8

スイッチは、10Gbps ポートが4個ついている NetGear の S3300-28X を2台、ダイレクトアタッチケーブル2本でつなぎスタックを構成します。計15万円ほどです。

メーカのサポートは一切ありませんが、それなりに満足して使っています。
ESXi のメモリが 32GB というのは時々つらいので、64GB 搭載可能なサーバに置き換えたい、という考えは持っていますが、もうしばらく我慢するつもりです。VCSA が 16GB も使うので、そのうち 32GB 要求してくるのではないかと危惧しています。



上記の ESXi 8台のうちの4台に、SSD を4台ずつ追加し、10Gbps NIC を追加し、オールフラッシュの VSAN 検証を始めました。10Gbps NIC は、NetGear XS708E に接続しています。


LIO Cluster  上にある仮想サーバ (A) と、VSAN 上にある仮想サーバ (B) で、fio によるベンチマークを取得してみました。

4K Block Random read, 32 Job, 100MB x32 data
 (A) 89.4 MB/s, 22465 iops
 (B) 92.1 MB/s, 23151 iops

4K Block Random write, 32 Job, 100MB x32 data
 (A) 98.5 MB/s, 24638 iops
 (B) 94.8 MB/s, 23718 iops

4K ブロックサイズのランダムアクセス、32個のジョブが同時実行されます。それぞれのジョブは 100 MB のファイルを持っていて、そのファイル内をランダムアクセスします。

SSD: Crucial 525GB の単体性能が、カタログスペックで以下のようになっています。
シーケンシャル読み取り : 530MB/s
シーケンシャル書き込み : 510MB/s
4KBランダム読み取り : 92,000 IOPS
4KBランダム書き込み : 83,000 IOPS

HDD でテストした時の100倍をはるかに超える性能が出ています。
ボトルネックは、サーバの PCIe バス (CPU のバス) の性能だと判断しております。Xeon 2ソケットのサーバでテストすると、もう1桁性能が向上すると考えています。
性能を求めると、コストも簡単に1桁、2桁上昇してしまうので、検証環境としては十分な性能が出ている、ということにします。

ESXi on ESXi の上で VCSA を利用してみましたが、物理サーバ HDD 上の Windows vCenter よりも快適に利用できました。HDD の利用をやめて SSD にした場合、仮想化のオーバヘッドはとるに足りないものであることが実感できます。


この環境に関する LIO Cluster 障害試験をブログに連載することに意味があるかどうかですが、サポートが存在しない、このような環境を利用する人はほとんどいないと思うので、今のところ意義を見出せていません。VSAN の障害試験についてであれば、それなりの意義があると思いますが、別途気が向いたら (NSX に関する連載の続きとして) 掲載することにします。
IBM Bluemix (SoftLayer) の共有ディスクとしての LIO Cluster であれば、今すぐにでも利用したい人はいると思うのですが、いかんせん、現在私がテスト環境を有していないため、スポンサーが出てくるのを待つことにします。Bluemix では、非常に高くついたとしても、QuantaStor を利用して Bluemix のサポートを受けた方がいいのかもしれません。QuantaStor も DRBD による冗長化をサポートしているはずです。


予算が許せば、以下の構成で LIO Cluster を構築したいと考えています。資材だけで2台計300万円です。

サーバ: Fujitsu Primergy TX1330 M2 (5インチベイ搭載、冗長化電源、ラックマウント可能)
5インチベイ1つに8台の SSD を搭載できる HDD ケース 2個
RAID コントローラ: MegaRAID 16ポート
SSD: Crucial 2TB × 16台
NIC: X540-T2 (10Gbps 2ポート)

同じような構成でサポートがあるメーカ製サーバにすると、CE費、SI費抜き、2台で2000万円ほどになります。ストレージ専用機で同容量を確保すると大台に乗ると思います。この価格構造はどうしようもないです。Google 社などは、安い機材を集めて独自にサーバを組み立てているので、AWS が SSD を積極的に利用している現状が理解できます。


オンプレミス環境における現時点のオールフラッシュ・ストレージの本命は、コスト対効果からすると、VSAN だと考えています。ただし、VSAN では、ESXi の共有ディスクにはなり得ても、WSFC の共有ディスクにはならないので、その隙間を埋めるものとして、仮想サーバで構築する LIO Cluster が必要となるのではないかと考えています。データベースを冗長化する際の共有ディスクについても同様です。
共有ディスクのバックアップを考えた場合、ある程度の大きさを超えるとストレージのスナップショット機能が必須となります。更に差分バックアップができないと、バックアップ時間が許容範囲を超えてしまいます。遠隔地へのレプリケーションでは、重複排除、圧縮機能が必須だと思われます。これらの機能を求めると、ストレージ専用機が必須となってしまうのですが、ストレージ専用機のオールフラッシュ構成は、あまりにも高価すぎます。
VMware の VSAN、VDP、Replication を利用する前提で考えると、LIO Cluster を追加することで、ストレージの仮想化というシナリオが完成します。LIO Cluster のバックアップは、VDP で取得することができます。VDP でバックアップすれば、重複排除、圧縮がなされます。バックアップをレプリケーションする機能もあります。VDP によるバックアップは差分バックアップなので、上記のニーズを一通り満たします。VDP のサポートはあれなので、同等以上の機能を有する別のソリューションに置き換えると、それなりの性能をそれなりの価格で、それなりのサポート付きで享受できます。
バックアップを積極利用できるデータの仮想化という観点で、Actifio が面白いと考えています。仮想環境に最高性能を求めてはいけませんが、便利な機能は追及すべきです。


思いつくままにつらつらと述べてきましたが、仮想環境の LIO Cluster を利用する WSFC を構築し、障害試験を実施することとします。これらの仮想マシンをオールフラッシュの VSAN 上で動かします。このシナリオが、LIO Cluster を生かす最善のものだと考えています。ただし、VSAN については本連載の範囲外と考えていますので、本連載の障害テストのシナリオ内には登場しない想定です。
Oracle での利用については、Oracle 用のクラスタと、LIO Cluster を動かすための VSAN クラスタに分けます。Oracle のライセンス費用は、ストレージ専用機よりもはるかに割高なのですが、オールフラッシュのストレージ専用機利用を考えるのであれば、コストが均衡してきますので、そのコストダウンを図る目的としての VSAN 導入はありうると思います。少なくとも、HDD ストレージを利用しているのであれば、すぐにでも置き換えを検討すべきだと考えられます。置き換えたら、Oracle を動かしているサーバの CPU コア数を半減させても、それまで以上にきびきびと動作してくれるものと思われます。時間が許せば、こちらの障害テスト環境も準備したいと思います。

2016年12月17日土曜日

LIO Cluster [LIO, DRBD, Pacemaker による冗長化 iSCSI Target] (その5)DRBD リソース設定


DRBD 設定ファイルを作成し、リソースを設定します。

DRBD が何者であるのかについては各自調べていただくとして、今回は、「snapshot-resync-target-lvm.sh」が自動的に呼び出される設定を追加しました。「fencing」設定が「resource-only」となっている点にも注意が必要です。これらの挙動は、「障害テスト編」で述べたいと思います。


cat /etc/drbd.conf
# You can find an example in  /usr/share/doc/drbd.../drbd.conf.example

include "drbd.d/global_common.conf";
include "drbd.d/*.res";

cat << 'EOF' | sudo tee /etc/drbd.d/global_common.conf
global {
  usage-count no;
}
common {
  handlers {
    pri-on-incon-degr "/usr/lib/drbd/notify-pri-on-incon-degr.sh; /usr/lib/drbd/notify-emergency-reboot.sh; echo 1 > /proc/sys/kernel/sysrq; echo b > /proc/sysrq-trigger; reboot -f";
    local-io-error "/usr/lib/drbd/notify-io-error.sh; /usr/lib/drbd/notify-emergency-shutdown.sh; echo 1 > /proc/sys/kernel/sysrq; echo o > /proc/sysrq-trigger; halt -f";
    fence-peer "/usr/lib/drbd/crm-fence-peer.sh";
    before-resync-target "/usr/lib/drbd/snapshot-resync-target-lvm.sh -p 4";
    after-resync-target "/usr/lib/drbd/unsnapshot-resync-target-lvm.sh; /usr/lib/drbd/crm-unfence-peer.sh";
  }
  startup {
#wfc# wfc-timeout 10;
#wfc# degr-wfc-timeout 10;
#wfc# outdated-wfc-timeout 10;
  }
  disk {
    on-io-error detach;
    fencing resource-only;
    al-extents 6433;
    c-plan-ahead 20;
    c-delay-target 100;
    c-fill-target 0;
    c-max-rate 100M;
    c-min-rate 1M;
  }
  net {
    protocol C;
    max-buffers 128k;
    sndbuf-size 0;
    rcvbuf-size 0;
    cram-hmac-alg sha1;
    shared-secret "password";
    congestion-fill 100M;
    congestion-extents 2000;
    csums-alg md5;
    verify-alg md5;
    use-rle yes;
  }
}
EOF

cat << 'EOF' | sudo tee /etc/drbd.d/r0.res
resource r0 {
  volume 0 {
    device /dev/drbd0;
    disk /dev/vg0/lv-drbd0;
    meta-disk internal;
  }
  on iscsitgt01a.example.com {
    address 192.168.1.2:7788;
  }
  on iscsitgt01s.example.com {
    address 192.168.1.3:7788;
  }
}
EOF


DRBD リソースを初期化します。


sudo drbdadm create-md r0
initializing activity log
NOT initializing bitmap
Writing meta data...
New drbd meta data block successfully created.


続いて、drbd.service を起動して初期同期を実行という手順ですが、サーバ間にまたがった作業は後でまとめて実行したいと思います。

2016年11月30日水曜日

LIO Cluster [LIO, DRBD, Pacemaker による冗長化 iSCSI Target] (その14)Munin インストール、設定

Munin をインストールし、必要な設定を入れます。
Active 機と Stand-by 機の両方で実行します。
LIO プラグインの設定時には、リソースが稼働している(LIO が LUN をエクスポートしている)側で操作する必要があるので、スイッチオーバさせて順次実行します。

インターネット接続可能な端末で以下のコマンドを実行する等して、必要なパッケージを収集します。


curl -O http://yum.oracle.com/repo/OracleLinux/OL7/optional/latest/x86_64/getPackage/perl-Crypt-DES-2.05-20.el7.x86_64.rpm
curl -O http://yum.oracle.com/repo/OracleLinux/OL7/optional/latest/x86_64/getPackage/perl-File-Copy-Recursive-0.38-14.el7.noarch.rpm
curl -O http://yum.oracle.com/repo/OracleLinux/OL7/optional/latest/x86_64/getPackage/perl-Taint-Runtime-0.03-19.el7.x86_64.rpm
curl -O http://yum.oracle.com/repo/OracleLinux/OL7/optional/latest/x86_64/getPackage/perl-XML-DOM-1.44-19.el7.noarch.rpm
curl -O http://yum.oracle.com/repo/OracleLinux/OL7/optional/latest/x86_64/getPackage/perl-XML-RegExp-0.04-2.el7.noarch.rpm
curl -O http://yum.oracle.com/repo/OracleLinux/OL7/optional/latest/x86_64/getPackage/rrdtool-perl-1.4.8-9.el7.x86_64.rpm
curl -O https://dl.fedoraproject.org/pub/epel/7/x86_64/m/munin-2.0.25-11.el7.noarch.rpm
curl -O https://dl.fedoraproject.org/pub/epel/7/x86_64/m/munin-common-2.0.25-11.el7.noarch.rpm
curl -O https://dl.fedoraproject.org/pub/epel/7/x86_64/m/munin-node-2.0.25-11.el7.noarch.rpm
curl -O https://dl.fedoraproject.org/pub/epel/7/x86_64/p/perl-Cache-Cache-1.06-12.el7.noarch.rpm
curl -O https://dl.fedoraproject.org/pub/epel/7/x86_64/p/perl-Email-Date-Format-1.002-15.el7.noarch.rpm
curl -O https://dl.fedoraproject.org/pub/epel/7/x86_64/p/perl-HTML-Template-2.95-1.el7.noarch.rpm
curl -O https://dl.fedoraproject.org/pub/epel/7/x86_64/p/perl-IO-Multiplex-1.13-6.el7.noarch.rpm
curl -O https://dl.fedoraproject.org/pub/epel/7/x86_64/p/perl-IPC-ShareLite-0.17-12.el7.x86_64.rpm
curl -O https://dl.fedoraproject.org/pub/epel/7/x86_64/p/perl-Log-Dispatch-2.41-1.el7.1.noarch.rpm
curl -O https://dl.fedoraproject.org/pub/epel/7/x86_64/p/perl-Log-Dispatch-FileRotate-1.19-13.el7.noarch.rpm
curl -O https://dl.fedoraproject.org/pub/epel/7/x86_64/p/perl-Log-Log4perl-1.42-2.el7.noarch.rpm
curl -O https://dl.fedoraproject.org/pub/epel/7/x86_64/p/perl-MIME-Lite-3.030-1.el7.noarch.rpm
curl -O https://dl.fedoraproject.org/pub/epel/7/x86_64/p/perl-MIME-Types-1.38-2.el7.noarch.rpm
curl -O https://dl.fedoraproject.org/pub/epel/7/x86_64/p/perl-Mail-Sender-0.8.23-1.el7.noarch.rpm
curl -O https://dl.fedoraproject.org/pub/epel/7/x86_64/p/perl-Mail-Sendmail-0.79-21.el7.noarch.rpm
curl -O https://dl.fedoraproject.org/pub/epel/7/x86_64/p/perl-Net-CIDR-0.18-1.el7.noarch.rpm
curl -O https://dl.fedoraproject.org/pub/epel/7/x86_64/p/perl-Net-SNMP-6.0.1-7.el7.noarch.rpm
curl -O https://dl.fedoraproject.org/pub/epel/7/x86_64/p/perl-Net-Server-2.007-2.el7.noarch.rpm


収集したパッケージを管理者用一般ユーザのホームディレクトリにコピーします。

コピーされたファイルを確認します。


ls -l *.rpm
-rw-rw-r-- 1 admin admin 410308 Nov 20 19:02 drbd84-utils-8.9.6-1.el7.elrepo.x86_64.rpm
-rw-rw-r-- 1 admin admin 204328 Nov 20 19:34 munin-2.0.25-11.el7.noarch.rpm
-rw-rw-r-- 1 admin admin  93672 Nov 20 19:34 munin-common-2.0.25-11.el7.noarch.rpm
-rw-rw-r-- 1 admin admin 408204 Nov 20 19:34 munin-node-2.0.25-11.el7.noarch.rpm
-rw-rw-r-- 1 admin admin  93340 Nov 20 19:34 perl-Cache-Cache-1.06-12.el7.noarch.rpm
-rw-rw-r-- 1 admin admin  19920 Nov 20 19:34 perl-Crypt-DES-2.05-20.el7.x86_64.rpm
-rw-rw-r-- 1 admin admin  17524 Nov 20 19:34 perl-Email-Date-Format-1.002-15.el7.noarch.rpm
-rw-rw-r-- 1 admin admin  23164 Nov 20 19:34 perl-File-Copy-Recursive-0.38-14.el7.noarch.rpm
-rw-rw-r-- 1 admin admin  77780 Nov 20 19:34 perl-HTML-Template-2.95-1.el7.noarch.rpm
-rw-rw-r-- 1 admin admin  25616 Nov 20 19:34 perl-IO-Multiplex-1.13-6.el7.noarch.rpm
-rw-rw-r-- 1 admin admin  31004 Nov 20 19:34 perl-IPC-ShareLite-0.17-12.el7.x86_64.rpm
-rw-rw-r-- 1 admin admin  84300 Nov 20 19:34 perl-Log-Dispatch-2.41-1.el7.1.noarch.rpm
-rw-rw-r-- 1 admin admin  25232 Nov 20 19:34 perl-Log-Dispatch-FileRotate-1.19-13.el7.noarch.rpm
-rw-rw-r-- 1 admin admin 433560 Nov 20 19:34 perl-Log-Log4perl-1.42-2.el7.noarch.rpm
-rw-rw-r-- 1 admin admin  60212 Nov 20 19:34 perl-Mail-Sender-0.8.23-1.el7.noarch.rpm
-rw-rw-r-- 1 admin admin  29540 Nov 20 19:35 perl-Mail-Sendmail-0.79-21.el7.noarch.rpm
-rw-rw-r-- 1 admin admin  98316 Nov 20 19:34 perl-MIME-Lite-3.030-1.el7.noarch.rpm
-rw-rw-r-- 1 admin admin  39184 Nov 20 19:34 perl-MIME-Types-1.38-2.el7.noarch.rpm
-rw-rw-r-- 1 admin admin  19640 Nov 20 19:35 perl-Net-CIDR-0.18-1.el7.noarch.rpm
-rw-rw-r-- 1 admin admin 213136 Nov 20 19:35 perl-Net-Server-2.007-2.el7.noarch.rpm
-rw-rw-r-- 1 admin admin 105348 Nov 20 19:35 perl-Net-SNMP-6.0.1-7.el7.noarch.rpm
-rw-rw-r-- 1 admin admin  22496 Nov 20 19:34 perl-Taint-Runtime-0.03-19.el7.x86_64.rpm
-rw-rw-r-- 1 admin admin 141504 Nov 20 19:34 perl-XML-DOM-1.44-19.el7.noarch.rpm
-rw-rw-r-- 1 admin admin  10628 Nov 20 19:34 perl-XML-RegExp-0.04-2.el7.noarch.rpm
-rw-rw-r-- 1 admin admin  42864 Nov 20 19:34 rrdtool-perl-1.4.8-9.el7.x86_64.rpm

file *.rpm
drbd84-utils-8.9.6-1.el7.elrepo.x86_64.rpm:          RPM v3.0 bin i386/x86_64 drbd84-utils-8.9.6-1.el7.elrepo
munin-2.0.25-11.el7.noarch.rpm:                      RPM v3.0 bin noarch munin-2.0.25-11.el7
munin-common-2.0.25-11.el7.noarch.rpm:               RPM v3.0 bin noarch munin-common-2.0.25-11.el7
munin-node-2.0.25-11.el7.noarch.rpm:                 RPM v3.0 bin noarch munin-node-2.0.25-11.el7
perl-Cache-Cache-1.06-12.el7.noarch.rpm:             RPM v3.0 bin noarch perl-Cache-Cache-1.06-12.el7
perl-Crypt-DES-2.05-20.el7.x86_64.rpm:               RPM v3.0 bin i386/x86_64 perl-Crypt-DES-2.05-20.el7
perl-Email-Date-Format-1.002-15.el7.noarch.rpm:      RPM v3.0 bin noarch perl-Email-Date-Format-1.002-15.el7
perl-File-Copy-Recursive-0.38-14.el7.noarch.rpm:     RPM v3.0 bin noarch perl-File-Copy-Recursive-0.38-14.el7
perl-HTML-Template-2.95-1.el7.noarch.rpm:            RPM v3.0 bin noarch perl-HTML-Template-2.95-1.el7
perl-IO-Multiplex-1.13-6.el7.noarch.rpm:             RPM v3.0 bin noarch perl-IO-Multiplex-1.13-6.el7
perl-IPC-ShareLite-0.17-12.el7.x86_64.rpm:           RPM v3.0 bin i386/x86_64 perl-IPC-ShareLite-0.17-12.el7
perl-Log-Dispatch-2.41-1.el7.1.noarch.rpm:           RPM v3.0 bin noarch perl-Log-Dispatch-2.41-1.el7.1
perl-Log-Dispatch-FileRotate-1.19-13.el7.noarch.rpm: RPM v3.0 bin noarch perl-Log-Dispatch-FileRotate-1.19-13.el7
perl-Log-Log4perl-1.42-2.el7.noarch.rpm:             RPM v3.0 bin noarch perl-Log-Log4perl-1.42-2.el7
perl-Mail-Sender-0.8.23-1.el7.noarch.rpm:            RPM v3.0 bin noarch perl-Mail-Sender-0.8.23-1.el7
perl-Mail-Sendmail-0.79-21.el7.noarch.rpm:           RPM v3.0 bin noarch perl-Mail-Sendmail-0.79-21.el7
perl-MIME-Lite-3.030-1.el7.noarch.rpm:               RPM v3.0 bin noarch perl-MIME-Lite-3.030-1.el7
perl-MIME-Types-1.38-2.el7.noarch.rpm:               RPM v3.0 bin noarch perl-MIME-Types-1.38-2.el7
perl-Net-CIDR-0.18-1.el7.noarch.rpm:                 RPM v3.0 bin noarch perl-Net-CIDR-0.18-1.el7
perl-Net-Server-2.007-2.el7.noarch.rpm:              RPM v3.0 bin noarch perl-Net-Server-2.007-2.el7
perl-Net-SNMP-6.0.1-7.el7.noarch.rpm:                RPM v3.0 bin noarch perl-Net-SNMP-6.0.1-7.el7
perl-Taint-Runtime-0.03-19.el7.x86_64.rpm:           RPM v3.0 bin i386/x86_64 perl-Taint-Runtime-0.03-19.el7
perl-XML-DOM-1.44-19.el7.noarch.rpm:                 RPM v3.0 bin noarch perl-XML-DOM-1.44-19.el7
perl-XML-RegExp-0.04-2.el7.noarch.rpm:               RPM v3.0 bin noarch perl-XML-RegExp-0.04-2.el7
rrdtool-perl-1.4.8-9.el7.x86_64.rpm:                 RPM v3.0 bin i386/x86_64 rrdtool-perl-1.4.8-9.el7


インストーラを DVD ドライブにセットし、マウントします。


sudo mount /dev/cdrom /mnt


Munin をインストールします。


sudo yum -y --disablerepo=\* --enablerepo=media install httpd
sudo yum -y --disablerepo=\* --enablerepo=media localinstall perl-*.rpm rrdtool-perl-*.rpm munin-*.rpm


インストーラをアンマウントし、DVD ドライブから取り出します。


sudo umount /mnt


追加インストールしたパッケージの設定をバックアップします。


sudo cp -a /etc{,~}/cron.d/munin
sudo cp -a /etc{,~}/fonts
sudo cp -a /etc{,~}/httpd
sudo cp -a /etc{,~}/logrotate.d/httpd
sudo cp -a /etc{,~}/logrotate.d/munin
sudo cp -a /etc{,~}/logrotate.d/munin-node
sudo cp -a /etc{,~}/munin
sudo cp -a /etc{,~}/sysconfig/htcacheclean
sudo cp -a /etc{,~}/sysconfig/httpd
sudo cp -a /etc/passwd   /etc~/passwd_$(date +%Y%m%d_%H%M%S)
sudo cp -a /etc/passwd-  /etc~/passwd-_$(date +%Y%m%d_%H%M%S)
sudo cp -a /etc/shadow   /etc~/shadow_$(date +%Y%m%d_%H%M%S)
sudo cp -a /etc/shadow-  /etc~/shadow-_$(date +%Y%m%d_%H%M%S)
sudo cp -a /etc/group    /etc~/group_$(date +%Y%m%d_%H%M%S)
sudo cp -a /etc/group-   /etc~/group-_$(date +%Y%m%d_%H%M%S)
sudo cp -a /etc/gshadow  /etc~/gshadow_$(date +%Y%m%d_%H%M%S)
sudo cp -a /etc/gshadow- /etc~/gshadow-_$(date +%Y%m%d_%H%M%S)


前稿、前々稿で紹介した5つのプラグインを /usr/share/munin/plugins/ に配置し、実行権限を付与します。

有効化されている不要なプラグインを削除します。


sudo rm /etc/munin/plugins/postfix_mail*
sudo rm /etc/munin/plugins/fw_packets


Munin の稼働状況をグラフ化するプラグイン用の設定を行います。


cat << 'EOF' | sudo tee -a /etc/munin/plugin-conf.d/munin-node

[munin_*]
user munin
EOF


Munin の稼働状況をグラフ化するプラグインを有効化します。


sudo ln -s '/usr/share/munin/plugins/http_loadtime' '/etc/munin/plugins/http_loadtime'
sudo ln -s '/usr/share/munin/plugins/munin_stats' '/etc/munin/plugins/munin_stats'
sudo ln -s '/usr/share/munin/plugins/munin_update' '/etc/munin/plugins/munin_update'


DRBD の稼働状況をグラフ化するプラグインを有効化します。


sudo ln -s '/usr/share/munin/plugins/drbd' '/etc/munin/plugins/drbd'
sudo ln -s '/usr/share/munin/plugins/drbd_al' '/etc/munin/plugins/drbd_al'
sudo ln -s '/usr/share/munin/plugins/drbd_ext' '/etc/munin/plugins/drbd_ext'


Munin にホスト名を登録します。


sudo sed -i -e "s/^host_name .*\$/host_name $(uname -n)/" /etc/munin/munin-node.conf
sudo sed -i -e "s/^\\[localhost/[$(uname -n)/" /etc/munin/munin.conf


rhel7 の systemd で新設された PrivateTmp 機能を munin-node.service については無効化します。一部のプラグインが対応していないためです。今回利用するプラグインには無関係です。


sudo sed -i -e 's/^PrivateTmp=.*$/PrivateTmp=false/' /usr/lib/systemd/system/munin-node.service
sudo systemctl daemon-reload


ベーシック認証設定を行います。


sudo htpasswd -c -b /etc/munin/munin-htpasswd munin 'password'
sudo htpasswd -b /etc/munin/munin-htpasswd admin 'password'
sudo htpasswd -b /etc/munin/munin-htpasswd monitor 'password'


Active 機で、LIO の稼働状況をグラフ化するプラグインを有効化します。


sudo ln -s '/usr/share/munin/plugins/lio_read' '/etc/munin/plugins/lio_read'
sudo ln -s '/usr/share/munin/plugins/lio_write' '/etc/munin/plugins/lio_write'


Active 機で、Munin 関連サービスを自動起動するように変更し、起動します。


sudo systemctl enable munin-node.service
sudo systemctl enable httpd.service
sudo systemctl start munin-node.service
sudo systemctl start httpd.service


数十分待ってから、ブラウザで http://<ホスト名または IP アドレス>/munin/ へアクセスし、動作確認します。

リソースをスイッチオーバします。


sudo pcs resource move g_tgt; sleep 5; sudo pcs resource clear g_tgt


Stand-by 機で、LIO の稼働状況をグラフ化するプラグインを有効化します。


sudo ln -s '/usr/share/munin/plugins/lio_read' '/etc/munin/plugins/lio_read'
sudo ln -s '/usr/share/munin/plugins/lio_write' '/etc/munin/plugins/lio_write'


Stand-by 機で、Munin 関連サービスを自動起動するように変更し、起動します。


sudo systemctl enable munin-node.service
sudo systemctl enable httpd.service
sudo systemctl start munin-node.service
sudo systemctl start httpd.service


数十分待ってから、ブラウザで http://<ホスト名または IP アドレス>/munin/ へアクセスし、動作確認します。

リソースをスイッチバックします。


sudo pcs resource move g_tgt; sleep 5; sudo pcs resource clear g_tgt


2016年11月29日火曜日

LIO Cluster [LIO, DRBD, Pacemaker による冗長化 iSCSI Target] (その13)Munin用プラグイン(LIO)

今回は、LIO に関するプラグインを紹介します。

元ネタになりそうなものを探したのですが、見つからなかったのでスクラッチで作りました。
perl スクリプトではなく、シェルスクリプトにしました。

Read と Write は別のグラフにしましたが、1つのグラフの中にターゲット、イニシエータ、LUN、の全ての組み合わせを詰め込みましたので、接続数が多くなると見やすくはないと思います。
ターゲット、LUN 別に作るとか、折れ線グラフではなく、塗りつぶしのスタックで表現した方が見やすいとか、いろいろと改造の余地はあると思いますが、とりあえずたたき台としてもらえればと思います。

Read/Write 以外にも、グラフ化した方が有用な情報があるのではないかと思いますが、私のスキルでは選びきれなかったので、とりあえず必要そうなすべての情報をテキストで保存しておけば役に立つのではないか、と考えております。

/sys/kernel/config/target/ 配下にある情報を全て取得すると、私のテスト環境では、仮想サーバで6秒ほど、物理サーバで1秒強かかりました。


sudo mkdir -p /etc/lio
sudo mkdir -p /var/log/lio/

cat << 'EOF' | sudo tee /etc/lio/save
#!/bin/sh
FILE=/dev/shm/lio-$(date +%Y%m%d%H%M)
for i in $(find /sys/kernel/config/target ! -type d | LANG=C sort)
 do echo [$i]; cat $i; echo; done > $FILE 2> /dev/null
gzip $FILE
mv $FILE.gz /var/log/lio/
EOF
sudo chmod 755 /etc/lio/save


これを1分ごとに収集するのは負荷が高すぎると判断しております。多くのデータは値が変化しないので、無駄が多すぎます。1時間に1回取得する方向で考えます。

もう少し絞り込むことにします。

/sys/kernel/config/target/core/*/*/statistics
/sys/kernel/config/target/iscsi/*/fabric_statistics
/sys/kernel/config/target/iscsi/*/tpgt_1/acls/*/fabric_statistics
/sys/kernel/config/target/iscsi/*/tpgt_1/acls/*/*/statistics
/sys/kernel/config/target/iscsi/*/tpgt_1/lun/*/statistics
この配下にある情報を1分ごとに取得する、というあたりが妥協点だと考えました。「statistics (統計)」というディレクトリ配下に有用な統計情報が集約されている、ということにします。
これだけであれば、仮想マシンでも1秒かからずに収集できました。


cat << 'EOF' | sudo tee /etc/lio/statistics
#!/bin/sh
FILE=/dev/shm/lio-statistics-$(date +%Y%m%d%H%M)
YYYYMMDD=$(echo $FILE | sed -e 's/^.*\([0-9][0-9][0-9][0-9][0-9][0-9][0-9][0-9]\)[0-9][0-9][0-9][0-9]$/\1/')
for i in $(for k in /sys/kernel/config/target/{core/*/*/,iscsi/*/{fabric_,tpgt_1/{acls/*/{fabric_,*/},lun/*/}}}statistics; do echo $k; done | LANG=C sort)
 do for j in $(find $i ! -type d | LANG=C sort); do echo [$j]; cat $j; echo; done; done > $FILE 2> /dev/null
gzip $FILE
mkdir -p /var/log/lio/$YYYYMMDD/
mv $FILE.gz /var/log/lio/$YYYYMMDD/
EOF
sudo chmod 755 /etc/lio/statistics


これらの情報を貯めこむと1年あたり 1GB 程度になる見込みです。1年経過したものは削除する、ということでいいと思います。1つのディレクトリに大量のファイルを置くのはよくないので、毎日別のディレクトリに入れるということで。
タダの HDD の肥やしになりそうな予感がしていますが、取得しておけばよかった、とならないための用心です。


cat << 'EOF' | sudo tee /etc/cron.d/lio
59 * * * * root nice -n 19 /etc/lio/save
* * * * * root nice -n 19 /etc/lio/statistics
58 23 * * * root nice -n 19 /bin/find /var/log/lio -mtime +365 -print0 | xargs -0 rm -rfv 2> /dev/null
EOF




Munin 用プラグインは以下の通りです。GitHubに置きました。

iqn については、「:」以降の文字列のみを切り出して表示しています。


https://raw.githubusercontent.com/blog-pcoffice/public/master/lio_read

cat << 'EOF' | sudo tee /usr/share/munin/plugins/lio_read
#!/bin/sh
#%# family=auto
#%# capabilities=autoconf

if [ "$1" = "autoconf" ]; then
  if [ -d /sys/kernel/config/target/iscsi/iqn.*/tpgt_1 ]; then
    echo yes
  else
    echo 'no (no iscsi target)'
  fi
  exit 0
fi
if [ "$1" = "config" ]; then
  echo 'graph_title LIO (Read)'
  echo 'graph_category LIO'
  echo 'graph_info Graph LIO (Read)'
  echo 'graph_vlabel Graph LIO (Bytes/sec)'
  echo 'graph_scale yes'
  echo 'graph_args --base 1024 --lower-limit 0'
  echo 'graph_period second'
#  echo 'graph_height 200'
#  echo 'graph_width 400'
  echo 'graph_printf %7.2lf'

  TGT_=
  INI_=
  for i in $(echo /sys/kernel/config/target/iscsi/iqn.*/tpgt_1/acls/iqn.*/*/statistics/scsi_auth_intr/read_mbytes | LANG=C sort)
  do
    TGT=$(echo $i | cut -d/ -f7)
    INI=$(echo $i | cut -d/ -f10)
    LUN=$(echo $i | cut -d/ -f11)
    if [ "$TGT_" = "$TGT" ]; then
      if [ "$INI_" = "$INI" ]; then
        :
      else
        INI_=$INI
        INI_F=$(echo $INI | tr "[:upper:]" "[:lower:]" | sed -e 's/-/_/g' -e 's![^a-z0-9_]!!g')
      fi
    else
       TGT_=$TGT
       TGT_F=$(echo $TGT | tr "[:upper:]" "[:lower:]" | sed -e 's/-/_/g' -e 's![^a-z0-9_]!!g')
       INI_=$INI
       INI_F=$(echo $INI | tr "[:upper:]" "[:lower:]" | sed -e 's/-/_/g' -e 's![^a-z0-9_]!!g')
       for j in $(echo /sys/kernel/config/target/iscsi/$TGT/tpgt_1/lun/*/statistics/scsi_tgt_port/read_mbytes | LANG=C sort)
       do
         LUN_=$(echo $j | cut -d/ -f10)
         echo ${TGT_F}$LUN_.label $(echo $TGT | cut -d: -f2) \($LUN_\) Read
         echo ${TGT_F}$LUN_.cdef ${TGT_F}$LUN_,1048576,\*
         echo ${TGT_F}$LUN_.min 0
         echo ${TGT_F}$LUN_.type DERIVE
       done
    fi
    echo ${TGT_F}${INI_F}$LUN.label $(echo $TGT | cut -d: -f2) - $(echo $INI | cut -d: -f2) \($LUN\) Read
    echo ${TGT_F}${INI_F}$LUN.cdef ${TGT_F}${INI_F}$LUN,1048576,\*
    echo ${TGT_F}${INI_F}$LUN.min 0
    echo ${TGT_F}${INI_F}$LUN.type DERIVE
  done
  exit 0
fi

TGT_=
INI_=
for i in $(echo /sys/kernel/config/target/iscsi/iqn.*/tpgt_1/acls/iqn.*/*/statistics/scsi_auth_intr/read_mbytes | LANG=C sort)
do
  TGT=$(echo $i | cut -d/ -f7)
  INI=$(echo $i | cut -d/ -f10)
  LUN=$(echo $i | cut -d/ -f11)
  if [ "$TGT_" = "$TGT" ]; then
    if [ "$INI_" = "$INI" ]; then
      :
    else
      INI_=$INI
      INI_F=$(echo $INI | tr "[:upper:]" "[:lower:]" | sed -e 's/-/_/g' -e 's![^a-z0-9_]!!g')
    fi
  else
     TGT_=$TGT
     TGT_F=$(echo $TGT | tr "[:upper:]" "[:lower:]" | sed -e 's/-/_/g' -e 's![^a-z0-9_]!!g')
     INI_=$INI
     INI_F=$(echo $INI | tr "[:upper:]" "[:lower:]" | sed -e 's/-/_/g' -e 's![^a-z0-9_]!!g')
     for j in $(echo /sys/kernel/config/target/iscsi/$TGT/tpgt_1/lun/*/statistics/scsi_tgt_port/read_mbytes | LANG=C sort)
     do
       LUN_=$(echo $j | cut -d/ -f10)
       echo -n "${TGT_F}$LUN_.value "
       cat $j
     done
  fi
  echo -n "${TGT_F}${INI_F}$LUN.value "
  cat $i
done

exit 0;
EOF
sudo chmod 755 /usr/share/munin/plugins/lio_read



https://raw.githubusercontent.com/blog-pcoffice/public/master/lio_write

cat << 'EOF' | sudo tee /usr/share/munin/plugins/lio_write
#!/bin/sh
#%# family=auto
#%# capabilities=autoconf

if [ "$1" = "autoconf" ]; then
  if [ -d /sys/kernel/config/target/iscsi/iqn.*/tpgt_1 ]; then
    echo yes
  else
    echo 'no (no iscsi target)'
  fi
  exit 0
fi
if [ "$1" = "config" ]; then
  echo 'graph_title LIO (Write)'
  echo 'graph_category LIO'
  echo 'graph_info Graph LIO (Write)'
  echo 'graph_vlabel Graph LIO (Bytes/sec)'
  echo 'graph_scale yes'
  echo 'graph_args --base 1024 --lower-limit 0'
  echo 'graph_period second'
#  echo 'graph_height 200'
#  echo 'graph_width 400'
  echo 'graph_printf %7.2lf'

  TGT_=
  INI_=
  for i in $(echo /sys/kernel/config/target/iscsi/iqn.*/tpgt_1/acls/iqn.*/*/statistics/scsi_auth_intr/write_mbytes | LANG=C sort)
  do
    TGT=$(echo $i | cut -d/ -f7)
    INI=$(echo $i | cut -d/ -f10)
    LUN=$(echo $i | cut -d/ -f11)
    if [ "$TGT_" = "$TGT" ]; then
      if [ "$INI_" = "$INI" ]; then
        :
      else
        INI_=$INI
        INI_F=$(echo $INI | tr "[:upper:]" "[:lower:]" | sed -e 's/-/_/g' -e 's![^a-z0-9_]!!g')
      fi
    else
       TGT_=$TGT
       TGT_F=$(echo $TGT | tr "[:upper:]" "[:lower:]" | sed -e 's/-/_/g' -e 's![^a-z0-9_]!!g')
       INI_=$INI
       INI_F=$(echo $INI | tr "[:upper:]" "[:lower:]" | sed -e 's/-/_/g' -e 's![^a-z0-9_]!!g')
       for j in $(echo /sys/kernel/config/target/iscsi/$TGT/tpgt_1/lun/*/statistics/scsi_tgt_port/write_mbytes | LANG=C sort)
       do
         LUN_=$(echo $j | cut -d/ -f10)
         echo ${TGT_F}$LUN_.label $(echo $TGT | cut -d: -f2) \($LUN_\) Write
         echo ${TGT_F}$LUN_.cdef ${TGT_F}$LUN_,1048576,\*
         echo ${TGT_F}$LUN_.min 0
         echo ${TGT_F}$LUN_.type DERIVE
       done
    fi
    echo ${TGT_F}${INI_F}$LUN.label $(echo $TGT | cut -d: -f2) - $(echo $INI | cut -d: -f2) \($LUN\) Write
    echo ${TGT_F}${INI_F}$LUN.cdef ${TGT_F}${INI_F}$LUN,1048576,\*
    echo ${TGT_F}${INI_F}$LUN.min 0
    echo ${TGT_F}${INI_F}$LUN.type DERIVE
  done
  exit 0
fi

TGT_=
INI_=
for i in $(echo /sys/kernel/config/target/iscsi/iqn.*/tpgt_1/acls/iqn.*/*/statistics/scsi_auth_intr/write_mbytes | LANG=C sort)
do
  TGT=$(echo $i | cut -d/ -f7)
  INI=$(echo $i | cut -d/ -f10)
  LUN=$(echo $i | cut -d/ -f11)
  if [ "$TGT_" = "$TGT" ]; then
    if [ "$INI_" = "$INI" ]; then
      :
    else
      INI_=$INI
      INI_F=$(echo $INI | tr "[:upper:]" "[:lower:]" | sed -e 's/-/_/g' -e 's![^a-z0-9_]!!g')
    fi
  else
     TGT_=$TGT
     TGT_F=$(echo $TGT | tr "[:upper:]" "[:lower:]" | sed -e 's/-/_/g' -e 's![^a-z0-9_]!!g')
     INI_=$INI
     INI_F=$(echo $INI | tr "[:upper:]" "[:lower:]" | sed -e 's/-/_/g' -e 's![^a-z0-9_]!!g')
     for j in $(echo /sys/kernel/config/target/iscsi/$TGT/tpgt_1/lun/*/statistics/scsi_tgt_port/write_mbytes | LANG=C sort)
     do
       LUN_=$(echo $j | cut -d/ -f10)
       echo -n "${TGT_F}$LUN_.value "
       cat $j
     done
  fi
  echo -n "${TGT_F}${INI_F}$LUN.value "
  cat $i
done

exit 0;
EOF
sudo chmod 755 /usr/share/munin/plugins/lio_write




LIO Cluster [LIO, DRBD, Pacemaker による冗長化 iSCSI Target] (その12)Munin用プラグイン(DRBD)

Munin 用のプラグインを作りました。

rhel サーバ個別のリソース監視を考えた場合、ほとんどの環境で有益なものはどれかと考えると、Munin しか選択肢がないのではないかと思います。既存環境では、Zabbix やその他の監視ソフトが既に動いていて、それらの邪魔にならないものでなければなりません。グラフ化が簡単にできるもの、負荷が軽いもの、インストールが容易なもの(本格的な RDBMS 不要は最低条件)、と考えると、RRD(Round Robin Database) Tool を利用している Munin に白羽の矢が立ちます。MRTG は rhel7 の標準パッケージとなっているという魅力がありますが、2値しかグラフ化できないことと、設定ファイルを作成するのが面倒で、候補から外れました。オープンソースを気軽に持ち込めない場合には、MRTG という選択肢は有用です。

Munin は、自動設定が進んでいて、プラグインが用意されているものを利用する限りにおいては、導入が簡単です。デフォルト設定のままだとホスト名が localhost になってしまう等の見た目を気にしなければ、インストールして、認証設定を入れ、サービス起動するだけです。
自動設定されたプラグインを個別に無効化したい場合は、シンボリックリンクを削除してサービスを再起動するだけで済みます。Zabbix 等でグラフ化しているのであれば、重複するものだけを除外するということも簡単にできます。


今回は、DRBD に関するプラグインを紹介します。

元ネタは以下にあります。

https://github.com/munin-monitoring/contrib/tree/master/plugins/drbd

2012年にコミットされてから変更されていないようです。
「drbd-stat」については、dr, dw, nr, ns の値が1024倍されていないです。
「drbd」については、dr, dw, nr, ns の値が1024倍ではなく、819倍されています。理由が分かりませんでした。ご存知の方がいらっしゃいましたら教えてください。
とりあえず、819倍の話は忘れて、以下の3つのプラグインを作りました。

dr(Disk Read), dw(Disk Write), nr(Network Receive), ns(Network Send), oos(Out Of Sync) については、KByte 単位の値が取得できるので、1つのグラフ内にまとめました。
その他の統計値に関するものを1つのグラフにまとめました。ただし、al(Activity Log) に関しては、取得される値が大きかったので、他の値に関するグラフが意味のないものになってしまうのを避けるため、別のグラフにしました。oos に関しても別グラフにした方がよいかもしれませんが、そこまではこだわらないことにします。
以上の3つです。
Disk アクセスと Netwok アクセスは、ほぼ同じ値になるため重なり合ってしまうので、分けてしまう方がいいのかもしれません。Primary と Secondary が入れ替わっても、別の種類でほぼ同じ値になってしまいます。グラフの読み方を理解していれば問題ないとも言えます。

気が向いたら、dr&,dw, nr&ns, oos, al, bm, lo, pe, ua, ap, ep の10個のグラフに分割します。

以下の DRBD8.4 に関するマニュアルを参照しながら作りました。
http://www.drbd.org/en/doc/users-guide-84/ch-admin#s-performance-indicators

ソースコードは GitHub にも置きました。


https://raw.githubusercontent.com/blog-pcoffice/public/master/drbd

cat << 'EOF' | sudo tee /usr/share/munin/plugins/drbd
#!/usr/bin/perl
#%# family=auto
#%# capabilities=autoconf
# http://www.drbd.org/en/doc/users-guide-84/ch-admin#s-performance-indicators

use strict;
my $file="/proc/drbd";
my $store = {};
my $rid;

&crunch;
&display;

sub display{
  if ($ARGV[0] and $ARGV[0] eq "config"){
    print "graph_title DRBD\n";
    print "graph_category DRBD\n";
    print "graph_info Graph DRBD\n";
    print "graph_vlabel Graph DRBD (Bytes/sec)\n";
    print "graph_scale yes\n";
    print "graph_args --base 1024 --lower-limit 0\n";
    print "graph_period second\n";
    print "graph_height 200\n";
    print "graph_width 400\n";
    print "graph_printf %7.2lf\n";
    foreach my $key ( keys %$store ){
      my $drbdname = 'drbd'.$key;
      print $drbdname."dr.label $drbdname Disk Read\n";
      print $drbdname."dw.label $drbdname Disk Write\n";
      print $drbdname."ns.label $drbdname Network Send\n";
      print $drbdname."nr.label $drbdname Network Receive\n";
      print $drbdname."os.label $drbdname Out of Sync\n";
      print $drbdname."dr.cdef ".$drbdname."dr,1024,*\n";
      print $drbdname."dw.cdef ".$drbdname."dw,1024,*\n";
      print $drbdname."ns.cdef ".$drbdname."ns,1024,*\n";
      print $drbdname."nr.cdef ".$drbdname."nr,1024,*\n";
      print $drbdname."os.cdef ".$drbdname."os,1024,*\n";
      print $drbdname."dr.min 0\n";
      print $drbdname."dw.min 0\n";
      print $drbdname."ns.min 0\n";
      print $drbdname."nr.min 0\n";
      print $drbdname."os.min 0\n";
      print $drbdname."dr.type DERIVE\n";
      print $drbdname."dw.type DERIVE\n";
      print $drbdname."ns.type DERIVE\n";
      print $drbdname."nr.type DERIVE\n";
      print $drbdname."os.type DERIVE\n";
    }
    exit 0;
  }
  foreach my $key ( keys %$store ){
    my $drbdname = 'drbd'.$key;
    print $drbdname."dw.value ".$store->{$key}->{'dw'}."\n";
    print $drbdname."dr.value ".$store->{$key}->{'dr'}."\n";
    print $drbdname."ns.value ".$store->{$key}->{'ns'}."\n";
    print $drbdname."nr.value ".$store->{$key}->{'nr'}."\n";
    print $drbdname."os.value ".$store->{$key}->{'os'}."\n";
  }
}

sub crunch{
  open (IN, $file) || die "Could not open $file for reading: $!";
  if ($ARGV[0] and $ARGV[0] eq "autoconf"){
    close (IN);
    print "yes\n";
    exit 0;
  }
  while (<IN>){
    next if /version:|GIT-hash:/;
    chomp;
    my ($drbd) = $_ =~ /^\s+(\d):/;
    $rid = $drbd if $drbd =~ /\d/;
    my ($ns) = $_ =~ /ns:(\d*)/;  $store->{ $rid }->{'ns'} = $ns if $ns ne undef;
    my ($nr) = $_ =~ /nr:(\d*)/;  $store->{ $rid }->{'nr'} = $nr if $ns ne undef;
    my ($dw) = $_ =~ /dw:(\d*)/;  $store->{ $rid }->{'dw'} = $dw if $dw ne undef;
    my ($dr) = $_ =~ /dr:(\d*)/;  $store->{ $rid }->{'dr'} = $dr if $dr ne undef;
    my ($os) = $_ =~ /oos:(\d*)/; $store->{ $rid }->{'os'} = $os if $os ne undef;
  }
  close (IN);
}

exit 0;
EOF
sudo chmod 755 /usr/share/munin/plugins/drbd



https://raw.githubusercontent.com/blog-pcoffice/public/master/drbd_al

cat << 'EOF' | sudo tee /usr/share/munin/plugins/drbd_al
#!/usr/bin/perl
#%# family=auto
#%# capabilities=autoconf
# http://www.drbd.org/en/doc/users-guide-84/ch-admin#s-performance-indicators

use strict;
my $file="/proc/drbd";
my $store = {};
my $rid;

&crunch;
&display;

sub display{
  if ($ARGV[0] and $ARGV[0] eq "config"){
    print "graph_title DRBD (Activity Log)\n";
    print "graph_category DRBD\n";
    print "graph_info Graph DRBD (Activity Log)\n";
    print "graph_vlabel Graph DRBD (Activity Log)\n";
    print "graph_scale yes\n";
    print "graph_args --base 1024 --lower-limit 0\n";
    print "graph_period second\n";
    print "graph_height 200\n";
    print "graph_width 400\n";
    print "graph_printf %7.2lf\n";
    foreach my $key ( keys %$store ){
      my $drbdname = 'drbd'.$key;
      print $drbdname."al.label $drbdname Activity log\n";
      print $drbdname."al.min 0\n";
#      print $drbdname."al.type DERIVE\n";
    }
    exit 0;
  }
  foreach my $key ( keys %$store ){
    my $drbdname = 'drbd'.$key;
    print $drbdname."al.value ".$store->{$key}->{'al'}."\n";
  }
}

sub crunch{
  open (IN, $file ) || die "Could not open $file for reading: $!";
  if ($ARGV[0] and $ARGV[0] eq "autoconf"){
    close (IN);
    print "yes\n";
    exit 0;
  }
  while (<IN>){
    next if /version:|GIT-hash:/;
    chomp;
    my ($drbd) = $_ =~ /^\s+(\d):/;
    $rid = $drbd if $drbd =~ /\d/;
    my ($al) = $_ =~ /al:(\d*)/; $store->{ $rid }->{'al'} = $al if $al ne undef;
  }
  close (IN);
}

exit 0;
EOF
sudo chmod 755 /usr/share/munin/plugins/drbd_al



https://raw.githubusercontent.com/blog-pcoffice/public/master/drbd_ext

cat << 'EOF' | sudo tee /usr/share/munin/plugins/drbd_ext
#!/usr/bin/perl
#%# family=auto
#%# capabilities=autoconf
# http://www.drbd.org/en/doc/users-guide-84/ch-admin#s-performance-indicators

use strict;
my $file="/proc/drbd";
my $store = {};
my $rid;

&crunch;
&display;

sub display{
  if ($ARGV[0] and $ARGV[0] eq "config"){
    print "graph_title DRBD (Ext)\n";
    print "graph_category DRBD\n";
    print "graph_info Graph DRBD (Ext)\n";
    print "graph_vlabel Graph DRBD (Ext)\n";
    print "graph_scale yes\n";
    print "graph_args --base 1024 --lower-limit 0\n";
    print "graph_period second\n";
    print "graph_height 200\n";
    print "graph_width 400\n";
    print "graph_printf %7.2lf\n";
    foreach my $key ( keys %$store ){
      my $drbdname = 'drbd'.$key;
      print $drbdname."bm.label $drbdname Bit Map\n";
      print $drbdname."lo.label $drbdname Local count\n";
      print $drbdname."pe.label $drbdname Pending\n";
      print $drbdname."ua.label $drbdname UnAcknowledged\n";
      print $drbdname."ap.label $drbdname Application Pending\n";
      print $drbdname."ep.label $drbdname Epochs\n";
    }
    exit 0;
  }
  foreach my $key ( keys %$store ){
    my $drbdname = 'drbd'.$key;
    print $drbdname."bm.value ".$store->{$key}->{'bm'}."\n";
    print $drbdname."lo.value ".$store->{$key}->{'lo'}."\n";
    print $drbdname."pe.value ".$store->{$key}->{'pe'}."\n";
    print $drbdname."ua.value ".$store->{$key}->{'ua'}."\n";
    print $drbdname."ap.value ".$store->{$key}->{'ap'}."\n";
    print $drbdname."ep.value ".$store->{$key}->{'ep'}."\n";
  }
}

sub crunch{
  open (IN, $file ) || die "Could not open $file for reading: $!";
  if ($ARGV[0] and $ARGV[0] eq "autoconf"){
    close (IN);
    print "yes\n";
    exit 0;
  }
  while (<IN>){
    next if /version:|GIT-hash:/;
    chomp;
    my ($drbd) = $_ =~ /^\s+(\d):/;
    $rid = $drbd if $drbd =~ /\d/;
    my ($bm) = $_ =~ /bm:(\d*)/; $store->{ $rid }->{'bm'} = $bm if $bm ne undef;
    my ($lo) = $_ =~ /lo:(\d*)/; $store->{ $rid }->{'lo'} = $lo if $lo ne undef;
    my ($pe) = $_ =~ /pe:(\d*)/; $store->{ $rid }->{'pe'} = $pe if $pe ne undef;
    my ($ua) = $_ =~ /ua:(\d*)/; $store->{ $rid }->{'ua'} = $ua if $ua ne undef;
    my ($ap) = $_ =~ /ap:(\d*)/; $store->{ $rid }->{'ap'} = $ap if $ap ne undef;
    my ($ep) = $_ =~ /ep:(\d*)/; $store->{ $rid }->{'ep'} = $ep if $ep ne undef;
  }
  close (IN);
}

exit 0;
EOF
sudo chmod 755 /usr/share/munin/plugins/drbd_ext




2016年11月16日水曜日

LIO Cluster [LIO, DRBD, Pacemaker による冗長化 iSCSI Target] (その11)構築編のまとめ


ここまでの構築手順を PDF にまとめました。

iSCSITarget-Build-OracleLinux7.3-1.20.pdf
iSCSITarget-Build-OracleLinux7.3-1.20.xlsx


多少、手順が入れ替わったりしています。
Oracle Linux 7.3 が出たので、7.3用に書き直しています。

行番号の右隣にチェック欄があります。「a」は Active 機(1号機)のみで実行するコマンドです。「s」は Stand-by 機(2号機)のみで実行するコマンドです。「a,s」は、Active 機と Stand-by 機の両方で実行するコマンドです。「o」は、別の適切な端末で実行するコマンドです。実施したら丸を付ける、といった使い方を想定しています。
罫線を入れるなどの装飾は施していません。手順の追加、削除に関する編集がしやすいように考えた結果です。

2016/11/30 追記
1.10  Munin 関連の手順を追加し、こまごまとバグフィックスしてあります。
元ネタのエクセルファイルも併せて公開しました。
1ページ目の絵を直し、右側欄外の情報を調整すれば、
同一構成の場合、c 列のみをコピーし、テキストエディタに貼り付けることで、
構築に必要なコマンド群が得られます。

2016/12/17 追記
Pacemaker の LIO リソースエージェントを改良版に入れ替え、不要なログ出力を抑制し、こまごまとバグフィックスしてあります。


本連載で紹介した構成で初期構築をご希望の方は、メールにてお問い合わせください。
サーバ1台あたり10万円~(税別)という超特価にてご提供中です。
詳細は、上記PDFの最終頁をご参照ください。

MySQL や PostgreSQL、Oracle の冗長構成構築サービスも鋭意開発中です。商品開発に関するリクエストがあればお知らせください。検討させていただきます。
貴社のアプリケーション、サービス等を冗長化する共同開発も承ります。

2016年11月15日火曜日

LIO Cluster [LIO, DRBD, Pacemaker による冗長化 iSCSI Target] (その10)Pacemaker のリソース設定


Pacemaker にリソースを登録します。

Active 機で、クラスタの状態を確認します。


sudo pcs status
Cluster name: iscsitgt01
WARNING: no stonith devices and stonith-enabled is not false
WARNING: corosync and pacemaker node names do not match (IPs used in setup?)
Last updated: Fri Oct 21 00:28:51 2016          Last change: Fri Oct 21 00:27:20 2016 by hacluster via crmd on iscsitgt01s.example.com
Stack: corosync
Current DC: iscsitgt01s.example.com (version 1.1.13-10.el7-44eb2dd) - partition with quorum
2 nodes and 0 resources configured

Online: [ iscsitgt01a.example.com iscsitgt01s.example.com ]

Full list of resources:

PCSD Status:
  iscsitgt01a.example.com (10.110.88.57): Online
  iscsitgt01s.example.com (10.110.88.58): Online

Daemon Status:
  corosync: active/disabled
  pacemaker: active/disabled
  pcsd: active/enabled


Active 機で、クラスタにリソースを登録します。


sudo /etc/ha.d/crm.sh


Active 機で、状態を確認します。


sudo pcs status
Cluster name: iscsitgt01
WARNING: corosync and pacemaker node names do not match (IPs used in setup?)
Last updated: Sat Oct 29 19:52:34 2016          Last change: Sat Oct 29 19:51:46 2016 by root via cibadmin on iscsitgt01s.example.com
Stack: corosync
Current DC: iscsitgt01s.example.com (version 1.1.13-10.el7-44eb2dd) - partition with quorum
2 nodes and 5 resources configured

Online: [ iscsitgt01a.example.com iscsitgt01s.example.com ]

Full list of resources:

 Master/Slave Set: ms_drbd_r0 [p_drbd_r0]
     Masters: [ iscsitgt01a.example.com ]
     Slaves: [ iscsitgt01s.example.com ]
 Resource Group: g_tgt
     p_lvm      (ocf::heartbeat:LVM):   Started iscsitgt01a.example.com
     p_lio      (ocf::heartbeat:LIO):   Started iscsitgt01a.example.com
     p_vip      (ocf::heartbeat:VIP):   Started iscsitgt01a.example.com

Failed Actions:
* p_lvm_start_0 on iscsitgt01s.example.com 'unknown error' (1): call=16, status=complete, exitreason='Volume group [vg1] does not exist or contains error!   Volume group "vg1" not found',
    last-rc-change='Fri Oct 21 00:32:13 2016', queued=0ms, exec=1095ms
PCSD Status:
  iscsitgt01a.example.com (10.110.88.57): Online
  iscsitgt01s.example.com (10.110.88.58): Online

Daemon Status:
  corosync: active/disabled
  pacemaker: active/disabled
  pcsd: active/enabled


※ ここでのエラー発生は想定の範囲内です。リソースをグループ化するコマンドの前に、各種リソースが Active 機側で起動しようとしたり、Stand-by 機側で起動しようとしたりしてしまうためです。

Active 機で、リソースのエラー状態をクリアします。


sudo pcs resource cleanup
Waiting for 1 replies from the CRMd. OK


Active 機で、状態を確認します。


sudo pcs status
Cluster name: iscsitgt01
WARNING: corosync and pacemaker node names do not match (IPs used in setup?)
Last updated: Sat Oct 29 19:58:35 2016          Last change: Sat Oct 29 19:58:34 2016 by hacluster via crmd on iscsitgt01a.example.com
Stack: corosync
Current DC: iscsitgt01s.example.com (version 1.1.13-10.el7-44eb2dd) - partition with quorum
2 nodes and 5 resources configured

Online: [ iscsitgt01a.example.com iscsitgt01s.example.com ]

Full list of resources:

 Master/Slave Set: ms_drbd_r0 [p_drbd_r0]
     Masters: [ iscsitgt01a.example.com ]
     Slaves: [ iscsitgt01s.example.com ]
 Resource Group: g_tgt
     p_lvm      (ocf::heartbeat:LVM):   Started iscsitgt01a.example.com
     p_lio      (ocf::heartbeat:LIO):   Started iscsitgt01a.example.com
     p_vip      (ocf::heartbeat:VIP):   Started iscsitgt01a.example.com

PCSD Status:
  iscsitgt01a.example.com (10.110.88.57): Online
  iscsitgt01s.example.com (10.110.88.58): Online

Daemon Status:
  corosync: active/disabled
  pacemaker: active/disabled
  pcsd: active/enabled


Active 機と Stand-by 機で、設定情報を保存します。


sudo pcs config | sudo tee /etc/ha.d/crm.conf


Stand-by 機で、クラスタの状態をワッチします。


sudo watch pcs status


Active 機で、スイッチオーバ(手動フェイルオーバ)させてみます。


sudo pcs resource move g_tgt
Warning: Creating location constraint cli-ban-g_tgt-on-iscsitgt01a.example.com with a score of -INFINITY for resource g_tgt on node iscsitgt01a.example.com.
This will prevent g_tgt from running on iscsitgt01a.example.com until the constraint is removed. This will be the case even if iscsitgt01a.example.com is the last node in the cluster.
 

Stand-by 機で、クラスタの状態を確認します。


Cluster name: iscsitgt01
WARNING: corosync and pacemaker node names do not match (IPs used in setup?)
Last updated: Sat Oct 29 19:52:34 2016          Last change: Sat Oct 29 19:51:46 2016 by root via crm_resource on iscsitgt01a.example.com
Stack: corosync
Current DC: iscsitgt01s.example.com (version 1.1.13-10.el7-44eb2dd) - partition with quorum
2 nodes and 5 resources configured

Online: [ iscsitgt01a.example.com iscsitgt01s.example.com ]

Full list of resources:

 Master/Slave Set: ms_drbd_r0 [p_drbd_r0]
     Masters: [ iscsitgt01s.example.com ]
     Slaves: [ iscsitgt01a.example.com ]
 Resource Group: g_tgt
     p_lvm      (ocf::heartbeat:LVM):   Started iscsitgt01s.example.com
     p_lio      (ocf::heartbeat:LIO):   Started iscsitgt01s.example.com
     p_vip      (ocf::heartbeat:VIP):   Started iscsitgt01s.example.com

PCSD Status:
  iscsitgt01a.example.com (10.110.88.57): Online
  iscsitgt01s.example.com (10.110.88.58): Online

Daemon Status:
  corosync: active/disabled
  pacemaker: active/disabled
  pcsd: active/enabled


※ 赤字の行で、VIP を持っているノードが確認できればスイッチオーバ完了です。

※ ログで確認すると、切り替えに2秒かかっていないです。スイッチオーバ操作はこうであってほしいものです。メンテナンスのために切り替え作業を行うことは多いと思いますが、この作業に数十秒以上かかるようであれば、利用者の影響が大きすぎると思われるので、メンテナンス停止に関する利用者との調整が難しくなってしまいます。

Active 機で、設定変更を確認します。


diff <(grep -v last-lrm-refresh /etc/ha.d/crm.conf) <(sudo pcs config | grep -v last-lrm-refresh)
41a42
>     Disabled on: iscsitgt01a.example.com (score:-INFINITY) (role: Started) (id:cli-ban-g_tgt-on-iscsitgt01a.example.com)


Active 機で、設定変更を元に戻します。


sudo pcs resource clear g_tgt
diff <(grep -v last-lrm-refresh /etc/ha.d/crm.conf) <(sudo pcs config | grep -v last-lrm-refresh)


※ pcs では「unmove」ではなく「clear」です。
※ この操作を忘れると、障害発生時にフェイルオーバできません。

Stand-by 機側でリソースが動いている状態の場合、もう一度スイッチオーバさせます。Active 機側でリソースが動いている場合には、その必要はありません。

Active 機と Stand-by 機で、クラスタの状態を記録します。


sudo pcs status | sudo tee /etc/ha.d/crm.status


Active 機で、クラスタを停止します。


sudo pcs cluster stop --all
10.110.88.57: Stopping Cluster (pacemaker)...
10.110.88.58: Stopping Cluster (pacemaker)...
10.110.88.58: Stopping Cluster (corosync)...
10.110.88.57: Stopping Cluster (corosync)...



OS を停止し、バックアップを取得するのは、ここが最適と思われます。


今回は、仮想マシンでも動くことを前提に構築しました。
物理マシンであれば、Stonith 設定を追加したり、物理 watchdog に入れ替えたりといった改良の余地があります。
ただし、ハードウェアに依存する実装となってしまい、都度、調整や挙動の違いを確認する作業が発生しますし、障害試験項目も増えていきます。IPMI 対応を前提とするのであれば、多くのサーバで同じ挙動を期待できるかもしれません。
その価値があると判断した場合には、これらの設定も追加することになります。

LVM のスナップショットを利用したバックアップ機能を実装するのも良い考えだと思います。
Device Mapper Thin-Provisioning を活用すると、ストレージとしての活用範囲が広がります。

2016年11月13日日曜日

LIO Cluster [LIO, DRBD, Pacemaker による冗長化 iSCSI Target] (その9)Pacemaker にさせたいこと


あとは、Pacemaker にリソースを登録するだけですが、登録する前に、Pacemaker にさせたいことを整理する意味で、コマンドで一つ一つのリソースを操作し、スイッチオーバ(手動フェイルオーバ)させてみます。

Active 機で、VIP を削除します。


sudo ip addr del 10.110.88.59/26 dev bond0

ip addr show bond0
6: bond0: <BROADCAST,MULTICAST,MASTER,UP,LOWER_UP> mtu 9000 qdisc noqueue state UNKNOWN
    link/ether 00:0c:29:0b:ab:b0 brd ff:ff:ff:ff:ff:ff
    inet 10.110.88.57/26 brd 10.110.88.63 scope global bond0
       valid_lft forever preferred_lft forever


Active 機で、LIO の設定をクリアします。


sudo targetctl clear

sudo targetcli ls /
o- / ..................................................................... [...]
  o- backstores .......................................................... [...]
  | o- block .............................................. [Storage Objects: 0]
  | o- fileio ............................................. [Storage Objects: 0]
  | o- pscsi .............................................. [Storage Objects: 0]
  | o- ramdisk ............................................ [Storage Objects: 0]
  o- iscsi ........................................................ [Targets: 0]
  o- loopback ..................................................... [Targets: 0]


Active 機で、DRBD 上の LVM ボリュームグループを非活性化します。


sudo vgchange -a n vg1
  0 logical volume(s) in volume group "vg1" now active

sudo lvs
  LV       VG   Attr       LSize   Pool Origin Data%  Meta%  Move Log Cpy%Sync Convert
  lv-drbd0 vg0  -wi-ao----   1.76t
  lv-lun0  vg1  -wi------- 359.98g
  lv-lun1  vg1  -wi------- 359.98g
  lv-lun2  vg1  -wi------- 359.98g
  lv-lun3  vg1  -wi------- 359.98g


Active 機で、DRBD リソースを secondary 化(デモート)します。


sudo drbdadm secondary all

cat /proc/drbd
version: 8.4.5 (api:1/proto:86-101)
srcversion: 1AEFF755B8BD61B81A0AF27
 0: cs:Connected ro:Secondary/Secondary ds:UpToDate/UpToDate C r-----
    ns:0 nr:0 dw:0 dr:2256 al:0 bm:0 lo:0 pe:0 ua:0 ap:0 ep:1 wo:f oos:0


Active 機と Stand-by 機で、drbd.service を停止します。


sudo systemctl stop drbd.service

cat /proc/drbd
cat: /proc/drbd: No such file or directory


※ Pacemaker によるスイッチオーバ動作時には、drbd サービスは停止させません。

ここまでの作業で、Pacemaker に登録する全てのリソースが停止できました。

今度は、Stand-by 機側でリソースを起動していきます。

Active 機と Stand-by 機で、drbd.service をほぼ同時に起動します。


sudo systemctl start drbd.service

cat /proc/drbd
version: 8.4.5 (api:1/proto:86-101)
srcversion: 1AEFF755B8BD61B81A0AF27
 0: cs:Connected ro:Secondary/Secondary ds:UpToDate/UpToDate C r-----
    ns:0 nr:0 dw:0 dr:0 al:0 bm:0 lo:0 pe:0 ua:0 ap:0 ep:1 wo:f oos:0


※ drbd.service は Active 機だけではなく、Stand-by 機側でも起動する必要があります。HA 構成のクラスタとしては、制御方法が珍しい部類に入るリソースです。

Stand-by 機で、DRBD リソースを primary 化(プロモート)します。


sudo drbdadm primary all

cat /proc/drbd
version: 8.4.5 (api:1/proto:86-101)
srcversion: 1AEFF755B8BD61B81A0AF27
 0: cs:Connected ro:Primary/Secondary ds:UpToDate/UpToDate C r-----
    ns:0 nr:0 dw:0 dr:152 al:0 bm:0 lo:0 pe:0 ua:0 ap:0 ep:1 wo:f oos:0


Stand-by 機で、DRBD 上の LVM ボリュームグループを活性化します。


sudo vgscan
  Reading all physical volumes.  This may take a while...
  Found volume group "vg0" using metadata type lvm2
  Found volume group "vg1" using metadata type lvm2

sudo vgchange -a y vg1
  4 logical volume(s) in volume group "vg1" now active

sudo lvs
  LV       VG   Attr       LSize   Pool Origin Data%  Meta%  Move Log Cpy%Sync Convert
  lv-drbd0 vg0  -wi-ao----   1.76t
  lv-lun0  vg1  -wi-a----- 359.98g
  lv-lun1  vg1  -wi-a----- 359.98g
  lv-lun2  vg1  -wi-a----- 359.98g
  lv-lun3  vg1  -wi-a----- 359.98g


Stand-by 機で、LIO 設定をリストアします。


sudo targetctl restore

sudo targetcli ls /
o- / ..................................................................... [...]
  o- backstores .......................................................... [...]
  | o- block .............................................. [Storage Objects: 4]
  | | o- lun0 ............... [/dev/vg1/lv-lun0 (360.0GiB) write-thru activated]
  | | o- lun1 ............... [/dev/vg1/lv-lun1 (360.0GiB) write-thru activated]
  | | o- lun2 ............... [/dev/vg1/lv-lun2 (360.0GiB) write-thru activated]
  | | o- lun3 ............... [/dev/vg1/lv-lun3 (360.0GiB) write-thru activated]
  | o- fileio ............................................. [Storage Objects: 0]
  | o- pscsi .............................................. [Storage Objects: 0]
  | o- ramdisk ............................................ [Storage Objects: 0]
  o- iscsi ........................................................ [Targets: 1]
  | o- iqn.2016-09.com.example:iscsitgt01 ............................ [TPGs: 1]
  |   o- tpg1 ........................................... [no-gen-acls, no-auth]
  |     o- acls ...................................................... [ACLs: 4]
  |     | o- iqn.2016-09.com.example:initiator01 .............. [Mapped LUNs: 4]
  |     | | o- mapped_lun0 .............................. [lun0 block/lun0 (rw)]
  |     | | o- mapped_lun1 .............................. [lun1 block/lun1 (rw)]
  |     | | o- mapped_lun2 .............................. [lun2 block/lun2 (rw)]
  |     | | o- mapped_lun3 .............................. [lun3 block/lun3 (rw)]
  |     | o- iqn.2016-09.com.example:initiator02 .............. [Mapped LUNs: 4]
  |     | | o- mapped_lun0 .............................. [lun0 block/lun0 (rw)]
  |     | | o- mapped_lun1 .............................. [lun1 block/lun1 (rw)]
  |     | | o- mapped_lun2 .............................. [lun2 block/lun2 (rw)]
  |     | | o- mapped_lun3 .............................. [lun3 block/lun3 (rw)]
  |     | o- iqn.2016-09.com.example:initiator03 .............. [Mapped LUNs: 4]
  |     | | o- mapped_lun0 .............................. [lun0 block/lun0 (rw)]
  |     | | o- mapped_lun1 .............................. [lun1 block/lun1 (rw)]
  |     | | o- mapped_lun2 .............................. [lun2 block/lun2 (rw)]
  |     | | o- mapped_lun3 .............................. [lun3 block/lun3 (rw)]
  |     | o- iqn.2016-09.com.example:initiator04 .............. [Mapped LUNs: 4]
  |     |   o- mapped_lun0 .............................. [lun0 block/lun0 (rw)]
  |     |   o- mapped_lun1 .............................. [lun1 block/lun1 (rw)]
  |     |   o- mapped_lun2 .............................. [lun2 block/lun2 (rw)]
  |     |   o- mapped_lun3 .............................. [lun3 block/lun3 (rw)]
  |     o- luns ...................................................... [LUNs: 4]
  |     | o- lun0 .............................. [block/lun0 (/dev/vg1/lv-lun0)]
  |     | o- lun1 .............................. [block/lun1 (/dev/vg1/lv-lun1)]
  |     | o- lun2 .............................. [block/lun2 (/dev/vg1/lv-lun2)]
  |     | o- lun3 .............................. [block/lun3 (/dev/vg1/lv-lun3)]
  |     o- portals ................................................ [Portals: 1]
  |       o- 10.110.88.59:3260 ............................................ [OK]
  o- loopback ..................................................... [Targets: 0]


Stand-by 機で、VIP を追加します。


sudo ip addr add 10.110.88.59/26 dev bond0

ip addr show bond0
6: bond0: <BROADCAST,MULTICAST,MASTER,UP,LOWER_UP> mtu 9000 qdisc noqueue state UNKNOWN
    link/ether 00:0c:29:c4:fe:24 brd ff:ff:ff:ff:ff:ff
    inet 10.110.88.58/26 brd 10.110.88.63 scope global bond0
       valid_lft forever preferred_lft forever
    inet 10.110.88.59/26 scope global secondary bond0
       valid_lft forever preferred_lft forever


次回は、Pacemaker にリソースを登録するので、前半の手順を主に Stand-by 機側で実行し、全てのリソースを停止させておきます。

2016年11月11日金曜日

LIO Cluster [LIO, DRBD, Pacemaker による冗長化 iSCSI Target] (その8)LIO


LIO の設定を行います。

Active 機と Stand-by 機で targetcli コマンドの設定を確認します。


sudo targetcli get global
Warning: Could not load preferences file /root/.targetcli/prefs.bin.
GLOBAL CONFIG GROUP
===================
auto_add_default_portal=true
----------------------------
If true, adds a portal listening on all IPs to new targets.

auto_add_mapped_luns=true
-------------------------
If true, automatically create node ACLs mapped LUNs after creating a new target LUN or a new node ACL

auto_cd_after_create=false
--------------------------
If true, changes current path to newly created objects.

auto_enable_tpgt=true
---------------------
If true, automatically enables TPGTs upon creation.

auto_save_on_exit=true
----------------------
If true, saves configuration on exit.

color_command=cyan
------------------
Color to use for command completions.

color_default=none
------------------
Default text display color.

color_keyword=cyan
------------------
Color to use for keyword completions.

color_mode=true
---------------
Console color display mode.

color_parameter=magenta
-----------------------
Color to use for parameter completions.

color_path=magenta
------------------
Color to use for path completions

export_backstore_name_as_model=true
-----------------------------------
If true, the backstore name is used for the scsi inquiry model name.

logfile=/root/.targetcli/log.txt
--------------------------------
Logfile to use.

loglevel_console=info
---------------------
Log level for messages going to the console.

loglevel_file=debug
-------------------
Log level for messages going to the log file.

prompt_length=30
----------------
Max length of the shell prompt path, 0 for infinite.

tree_max_depth=0
----------------
Maximum depth of displayed node tree.

tree_round_nodes=true
---------------------
Tree node display style.

tree_show_root=true
-------------------
Whether or not to display tree root.

tree_status_mode=true
---------------------
Whether or not to display status in tree.


Active 機と Stand-by 機で、targetcli から exit する際に自動的に設定を save する挙動を無効化します。


sudo targetcli set global auto_save_on_exit=false
Parameter auto_save_on_exit is now 'false'.


Active 機と Stand-by 機で、targetcli から target を追加する際に自動的に portal がデフォルト値で作成される挙動を無効化します。


sudo targetcli set global auto_add_default_portal=false
Parameter auto_add_default_portal is now 'false'.


Active 機で、targetcli から 状態を確認します。


sudo targetcli ls /
o- / ..................................................................... [...]
  o- backstores .......................................................... [...]
  | o- block .............................................. [Storage Objects: 0]
  | o- fileio ............................................. [Storage Objects: 0]
  | o- pscsi .............................................. [Storage Objects: 0]
  | o- ramdisk ............................................ [Storage Objects: 0]
  o- iscsi ........................................................ [Targets: 0]
  o- loopback ..................................................... [Targets: 0]


Active 機で、IQN を定義します。


sudo targetcli /iscsi create iqn.2016-09.com.example:iscsitgt01
Created target iqn.2016-09.com.example:iscsitgt01.
Created TPG 1.

sudo targetcli ls /
o- / ..................................................................... [...]
  o- backstores .......................................................... [...]
  | o- block .............................................. [Storage Objects: 0]
  | o- fileio ............................................. [Storage Objects: 0]
  | o- pscsi .............................................. [Storage Objects: 0]
  | o- ramdisk ............................................ [Storage Objects: 0]
  o- iscsi ........................................................ [Targets: 1]
  | o- iqn.2016-09.com.example:iscsitgt01 ............................ [TPGs: 1]
  |   o- tpg1 ........................................... [no-gen-acls, no-auth]
  |     o- acls ...................................................... [ACLs: 0]
  |     o- luns ...................................................... [LUNs: 0]
  |     o- portals ................................................ [Portals: 0]
  o- loopback ..................................................... [Targets: 0]


Active 機で、ACL(アクセス許可リスト)にイニシエータ名を登録します。必要に応じて CHAP 認証情報も紐付けします。認証なしとしたい場合には、この作業をスキップします。


sudo targetcli /iscsi/iqn.2016-09.com.example:iscsitgt01/tpg1/acls create iqn.2016-09.com.example:initiator01
Created Node ACL for iqn.2016-09.com.example:initiator01

  sudo targetcli /iscsi/iqn.2016-09.com.example:iscsitgt01/tpg1/acls/iqn.2016-09.com.example:initiator01 set auth userid=iscsiuser01
Parameter userid is now 'iscsiuser01'.

  sudo targetcli /iscsi/iqn.2016-09.com.example:iscsitgt01/tpg1/acls/iqn.2016-09.com.example:initiator01 set auth password=password-user01
Parameter password is now 'password-user01'.


sudo targetcli /iscsi/iqn.2016-09.com.example:iscsitgt01/tpg1/acls create iqn.2016-09.com.example:initiator02
Created Node ACL for iqn.2016-09.com.example:initiator02

  sudo targetcli /iscsi/iqn.2016-09.com.example:iscsitgt01/tpg1/acls/iqn.2016-09.com.example:initiator02 set auth userid=iscsiuser02
Parameter userid is now 'iscsiuser02'.

  sudo targetcli /iscsi/iqn.2016-09.com.example:iscsitgt01/tpg1/acls/iqn.2016-09.com.example:initiator02 set auth password=password-user02
Parameter password is now 'password-user02'.


sudo targetcli /iscsi/iqn.2016-09.com.example:iscsitgt01/tpg1/acls create iqn.2016-09.com.example:initiator03
Created Node ACL for iqn.2016-09.com.example:initiator03

  sudo targetcli /iscsi/iqn.2016-09.com.example:iscsitgt01/tpg1/acls/iqn.2016-09.com.example:initiator03 set auth userid=iscsiuser03
Parameter userid is now 'iscsiuser03'.

  sudo targetcli /iscsi/iqn.2016-09.com.example:iscsitgt01/tpg1/acls/iqn.2016-09.com.example:initiator03 set auth password=password-user03
Parameter password is now 'password-user03'.


sudo targetcli /iscsi/iqn.2016-09.com.example:iscsitgt01/tpg1/acls create iqn.2016-09.com.example:initiator04
Created Node ACL for iqn.2016-09.com.example:initiator04

  sudo targetcli /iscsi/iqn.2016-09.com.example:iscsitgt01/tpg1/acls/iqn.2016-09.com.example:initiator04 set auth userid=iscsiuser04
Parameter userid is now 'iscsiuser04'.

  sudo targetcli /iscsi/iqn.2016-09.com.example:iscsitgt01/tpg1/acls/iqn.2016-09.com.example:initiator04 set auth password=password-user04
Parameter password is now 'password-user04'.

sudo targetcli ls /
o- / ..................................................................... [...]
  o- backstores .......................................................... [...]
  | o- block .............................................. [Storage Objects: 0]
  | o- fileio ............................................. [Storage Objects: 0]
  | o- pscsi .............................................. [Storage Objects: 0]
  | o- ramdisk ............................................ [Storage Objects: 0]
  o- iscsi ........................................................ [Targets: 1]
  | o- iqn.2016-09.com.example:iscsitgt01 ............................ [TPGs: 1]
  |   o- tpg1 ........................................... [no-gen-acls, no-auth]
  |     o- acls ...................................................... [ACLs: 4]
  |     | o- iqn.2016-09.com.example:initiator01 .............. [Mapped LUNs: 0]
  |     | o- iqn.2016-09.com.example:initiator02 .............. [Mapped LUNs: 0]
  |     | o- iqn.2016-09.com.example:initiator03 .............. [Mapped LUNs: 0]
  |     | o- iqn.2016-09.com.example:initiator04 .............. [Mapped LUNs: 0]
  |     o- luns ...................................................... [LUNs: 0]
  |     o- portals ................................................ [Portals: 0]
  o- loopback ..................................................... [Targets: 0]


Active 機で、バックエンド・デバイスを指定し、IQN に紐付けます。


sudo targetcli /backstores/block create name=lun0 dev=/dev/vg1/lv-lun0
Created block storage object lun0 using /dev/vg1/lv-lun0.

sudo targetcli /iscsi/iqn.2016-09.com.example:iscsitgt01/tpg1/luns create /backstores/block/lun0
Created LUN 0.
Created LUN 0->0 mapping in node ACL iqn.2016-09.com.example:initiator04
Created LUN 0->0 mapping in node ACL iqn.2016-09.com.example:initiator03
Created LUN 0->0 mapping in node ACL iqn.2016-09.com.example:initiator02
Created LUN 0->0 mapping in node ACL iqn.2016-09.com.example:initiator01


sudo targetcli /backstores/block create name=lun1 dev=/dev/vg1/lv-lun1
Created block storage object lun1 using /dev/vg1/lv-lun1.

sudo targetcli /iscsi/iqn.2016-09.com.example:iscsitgt01/tpg1/luns create /backstores/block/lun1
Created LUN 1.
Created LUN 1->1 mapping in node ACL iqn.2016-09.com.example:initiator04
Created LUN 1->1 mapping in node ACL iqn.2016-09.com.example:initiator03
Created LUN 1->1 mapping in node ACL iqn.2016-09.com.example:initiator02
Created LUN 1->1 mapping in node ACL iqn.2016-09.com.example:initiator01


sudo targetcli /backstores/block create name=lun2 dev=/dev/vg1/lv-lun2
Created block storage object lun2 using /dev/vg1/lv-lun2.

sudo targetcli /iscsi/iqn.2016-09.com.example:iscsitgt01/tpg1/luns create /backstores/block/lun2
Created LUN 2.
Created LUN 2->2 mapping in node ACL iqn.2016-09.com.example:initiator04
Created LUN 2->2 mapping in node ACL iqn.2016-09.com.example:initiator03
Created LUN 2->2 mapping in node ACL iqn.2016-09.com.example:initiator02
Created LUN 2->2 mapping in node ACL iqn.2016-09.com.example:initiator01


sudo targetcli /backstores/block create name=lun3 dev=/dev/vg1/lv-lun3
Created block storage object lun3 using /dev/vg1/lv-lun3.

sudo targetcli /iscsi/iqn.2016-09.com.example:iscsitgt01/tpg1/luns create /backstores/block/lun3
Created LUN 3.
Created LUN 3->3 mapping in node ACL iqn.2016-09.com.example:initiator04
Created LUN 3->3 mapping in node ACL iqn.2016-09.com.example:initiator03
Created LUN 3->3 mapping in node ACL iqn.2016-09.com.example:initiator02
Created LUN 3->3 mapping in node ACL iqn.2016-09.com.example:initiator01

sudo targetcli ls /
o- / ..................................................................... [...]
  o- backstores .......................................................... [...]
  | o- block .............................................. [Storage Objects: 4]
  | | o- lun0 ............... [/dev/vg1/lv-lun0 (360.0GiB) write-thru activated]
  | | o- lun1 ............... [/dev/vg1/lv-lun1 (360.0GiB) write-thru activated]
  | | o- lun2 ............... [/dev/vg1/lv-lun2 (360.0GiB) write-thru activated]
  | | o- lun3 ............... [/dev/vg1/lv-lun3 (360.0GiB) write-thru activated]
  | o- fileio ............................................. [Storage Objects: 0]
  | o- pscsi .............................................. [Storage Objects: 0]
  | o- ramdisk ............................................ [Storage Objects: 0]
  o- iscsi ........................................................ [Targets: 1]
  | o- iqn.2016-09.com.example:iscsitgt01 ............................ [TPGs: 1]
  |   o- tpg1 ........................................... [no-gen-acls, no-auth]
  |     o- acls ...................................................... [ACLs: 4]
  |     | o- iqn.2016-09.com.example:initiator01 .............. [Mapped LUNs: 4]
  |     | | o- mapped_lun0 .............................. [lun0 block/lun0 (rw)]
  |     | | o- mapped_lun1 .............................. [lun1 block/lun1 (rw)]
  |     | | o- mapped_lun2 .............................. [lun2 block/lun2 (rw)]
  |     | | o- mapped_lun3 .............................. [lun3 block/lun3 (rw)]
  |     | o- iqn.2016-09.com.example:initiator02 .............. [Mapped LUNs: 4]
  |     | | o- mapped_lun0 .............................. [lun0 block/lun0 (rw)]
  |     | | o- mapped_lun1 .............................. [lun1 block/lun1 (rw)]
  |     | | o- mapped_lun2 .............................. [lun2 block/lun2 (rw)]
  |     | | o- mapped_lun3 .............................. [lun3 block/lun3 (rw)]
  |     | o- iqn.2016-09.com.example:initiator03 .............. [Mapped LUNs: 4]
  |     | | o- mapped_lun0 .............................. [lun0 block/lun0 (rw)]
  |     | | o- mapped_lun1 .............................. [lun1 block/lun1 (rw)]
  |     | | o- mapped_lun2 .............................. [lun2 block/lun2 (rw)]
  |     | | o- mapped_lun3 .............................. [lun3 block/lun3 (rw)]
  |     | o- iqn.2016-09.com.example:initiator04 .............. [Mapped LUNs: 4]
  |     |   o- mapped_lun0 .............................. [lun0 block/lun0 (rw)]
  |     |   o- mapped_lun1 .............................. [lun1 block/lun1 (rw)]
  |     |   o- mapped_lun2 .............................. [lun2 block/lun2 (rw)]
  |     |   o- mapped_lun3 .............................. [lun3 block/lun3 (rw)]
  |     o- luns ...................................................... [LUNs: 4]
  |     | o- lun0 .............................. [block/lun0 (/dev/vg1/lv-lun0)]
  |     | o- lun1 .............................. [block/lun1 (/dev/vg1/lv-lun1)]
  |     | o- lun2 .............................. [block/lun2 (/dev/vg1/lv-lun2)]
  |     | o- lun3 .............................. [block/lun3 (/dev/vg1/lv-lun3)]
  |     o- portals ................................................ [Portals: 0]
  o- loopback ..................................................... [Targets: 0]


※ 今回試してみた範囲では、ここで「block」ではなく「fileio」を選ぶと、デバイス名が「/dev/dm-1」等という名前で保存されてしまい、再起動後やフェイルオーバー先で同じデバイス名となることが保証されないため、udev の設定変更も加える等の処置が追加で必要となるはずです。LVM 論理ボリュームを指定する場合は「block」を利用することをお奨めします。

※ ここでは、1つの Target IQN に複数の LUN を紐付けました。複数の IQN を用意し、1 IQN に 1 LUN という方が、きめ細かく設定できます。

2016/11/20追記
※ 1つの Target IQN に tpg が1つ紐付くわけですが、この1つの tpg が CPU の 1Core しか活用してくれないので、マルチコア、マルチプロセッサ環境で複数の LUN をエクスポートしたい場合には、1 IQN に 1 LUN という設定が推奨となります。10Gbit Ethernet 環境では、1 IQN には、多くても 4 LUN までにとどめておくべきです。

Active 機で、IQN に portal を作成します。


sudo targetcli /iscsi/iqn.2016-09.com.example:iscsitgt01/tpg1/portals create 10.110.88.58 3260
Using default IP port 3260
Created network portal 10.110.88.59:3260.

sudo targetcli ls /
o- / ..................................................................... [...]
  o- backstores .......................................................... [...]
  | o- block .............................................. [Storage Objects: 4]
  | | o- lun0 ............... [/dev/vg1/lv-lun0 (360.0GiB) write-thru activated]
  | | o- lun1 ............... [/dev/vg1/lv-lun1 (360.0GiB) write-thru activated]
  | | o- lun2 ............... [/dev/vg1/lv-lun2 (360.0GiB) write-thru activated]
  | | o- lun3 ............... [/dev/vg1/lv-lun3 (360.0GiB) write-thru activated]
  | o- fileio ............................................. [Storage Objects: 0]
  | o- pscsi .............................................. [Storage Objects: 0]
  | o- ramdisk ............................................ [Storage Objects: 0]
  o- iscsi ........................................................ [Targets: 1]
  | o- iqn.2016-09.com.example:iscsitgt01 ............................ [TPGs: 1]
  |   o- tpg1 ........................................... [no-gen-acls, no-auth]
  |     o- acls ...................................................... [ACLs: 4]
  |     | o- iqn.2016-09.com.example:initiator01 .............. [Mapped LUNs: 4]
  |     | | o- mapped_lun0 .............................. [lun0 block/lun0 (rw)]
  |     | | o- mapped_lun1 .............................. [lun1 block/lun1 (rw)]
  |     | | o- mapped_lun2 .............................. [lun2 block/lun2 (rw)]
  |     | | o- mapped_lun3 .............................. [lun3 block/lun3 (rw)]
  |     | o- iqn.2016-09.com.example:initiator02 .............. [Mapped LUNs: 4]
  |     | | o- mapped_lun0 .............................. [lun0 block/lun0 (rw)]
  |     | | o- mapped_lun1 .............................. [lun1 block/lun1 (rw)]
  |     | | o- mapped_lun2 .............................. [lun2 block/lun2 (rw)]
  |     | | o- mapped_lun3 .............................. [lun3 block/lun3 (rw)]
  |     | o- iqn.2016-09.com.example:initiator03 .............. [Mapped LUNs: 4]
  |     | | o- mapped_lun0 .............................. [lun0 block/lun0 (rw)]
  |     | | o- mapped_lun1 .............................. [lun1 block/lun1 (rw)]
  |     | | o- mapped_lun2 .............................. [lun2 block/lun2 (rw)]
  |     | | o- mapped_lun3 .............................. [lun3 block/lun3 (rw)]
  |     | o- iqn.2016-09.com.example:initiator04 .............. [Mapped LUNs: 4]
  |     |   o- mapped_lun0 .............................. [lun0 block/lun0 (rw)]
  |     |   o- mapped_lun1 .............................. [lun1 block/lun1 (rw)]
  |     |   o- mapped_lun2 .............................. [lun2 block/lun2 (rw)]
  |     |   o- mapped_lun3 .............................. [lun3 block/lun3 (rw)]
  |     o- luns ...................................................... [LUNs: 4]
  |     | o- lun0 .............................. [block/lun0 (/dev/vg1/lv-lun0)]
  |     | o- lun1 .............................. [block/lun1 (/dev/vg1/lv-lun1)]
  |     | o- lun2 .............................. [block/lun2 (/dev/vg1/lv-lun2)]
  |     | o- lun3 .............................. [block/lun3 (/dev/vg1/lv-lun3)]
  |     o- portals ................................................ [Portals: 1]
  |       o- 10.110.88.59:3260 ............................................ [OK]
  o- loopback ..................................................... [Targets: 0]

sudo ss -ant | grep LISTEN.\*:3260
LISTEN     0      256    10.110.88.59:3260                     *:*


Active 機で、設定ファイルに設定を保存し、Stand-by 機にコピーします。


sudo targetcli saveconfig
Last 10 configs saved in /etc/target/backup.
Configuration saved to /etc/target/saveconfig.json

sudo scp -p /etc/target/saveconfig.json iscsitgt01s:/etc/target/saveconfig.json
saveconfig.json                               100% 8709     8.5KB/s   00:00


Active 機と Stand-by 機で、LIO のリソース・エージェントを作成します。


cat << 'EOF_LIO' | sudo tee /usr/lib/ocf/resource.d/heartbeat/LIO
#!/bin/bash
#
#     LIO OCF RA. manages iSCSI target LIO.
#
#   (c) 2009-2010 Florian Haas, Dejan Muhamedagic,
#                 and Linux-HA contributors
#
#      modified by Katsuaki Hamada (hamada@pc-office.net), 10 Dec 2016
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of version 2 of the GNU General Public License as
# published by the Free Software Foundation.
#
# This program is distributed in the hope that it would be useful, but
# WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
#
# Further, this software is distributed without any warranty that it is
# free of the rightful claim of any third person regarding infringement
# or the like.  Any license provided herein, whether implied or
# otherwise, applies only to this software file.  Patent licenses, if
# any, provided herein do not apply to combinations of this program with
# other software, or any other product whatsoever.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write the Free Software Foundation,
# Inc., 59 Temple Place - Suite 330, Boston MA 02111-1307, USA.
#

#######################################################################
# Initialization:
: ${OCF_FUNCTIONS_DIR=${OCF_ROOT}/lib/heartbeat}
. ${OCF_FUNCTIONS_DIR}/ocf-shellfuncs

# Lockfile, used for selecting a target ID
LOCKFILE=${HA_RSCTMP}/target.lock
#######################################################################

meta_data() {
        cat <<END
<?xml version="1.0"?>
<!DOCTYPE resource-agent SYSTEM "ra-api-1.dtd">
<resource-agent name="LIO" version="1.0">
<version>0.9</version>

<longdesc lang="en">
Manages iSCSI target LIO. An iSCSI target is a collection of SCSI Logical
Units (LUs) exported via a daemon that speaks the iSCSI protocol.
</longdesc>
<shortdesc lang="en">iSCSI target export agent</shortdesc>

<parameters>
<parameter name="iqn" required="0" unique="1">
<longdesc lang="en">
The target iSCSI Qualified Name (IQN). Should follow the conventional
iqn.yyyy-mm.&lt;reversed domain name&gt;[:identifier] syntax.
</longdesc>
<shortdesc lang="en">iSCSI target IQN</shortdesc>
<content type="string" />
</parameter>
</parameters>

<actions>
<action name="start" timeout="10" />
<action name="stop" timeout="10" />
<action name="status" timeout="10" interval="10" depth="0" />
<action name="monitor" timeout="10" interval="10" depth="0" />
<action name="meta-data" timeout="5" />
<action name="validate-all" timeout="10" />
</actions>
</resource-agent>
END
}

#######################################################################

LIO_usage() {
  cat <<END
usage: $0 {start|stop|status|monitor|validate-all|meta-data}

Expects to have a fully populated OCF RA-compliant environment set.
END
}

LIO_start() {
  LIO_monitor
  [ $? = $OCF_SUCCESS ] && return $OCF_SUCCESS
  /usr/bin/timeout 3 /usr/bin/targetctl restore
  LIO_monitor
}

LIO_stop() {
  LIO_monitor
  [ $? -eq $OCF_NOT_RUNNING ] && return $OCF_SUCCESS
  /usr/bin/timeout 3 /usr/bin/targetctl clear
  rc=$?
  [ $rc -eq 0 ] && return $OCF_SUCCESS
  [ -e /etc/ha.d/noreboot ] && return $rc
  echo 1 > /proc/sys/kernel/sysrq
  echo s > /proc/sysrq-trigger
  echo u > /proc/sysrq-trigger
  echo c > /proc/sysrq-trigger
  /sbin/reboot -f
  return $rc
}

LIO_monitor() {
  for i in /sys/kernel/config/target/iscsi/iqn.*
  do
    [ -d $i ] && [ $(cat $i/tpgt_1/enable) -eq 1 ] && return $OCF_SUCCESS
  done
  return $OCF_NOT_RUNNING
}

LIO_validate() {
  if ! ocf_is_probe; then
    # Do we have all required binaries?
    check_binary targetctl
  fi
  return $OCF_SUCCESS
}

case $1 in
  meta-data)  meta_data; exit $OCF_SUCCESS;;
  usage|help) LIO_usage; exit $OCF_SUCCESS;;
esac

# Everything except usage and meta-data must pass the validate test
LIO_validate

case $__OCF_ACTION in
  start)          LIO_start;;
  stop)           LIO_stop;;
  monitor|status) LIO_monitor;;
  reload)         ocf_log err "Reloading..."; LIO_start;;
  validate-all)   ;;
  *)              LIO_usage; exit $OCF_ERR_UNIMPLEMENTED;;
esac
rc=$?
ocf_log debug "${OCF_RESOURCE_INSTANCE} $__OCF_ACTION : $rc"
exit $rc
EOF_LIO
sudo chmod 755 /usr/lib/ocf/resource.d/heartbeat/LIO


※ 2016/12/10
targetctl, targetcli コマンドが応答不能になるケース(LIO のバグ)が見つかったので、stop に関して、3秒以内に応答がない場合は強制的に OS を再起動するように変更しました。
但し、/etc/ha.d/noreboot というファイルが存在する場合は、単にエラーを返します。
start に関しては、3秒でタイムアウトするように変更しました。


※ 当初は、systemd の target.service をリソース・エージェントとして利用しようと考えていました。スイッチオーバはうまく動くのですが、クラスタを停止しようとした場合にエラーが発生します。oneshot タイプだとうまくいかないのかと考え、sleep するだけのデーモンプロセスを作ってみました。どうも Pacemaker のプロセス処理で、リソース・エージェントの子プロセスに対する処理はしていない(考慮事項が足りない)ようで、かつ、終了時には stop メソッドも呼び出さないらしく、エラーを解消することができませんでした。以下のようなロジックで TERM シグナルを送ってくれればいいと思うのですが、そうではないようで、残念です。

killpstree(){
  kill -STOP $1
  for i in $(ps -o pid --no-heading --ppid $1)
  do
    killpstree $i
  done
  kill $2 $1
  kill -CONT $1
}
killpstree $(cat /run/target.pid) -TERM

※ このリソース・エージェントは、標準のリソース・エージェントとは設計思想が異なります。標準のリソース・エージェントは、サービスの内部のリソースまで管理し、種々の iSCSI Target で同じようによう扱えるように標準化しようという目標の元、処理が複雑化しています。私が作ったリソース・エージェントは、単純に、target.service の置き換えとなるようにしました。
単純なおかげで、iSCSITarget リソース・エージェントからの改造にかかった時間も1時間ほどですみました。他の iSCSI Target のことは考えなくてよいので、LIO の全ての機能を利用可能です。改造元のリソース・エージェントは、LIO の CHAP 認証機能を扱う機構が組み込まれていませんでした。

Active 機と Stand-by 機で、VIP 用のリソースエージェントを作ります。作るというよりも、IPaddr2  リソースエージェントの名前を VIP にリネームします。


sed -e 's/IPaddr2/VIP/g' /usr/lib/ocf/resource.d/heartbeat/IPaddr2 | sudo tee /usr/lib/ocf/resource.d/heartbeat/VIP > /dev/null
sudo chmod 755 /usr/lib/ocf/resource.d/heartbeat/VIP


Active 機で、VIP を追加します。


sudo ip addr add 10.110.88.59/26 dev bond0

ip addr show bond0
6: bond0: <BROADCAST,MULTICAST,MASTER,UP,LOWER_UP> mtu 9000 qdisc noqueue state UNKNOWN
    link/ether 00:0c:29:0b:ab:b0 brd ff:ff:ff:ff:ff:ff
    inet 10.110.88.57/26 brd 10.110.88.63 scope global bond0
       valid_lft forever preferred_lft forever
    inet 10.110.88.59/26 brd 10.110.88.63 scope global secondary bond0
       valid_lft forever preferred_lft forever


ここまでの操作で、イニシエータから接続が可能な状態になっています。