2015年12月4日金曜日

SuperMicro Update Managerを試してみる

SuperMicro社が提供している有償ツールのSuperMicro Update Manager(SUM)を試してみました。このツールを利用するとIPMIと同じ感覚でBIOS設定の確認や変更、BIOSファームウエアの更新が可能です。

SuperMicro Update Manager

SUM紹介ベージ

https://www.supermicro.com/solutions/SMS_SUM.cfm

Linux起動中にBIOSの設定を確認したくなることありませんか。Windows環境のマシンであればそのようなツールもあるよう気もしますが、Linux上となるとあまり聞かないと思います。以前、Linux上でEFI変数を利用する方法を試してみたのですが、設定らしきものはバイナリデータになっていて詳細不明で、設定の変更はブートデバイスの優先順位くらいしか変更できませんでした。SuperMicro社が提供しているSuperMicro Update Managerを利用すると簡単に(同社のMB限定ですが)OS起動中にBIOSの設定を確認したり変更したりすることが可能になります。

SUMの機能などの詳細な説明は上記のWebページに詳しく紹介されていますのでそちらを参照ください。今回はBIOS周りの機能を試してみました。

SUMではツールを利用して以下のことが可能です。
  • BIOS設定の取得
    • 現在の設定やデフォルトの設定などをテキストファイルベースで確認できます。
  • BIOS設定の変更
    • テキストファイルベースで設定の変更ができます。ただし変更を反映するには再起動が必要です。
  • BIOSファームウェアのアップデート
    • BIOSをアップデートをそのままの環境で実行できます(DOS環境はいりません)。ただしアップデートを反映するには再起動が必要です。
また対象のサーバにアクセスする方法として二つの方法あります。
  • リモート(Out-band)でアクセスする。
    • 別のマシンでSUMを実行してネットワーク経由で対象サーバにアクセスする
  • ローカル(In-band)でアクセスする。
    • 対象サーバ上で起動しているOS(Llnux)上でSUMを実行して自分自身にアクセスする。
IPMIと同様に実際にBIOSの設定を取得したり変更したりするのを担っているのはMB上に搭載されているコントローラです。したがって、リモートでアクセスする場合には対象サーバのOSには制限ありません。OSが起動していない状態や、通電はされていてサーバの電源は入っていない状態でもリモートアクセスであれば実行可能です。

SUMのダウンロードとインストール

SUMはソフトウェア上記のWebページのリンク先からダウンロードできますがアクセスキーが必要です。また利用にはライセンスを購入する必要があります。ただ、上記ページから評価用のライセンスを申請することができ、試せる機能も購入した場合のものとかわらないようです。評価用のライセンスの申請にはMBの型番とBMC(IPMI)のMACアドレスを合わせて申請する必要があります。申請は(英語ですが)Webのフォームに必要事項を記入して送信するとメールでライセンスとソフトウエアのダウンロード用のアクセスキーが送られてきます。評価用のライセンスはすぐに発行されるようですのでお手もとのSuperMicro社製のMBが対応していれば試してみるものもよいのではないでしょうか。

対応システム

SUMはSuperMicro社製のX10世代のMBあるいは一部のX9世代のMBを搭載したシステムで利用できます。X10というのはだいたいHaswell世代のMB、X9の一部というのはRomleyチップセットを搭載した2ソケットのMBのことです。

対応BMC(IPMI)/BIOS

SUMでBIOSをアップデートしたいのにそのためにBIOSをアップデートしないといけないというのはなんか本末転倒ですが、MBのBMC/BIOSがSUMでのアクセスに対応していないといけません。最近の製品であれば問題ないと思われますが、MBのBMC(IPMI)およびBIOSのバージョン以下の通りある必要があるようです。

リモート(Out-Band)アクセスでの利用に必要なファームウェア

BMC Version

PlatformBMC Version
X9 ATEN platform   (SMT_X9)3.14 or later
X10 ATEN platform (SMT_X10)1.52 or later
X9 AMI platform     (SMM_X9)2.32 or later

BIOS Version

SystemBIOS Version
X9 Romley and X10 Denlow systems2.0 or later
X10 Grantley systems1.0 or later

 

ローカル(In-Band)アクセスの利用に必要なファームウェア

BIOS Version

SystemBIOS Version
X9 Romley and X10 Denlow systems3.0 or later
X10 Grantley systems1.0 or later
 
またLlnux上でローカルに実行する際にBIOSによっては専用のドライバ(カーネルモジュール)が必要になるようです。今回自分がためした環境では特にBIOS/BMCのアップデートやカーネルモジュールは必要ありませんでした。

ライセンス

SUMを利用するには(有償の)のライセンスが必要です。はじめにライセンスキーを利用してMBのコントローラをactivateする必要があります。SUMのソフトウェアの実行自体には特に制限はないようですが、ライセンスキーで activateしないとコントローラがSUMからのアクセスを受け付けてくれないようです。このようにライセンスはシステム(MB)1つにつき1つ必要です。

SUMの実行環境

SUMのソフトウェアにはLinux版とWindows版がありますが、どちらも64bit用しかないようです。またSUMをつかってリモートでアクセスするためには以下のJAVAのランタイム環境が必要です。
  • OPEN JDK/Oracle JRE 1.7.0以降
ローカルで実行する場合にはJava環境は必要ないようです。今回はOPEN JDK 1.7/Oracle JRE 1.8で動作を確認しています。

SUMのダウンロードとインストール

上記のページにあるリンク先からアクセスキーを使ってSUMのソフトウェアをダウンロードできます。展開するとsumコマンドがあるのでそれを実行すればOKです。インストールする際には展開したディレクトリをそのまま適当な場所にコピーすればいいと思います。コマンド本体はsumバイナリですが、リモートでアクセスする場合は同じディレクトリある付属のjarファイルが必要があります。

SUMのコマンドの形式

SUMのコマンドの形式は次の通りです。コマンド名で各動作を指定します。

# sum -i <ターゲットのIPMIアドレス> -u <ユーザ名> -p <パスワード> -c <コマンド名> [ --file <入出力ファイル> ]
アドレスはIPMIのアドレス、ユーザ名とパスワードもIPMIのそれと一緒です。ローカルで実行する場合はIPMIのアドレス,ユーザ名,パスワードを省略して-c <コマンド名>から始めればOKです。IPアドレスを改行で区切ったリストファイルを作成してそれを-l <リストファイル名>でアドレスのかわりに指定することによって同時に複数のターゲットに対してコマンドを実行することも可能です。
基本的にはコマンドはリモートでもローカルでもどちらでも実行可能です。また、SUMのコマンドをローカルで実行する場合はroot権限が必要です。

ランセンスのアクティベーション

ますシステムのコントローラをランセンスをつかってアクティベーションする必要があります。

$ ./sum -i 192.168.0.101 -u ADMIN -p ADMIN -c ActivateProductKey --key XXXX-XXXX-XXXX-XXXX-XXXX-XXXX 
Supermicro Update Manager (for UEFI BIOS) 1.4.2 (2015/09/23) (x86_64) Copyright©2015 Super Micro Computer, Inc. All rights reserved Product key activated for 192.168.0.101

これでSUMが使えるようになりました。アクティベーションしないと基本的に全ての機能は利用できません。CheckOOBSupportコマンドでリモートでのコマンドのサポート状況を確認できます。

./sum -i 192.168.0.101 -u ADMIN -p ADMIN -i -c  CheckOOBSupport
Supermicro Update Manager (for UEFI BIOS) 1.4.2 (2015/09/23) (x86_64)
Copyright©2015 Super Micro Computer, Inc. All rights reserved

[KEY]
Node Product Key Activated.......OOB

[BMC]
BMC FW Version...................03.19
BMC Supports OOB BIOS Config.....Yes
BMC Supports OOB DMI Edit........Yes

[BIOS]
BIOS Board ID....................0821
BIOS Build Date..................2015/8/13
BIOS Supports OOB BIOS Config....Yes
BIOS Supports OOB DMI Edit.......Yes

BIOS設定の取得

早速BIOSの設定を取得してみましょう。コマンドはGetCurrentBiosCfgTextFile(長い!)です。ちなみにコマンド名の大文字小文字は区別されないので全部小文字でも大丈夫です。

# time sum -i 192.168.0.101 -u ADMIN -p ADMIN -c GetCurrentBiosCfgTextFile --file config.txt
Supermicro Update Manager (for UEFI BIOS) 1.4.2 (2015/09/23) (x86_64)
Copyright©2015 Super Micro Computer, Inc. All rights reserved


File "config.txt" is created.

real    0m15.509s
user    0m14.721s
sys     0m0.800s

timeで時間を測定してみましたがリモートで大体16-20秒くらいでした。ローカルで実行してもそんなに変わりませんが、体感リモートの方がかかる時間が短かったような気がします。--fileで指定したファイルにテキストして次のような形で出力されます(長いので割愛します)

#Please refer to SUM User's guide '4.1 Format of BIOS Settings Text File' for usage.

[Advanced|Boot Feature]
Quiet Boot=01                           // Please enter the value in 2 hexadecimal digits. Default value is <<<01>>>       
AddOn ROM Display Mode=01               // *01 (Force BIOS), 00 (Keep Current)       
Bootup NumLock State=01                 // *01 (On), 00 (Off)       
Wait For "F1" If Error=01               // 00 (Disabled), *01 (Enabled)       
INT19 Trap Response=01                  // *01 (Immediate), 00 (Postponed)       
Re-try Boot=00                          // *00 (Disabled), 01 (Legacy Boot), 02 (EFI Boot)       
Watch Dog Function=00                   // *00 (Disabled), 01 (Enabled)       
Power Button Function=01                // *01 (Instant Off), 00 (4 Seconds Override)       
Restore on AC Power Loss=02             // 00 (Stay Off), 01 (Power On), *02 (Last State)       

[Advanced|CPU Configuration]
Clock Spread Spectrum=00                // Please enter the value in 2 hexadecimal digits. Default value is <<<00>>>       
Hyper-Threading (ALL)=00                // 01 (Disable), *00 (Enable)       
Cores Enabled=00                        // Please enter the value in 2 hexadecimal digits

(以下省略)

これはただのテキストファイルですので、BIOSの設定をdiffで比較したり、gitなどにあげて管理したりする事が可能です。便利ですね。

BIOS設定の変更

BIOS設定の変更は先ほど出力した設定のテキストファイルを編集して再度読み込ませる形で行います。編集の方法はテキストファイルのコメントみれば直感的に分かるとおもいますが"="のあとの数字を変更しておこないます。例えば最初の部分を以下のように編集します。

$ cp config.txt new_config.txt
$ vi new_config
$ diff config.txt new_config.txt
4c4
< Quiet Boot=01                           // Please enter the value in 2 hexadecimal digits. Default value is <<<01>>>       
---
> Quiet Boot=00                           // Please enter the value in 2 hexadecimal digits. Default value is <<<01>>>       

変更する箇所以外の設定は削除してもしなくても問題ありません。削除しても設定の変更にかかる時間は変わらないようです。変更する場所のみを残す場合その設定の項目([ ]で囲まれている行)も一緒に残しておく必要があります。今回は設定を変更しない部分もそのままに単純に取得した設定ファイルに手を加えるだけにしています。


これの新しい設定ファイルをChangeBiosCfgコマンドで指定して変更します。
# time sum -i 192.168.0.101 -u ADMIN -p ADMIN -c ChangeBiosCfg --file new_config.txt
Supermicro Update Manager (for UEFI BIOS) 1.4.2 (2015/09/23) (x86_64)
Copyright©2015 Super Micro Computer, Inc. All rights reserved



Status: Start updating the BIOS configuration for 192.168.0.101

************************************WARNING*************************************
    Do not remove AC power from the server.
********************************************************************************

Status: The BIOS configuration is updated for 192.168.0.101

Note: You have to reboot or power up the system for the changes to take effect


real    0m17.279s
user    0m16.581s
sys     0m0.876s

時間を計ってみましたが大体20秒前後で終了しました。
上にログにもでていますが設定の変更の反映は再起動されるまで行われません。それまでは設定は今まで通りです。
サーバが通電だけれされていて起動していない状態でもBIOSの設定の変更は可能ですがその場合は起動するまで反映されません。
逆に言えば複数あるサーバに対してまとめて変更だけを実行しておいて、それぞれのサーバの再起動は可能なタイミングで別個に実行するみたいな運用も可能です。
ただ、変更はサーバが通電されていないと保持されないようです。設定は変更したものの(再)起動しないまま電源ケーブルを抜いてしまった場合などは変更が消えてキャンセルされてしまうようです。
忘れずに(再)起動するようにしましょう。

ちなみに許容される設定値以外を指定した場合など、設定に不備がある場合にはエラーになって変更されません。ご安心を。

Supermicro Update Manager (for UEFI BIOS) 1.4.2 (2015/09/23) (x86_64)
Copyright©2015 Super Micro Computer, Inc. All rights reserved


********************************<<<<<ERROR>>>>>*********************************

ExitCode             = 60
Description          = Invalid BIOS configuration text file
Program Error Code   = 2.18
Error message:
    In file fail_config.txt, line 2:
    [Advanced|Boot Feature]Quiet Boot
        Value <<<02>>> has no option.

********************************************************************************

BIOSファームウェアのアップデート

SUMをつかってBIOSのファームウェアをアップデートすることが可能です。BIOSファームウェアのアップデートなんてCriticalな作業をネットワーク越しでするってのはどうなの?という意見はあるとおもいますがとにかく可能です。
もちろんLinux上でローカルにSUMを実行してアップデートすることもできます。
コマンドはUpdateBiosです。ファイルとしてSuperMicroから配布されているBIOSファイルのバイナリイメージを直接指定します。

# unzip X10DRW5_813.zip
# ls
FLASH.BAT                    SMCIPMITool.properties       afudosu.smc                  choice.smc                   tmp.txt                     
Readme for X10 AMI BIOS.txt  X10DRW5.813                  bios_update.log              fdt.smc

# time ./sum -i 192.168.0.101 -u ADMIN -p ADMIN -c updatebios --file X10DRW5.813
Supermicro Update Manager (for UEFI BIOS) 1.4.2 (2015/09/23) (x86_64)
Copyright©2015 Super Micro Computer, Inc. All rights reserved
Status: Start updating BIOS for 192.168.0.101

************************************WARNING*************************************
    Do not remove AC power from the server.
********************************************************************************

..................................................
..................................................
..................................................
..................................................
...........
Status: BIOS is updated for 192.168.0.101

Note: You have to reboot or power up the system for the changes to take effect


real    3m41.213s
user    0m13.745s
sys     0m1.016s

リモートで4分弱ほどかかりました。最初にイメージファイルを転送しているので多分途中でネットワークが切れても大丈夫だと思いますが確認していません。
例によって再起動するまでは変更は反映されす、ファームウェアも古いままです。BIOSの設定同様、起動がかかる前に電源を完全に落としてしまうとキャンセルされてしまうのではないかと思われますがこれも確認していません。

ローカルでも実行してみました。この場合リモートに比べてかなり時間がかなりかかったのと、再起動を強制するオプションをつけないと実行できませんでした。
他にオプションを指定するなどして調整できたのかもしれませんが調べていません。

# time ./sum -c updatebios --file X10DRW5.813 --reboot
Supermicro Update Manager (for UEFI BIOS) 1.4.2 (2015/09/23) (x86_64)
Copyright©2015 Super Micro Computer, Inc. All rights reserved
sh: 1: cannot create /proc/sys/kernel/nmi_watchdog: Directory nonexistent
Reading BIOS flash ..................... (100%)
Checking BIOS ID ...
Checking ME Firmware ...
Comparing FDT for ROM file and flash.... (98%)
FDT is same, Update BIOS and ME(exclude FDT) regions....
sh: 1: cannot create /proc/sys/kernel/nmi_watchdog: Directory nonexistent
Reading BIOS flash ..................... (100%)
Checking BIOS ID ...
Checking BIOS ID ...
Writing BIOS flash ..................... (100%)
Verifying BIOS flash ................... (100%)
Checking ME Firmware ...
Putting ME data to BIOS ................ (98%)
Writing ME region in BIOS flash ...
 - FDT won't be updated when ME is not in Manufacturing mode!!
   BIOS upgrade continues...
 - Updated Recovery Loader to OPRx
 - Updated FPT, MFSB, FTPR and MFS
 - ME Entire Image done
WARNING:Must power cycle the system for the changes to take effect!


Broadcast message from root@wheezy64 (pts/0) (Fri Nov 27 15:14:59 2015):

The system is going down for reboot NOW!
                        
real    18m18.135s
user    2m30.510s
sys     5m30.040s

18分以上かかってしまいました。--rebootオプションをつけないとエラーになって実行できませんでした。この場合ファームウェアのアップデート完了後、強制的に再起動されます。

リモートでのアップデートに抵抗がなければかなり簡単にアップデートが可能なのではないでしょうか。ローカルだと時間がかかってしまったり、強制的に再起動になってしまうのがちょっと使いにくい印象ですが、 DOS環境を立ち上げてアップデートするよりもずっと簡単にアップデートが可能だと思います。

WebインターフェースでのBIOSアップデート

最近のSuperMicro社せいのMBではIPMIのWebインターフェース(IPMIのアドレスにhttpでアクセスすると利用できる)上でもBIOSのファームウェアのアップデートが可能なようです。今までもBMC(IPMI)のファームウェアのアップデートはWebインターフェースで可能でしたが、それと同じ要領でBIOSのファームウェアもアップデートできます。
その際にライセンスが必要になりますが、そのライセンスはSUMのライセンスと一緒です。おそらく、SUMでアクティベートしてあればWebインターフェスでのアップデートも利用できるようになっているとおもいます。

そのほかの機能

SUMではこれらBIOS関連以外にもBMC(IPMI)の設定の取得や変更、DMI情報の取得と変更およびAsset情報の取得なども可能です。
これらの機能は従来のツールでも可能でオマケ的なものもありますが、DMI情報を変更できるのはちょっと便利な気がします。また機会があったら試してみたいです。

まとめ

SUMを使うことによって大量にあるサーバを簡単に同一のBIOS設定にすることが可能で、いつでも設定を確認できます。
設定の確認、変更に利用するテキストファイルは可読性が高く直感的に扱えます。またテキストファイルなのでgit上などで共有する上も差分を簡単に取得でき便利です。
BIOSのファームウェアのアップデートはそう頻繁に実行するものでもないとはおもいますが、このような仕組みがあればいざいうとき便利だと思います。

Serfを試してみました。

非集中型のクラスタ管理ツールのSerfを触ってみました。クラスタ管理というと何かいろいろ大変そうなイメージですが、Serfを利用すると簡単にサーバの死活監視や情報の収集が可能になります。

Serfについて

Serfの本家サイト:https://www.serfdom.io/

Serf is a decentralized solution for cluster membership, failure detection,and orchestration. Lightweght and highly available.

本家のサイトのトップページに書かれているようにserfは軽量で高可用性の非集中型のクラスタ管理ツールです。
  • インストールは簡単。
    •  serfの静的バイナリを各サーバにコピーするだけOK。
  • マスターサーバのような全体を管理しているノードはない
    • 全てのノードで実行されているserfは平等。
  • ゴシッププロトコルを利用したノード間のメッセージングツール
    • ノード間でお互いに通信して情報を全体に伝播させる。
  • 各ノードで実行されているserf agent が情報のやりとりをする。
    • クラスタ内のノードの増減についてのイベント
    • クラスタ内のノードの生死についてのイベント
    • ユーザ独自のイベントを通知することも可能
  • イベントをトリガにして任意の処理(スクリプト)を実行できる。
    • これによっていろいろ応用が効くようになる。

    例えば、クラスタ内のノードの死活監視やノードが追加/停止したときに自動でロードバランサの設定(バランス先)を変更するなどの使い方が考えられます。
    また複数のアプリケーションを組み合わせて利用する場合に全体の統制をとるのに利用できます。元々そのような管理の仕組みのないアプリケーションの組み合わせでも全体を統制するような仕組みを構築できます。

      インストール

      公式サイトに(静的)バイナリで配布されているのでそれをダウンロードしてきて展開し適当なパスにコピーすればOKです。今回は/usr/local/binに置く事にしました。

      # wget https://releases.hashicorp.com/serf/0.6.4/serf_0.6.4_linux_amd64.zip
      # unzip  0.6.4_linux_amd64.zip
      # cp serf /usr/local/bin

      Serfではこの基本的にserfコマンドのみを利用し、serf <コマンド名> [ 引数 ...]という形式で複数の機能を実行します。

      実行方法

      今回はVagrant+Virtualboxの仮想環境で検証していますが、実マシンはもちろんコンテナ環境でも問題ないです。とりあえず、debian01,debian02という名前の2つの仮想サーバを立ち上げます。サーバのアドレスは次のようになっています。
      debian01 : 192.168.0.101
      debian02 : 192.168.0.102
      debian03 : 192.168.0.103 (後ほど出てきます)
      まだ以下のログでサーバ毎の時間がずれていますが気にしないでください(すみません)

      まずそれぞれの仮想サーバでserf agentを実行します。コマンドはそのまま実行するとforegroundでの実行になります。今回はログをそのまま表示するためにforegroundで実行していますが、実際に利用する場合はbackgroundでの実行になると思います。

      debian01上で

      root@debian01:# serf agent -node=debian01 -bind=192.168.0.101
      ==> Starting Serf agent...
      ==> Starting Serf agent RPC...
      ==> Serf agent running!
               Node name: 'debian01'
               Bind addr: '192.168.0.101:7946'
                RPC addr: '127.0.0.1:7373'
               Encrypted: false
                Snapshot: false
                 Profile: lan

      ==> Log data will now stream in as it occurs:

          2015/12/02 10:15:41 [INFO] agent: Serf agent starting
          2015/12/02 10:15:41 [INFO] serf: EventMemberJoin: debian01 192.168.0.101
          2015/12/02 10:15:42 [INFO] agent: Received event: member-join

      同様なことをdebian02上でも実行します。

       

      ノードのクラスタへの参加

      agentを実行した段階ではまだお互いに"自分のクラスタ"に属しているだけの状態です。それぞれのサーバでメンバーを確認してみると自分自身しかいません。

      root@debian01:~# serf members
      debian01  192.168.0.101:7946  alive

      root@debian02:~# serf members
      debian02  192.168.0.102:7946  alive

      どちらかのノードをもう片方のクラスタに参加させることにより同じクラスタに属して通信が可能な状態になります。debian02をdebian01のクラスタに参加させてみます。このことはdebian01をdebian02のクラスタに参加させることと同じです。debian02には自分のクラスタにdebian01が参加したというイベントが通知されます。

      root@debian02:~# serf join 192.168.0.101
      Successfully joined cluster by contacting 1 nodes.
      root@debian02:~# serf members
      debian02  192.168.0.102:7946  alive 
      debian01  192.168.0.101:7946  alive

      debian01上で確認してみてもdebian02が参加していることがわかります。

      root@debian01:~# serf members
      debian01  192.168.0.101:7946  alive 
      debian02  192.168.0.102:7946  alive

      またそれぞれのノードにノードが追加されたことが通知されています。
      debian01側

      2015/12/02 10:43:49 [INFO] serf: EventMemberJoin: debian02 192.168.0.102
      2015/12/02 10:43:50 [INFO] agent: Received event: member-join

      debian02側

      2015/12/02 10:39:16 [INFO] serf: EventMemberJoin: debian01 192.168.0.101
      2015/12/02 10:39:16 [INFO] agent: joined: 1 nodes
      2015/12/02 10:39:17 [INFO] agent: Received event: member-join
      さらにクラスタにノードを追加する場合にはノードのいずれかのメンバのクラスタに追加すればOKです。例えば3番目のノードdebian03立ち上げてをdebian02のクラスタに参加させてみましょう。次のようにserf agentの起動時にノードを指定して同時にjoinすることも可能です。

      debian03上で

      root@debian03:~# serf agent --node=debian03 --bind=192.168.0.103 --join=192.168.0.102
      ==> Starting Serf agent...
      ==> Starting Serf agent RPC...
      ==> Serf agent running!
               Node name: 'debian03'
               Bind addr: '192.168.0.103:7946'
                RPC addr: '127.0.0.1:7373'
               Encrypted: false
                Snapshot: false
                 Profile: lan
      ==> Joining cluster...(replay: false)
          Join completed. Synced with 1 initial agents

      ==> Log data will now stream in as it occurs:

          2015/12/02 10:50:11 [INFO] agent: Serf agent starting
          2015/12/02 10:50:11 [INFO] serf: EventMemberJoin: debian03 192.168.0.103
          2015/12/02 10:50:11 [INFO] agent: joining: [192.168.0.102] replay: false
          2015/12/02 10:50:11 [INFO] serf: EventMemberJoin: debian01 192.168.0.101
          2015/12/02 10:50:11 [INFO] serf: EventMemberJoin: debian02 192.168.0.102
          2015/12/02 10:50:11 [INFO] agent: joined: 1 nodes
          2015/12/02 10:50:12 [INFO] agent: Received event: member-join

      debian03はdebian01とdebian02が追加されたというイベントを受け取ります。またdebian03が追加されたというイベントはdebian02だけでなく、debian01にも伝播して通知され、3台のノードが同じクラスタに参加している状態になります。

      root@debian01:~# serf members
      debian01  192.168.33.101:7946  alive 
      debian02  192.168.33.102:7946  alive 
      debian03  192.168.33.103:7946  alive

      debian01のログ

      2015/12/02 10:55:33 [INFO] serf: EventMemberJoin: debian03 192.168.0.103
      2015/12/02 10:55:34 [INFO] agent: Received event: member-join

      ノードのクラスタからの離脱

      ノードをクラスタから離脱させるためにはそのノードのagentを停止させればOKです。正常終了した場合と、異常終了した場合とではこのときに他のサーバに通知されるイベントが異なります。

      正常終了

      正常終了するには以下方法があります。
      • serf leaveコマンドを実行
      • SIGINTあるいはCtrl-Cでserf agentプロセスを終了させる。
      正常終了させた場合は終了したという通知がそのagentから発せられクラスタの各ノードに伝播します。ここではdebian03で(フォアグランドで実行していた)agentをCtrl-Cで終了させてみます。

      debian03でCtrl-C

      ^C==> Caught signal: interrupt
      ==> Gracefully shutting down agent...
          2015/12/02 10:58:49 [INFO] agent: requesting graceful leave from Serf
          2015/12/02 10:58:49 [INFO] serf: EventMemberLeave: debian03 192.168.0.103
          2015/12/02 10:58:49 [INFO] agent: requesting serf shutdown
          2015/12/02 10:58:49 [INFO] agent: shutdown complete

       debian01,debian02にはそれぞれmember-leaveのイベントが通知されているのが分かります。
      debian01
      2015/12/02 11:04:51 [INFO] serf: EventMemberLeave: debian03 192.168.0.103
      2015/12/02 11:04:52 [INFO] agent: Received event: member-leave

      debian02
      2015/12/02 10:58:49 [INFO] serf: EventMemberLeave: debian03 192.168.0.103
      2015/12/02 10:58:50 [INFO] agent: Received event: member-leave

      この場合、メンバーの確認すると 正常終了したサーバはleftと表示されます。

      root@debian01:~# serf members
      debian01  192.168.33.101:7946  alive 
      debian02  192.168.33.102:7946  alive 
      debian03  192.168.33.103:7946  left

       

      異常終了

      SIGTERMでプロセスを停止した場合やサーバの電源OFFなど、強制的にagentが停止された場合は他のノードがそのことを感知してイベントとして通知されます。debian03のagentをSIGTERM(9)で停止してみます。

      root@debian03:~# ps -ef | grep -i serf
      root      3607  3592  0 19:48 pts/0    00:00:00 serf agent -node=debian03 -bind=192.168.33.103 -join=192.168.0.102
      root@debian03:~# kill -9 3607
      この場合は他のメンバーがdebian03がアクセス不可になっていることを検出する形になります。
      debian01

      2015/12/02 11:19:28 [INFO] memberlist: Suspect debian03 has failed, no acks received
      2015/12/02 11:19:30 [INFO] memberlist: Suspect debian03 has failed, no acks received
      2015/12/02 11:19:31 [INFO] memberlist: Suspect debian03 has failed, no acks received
      2015/12/02 11:19:33 [INFO] memberlist: Marking debian03 as failed, suspect timeout reached
      2015/12/02 11:19:33 [INFO] serf: EventMemberFailed: debian03 192.168.0.103
      2015/12/02 11:19:34 [INFO] agent: Received event: member-failed
      2015/12/02 11:19:42 [INFO] serf: attempting reconnect to debian03 192.168.0.103:7946
      2015/12/02 11:21:12 [INFO] serf: attempting reconnect to debian03 192.168.0.103:7946
      ...
      ...

      debian02
      2015/12/02 11:12:24 [INFO] memberlist: Suspect debian03 has failed, no acks received
      2015/12/02 11:12:27 [INFO] memberlist: Suspect debian03 has failed, no acks received
      2015/12/02 11:12:28 [INFO] memberlist: Suspect debian03 has failed, no acks received
      2015/12/02 11:12:29 [INFO] serf: EventMemberFailed: debian03 192.168.0.103
      2015/12/02 11:12:30 [INFO] agent: Received event: member-failed
      2015/12/02 11:14:05 [INFO] serf: attempting reconnect to debian03 192.168.0.103:7946
      .....


      debian01,debian02にはmember-failedのイベントが通知されているのが分かります。またイベントを受け取ったあとも一定間隔でdebian03へのアクセスを試み続けます。

      この場合にクラスタのメンバをチェックするとfailedと表示されます。

      root@debian01:~# serf members
      debian02  192.168.0.102:7946  alive  
      debian03  192.168.0.103:7946  failed 
      debian01  192.168.0.101:7946  alive


      まとめ

      serfの起動と停止をためしてみました。今回はサーバの死活だけでしたがserfを利用するとサーバの状態を把握したり、イベントを受けて任意のスクリプトを実行したりすることができます。クラスタの管理自体も非集中型でシンプルなものになっておりそれぞれのサーバにserfのバイナリをコピーするだけで構成することが可能です。

    2015年11月17日火曜日

    コンテナ上でのipvsおよびiptablesの利用

    従来の仮想マシンと比較して軽量な仮想環境としてコンテナが注目されている。コンテナによる仮想環境での特徴としてコンテナで同じカーネルを共有している点があげられる。

    また、コンテナで実際のサービスを提供する場合、アプリケーションがほかにカーネルの提供する機能も必要となる。そこで今回はコンテナ環境下でのカーネルの機能の利用について実際に試してみた。

    コンテナ上でのカーネルの機能の利用

    • コンテナではapacheやmysqlといったプロセスはそれぞれの名前空間で実行されている
    • カーネルはすべてのコンテナでホストのカーネルを利用している。
    • ipvsやiptablesはカーネル側の機能
    コンテナではホストのカーネルを共有しそれぞれのコンテナごとに独立した名前空間を作成して、その上でユーザプロセスを実行することによって仮想環境を実現している。
    しかし、実際のサービスなどにおいてはhttpサーバやデータベースなどのユーザプロセスだけではなくカーネルの機能も合わせて利用される。例えば、ロードバランスやパケットのフィルタリングを行う場合などはipvsやiptablesといったカーネルの機能が必要になる。
    コンテナ上でカーネルの機能を利用する場合、そのカーネルについてはすべてのコンテナで共有されている点において通常とは事情が異なる。
    今回はipvsおよびiptablesについて実際にコンテナ上での利用を試してみた。

    システム構成

    コンテナ構成図
    検証としてWebサーバへのアクセスをLVSを利用してロードバランスするシステムをコンテナを利用して構成することを考える(上図)
    ホストマシン2台からなる構成で、それぞれのホストにipvsを利用してWebコンテナへのロードバランスを実行するLVSコンテナ、 iptablesとapacheを使ってLVSからロードバランスされてきたアクセスを受けるWebコンテナを作成する。
    以下の説明ではそれぞれのホスト及びコンテナの構成方法についての詳細は割愛して、それぞれのコンテナ上でのipvsおよびiptablesの動作および設定についてのみ述べる

    LVSコンテナ

    LVSコンテナは2つのネットワークインターフェースeth0、eth1を持ちそれぞれが仮想ブリッジを介して仮想イーサネット(veth)によってホストマシン(物理マシン)のインターフェースに接続されている。eth0側が外部ネットワーク、eth1側がWebコンテナ側のネットワークになっている。

    ipvsの設定

    ipvsの設定はコンテナ上にipvsadmによって可能である。ただし、ipvsadmを利用してコンテナ上でipvsの設定を実行する前にホスト側でip_vsモジュールをmodprobeにより読み込んでおく必要がある。

    lvshost# modprobe ip_vs

    またコンテナ上でipvsadmで設定を行うためにはコンテナがroot権限で実行されている必要がある。いわゆる一般ユーザ権限による非特権コンテナではipvsの設定はできないようである。
    実際にipvs設定を行うと次のようになる。今回はロードバランスするアドレスは10.10.0.100としてeth0のエイリアスとして設定してある。またLVSのパケットの転送方式はダイレクトルーティング(-gオプション)を選択している。

    lvs1 # ipvsadm -A -t 10.10.0.100:80 -s lc
    lvs1 # ipvsadm -a -t 10.10.0.100:80 -r 192.168.0.50 -g
    lvs1 # ipvsadm -a -t 10.10.0.100:80 -r 192.168.0.51 -g
    lvs1 # ipvsadm -Ln
    IP Virtual Server version 1.2.1 (size=4096)
    Prot LocalAddress:Port Scheduler Flags
      -> RemoteAddress:Port           Forward Weight ActiveConn InActConn
    TCP  10.10.0.100:80 lc
      -> 192.168.10.50:80             Route   1      0          0        
      -> 192.168.10.51:80             Route   1      0          0

    lvs1 # ip addr add 10.10.0.100 label eth0:100 dev eth0
    lvs1 # echo 1 > /proc/sys/net/ipv4/ip_forward

     このようにipvsの設定方法は普通のLinux Boxの場合とほとんど変わらない。

    Webコンテナ 

    Webコンテナのネットワークインターフェースは仮想ブリッジを介して仮想イーサネット(veth)によりホストマシ ンのインターフェースに接続されている。ホストマシンのネットワークインターフェースは先ほどのLVSホストのeth1側のネットワークに接続するように 構成されている。
    Webコンテナはアドレスが異なる(192.168.0.50と192.168.0.51)2つのものを作成して、それそれにLVSコンテナからロードバランスされたパケットが転送されてくるようにする。
     またここではWebコンテナは検証のためいわゆる非特権コンテナで実行されている。つまりWebコンテナ上のrootはホスト上からみた場合一般ユーザになっている。

    Webコンテナの設定

    コンテナ上でiptablesコマンドによりiptablesの設定は可能である。ただし、ipvsの場合と同様に設定を実行する前にホスト側でip_tablesモジュールをmodprobeにより読み込んでおく必要がある。

    webhost# modprobe ip_tables

    LVSでダイレクトルーティング方式での転送を選択しているので、ロードバランスされてWebコンテナに振り分けられてくるパケットの宛先はサービスアドレス(10.10.0.100)のまになっている。この宛先のパケットをWebコンテナで受け取るためにiptablesのREDIRECTターゲットを利用する。

    root@web1# iptables -t nat -A PREROUTING -p tcp --dport 80 -d 10.10.0.100 -j REDIRECT

    ipvsの場合と異なり、iptablesの設定はいわゆる非特権コンテナ上でも可能なようである。テスト時にWebコンテナの区別がつくようにindex.htmlにコンテナ名を記述しておく。

    root@web1# echo "HELLO,This is web1" > /var/www/html/index.htm

    同様にもう一つのWebコンテナ(web2)をipアドレスを変えて(192.168.0.51)作成する。本来であれば同じホストにコンテナ複数作成してロードバランスしたとしても負荷分散や冗長化という観点からはあまり意味がないが検証用にそのように構成した。

    2つのWebコンテナを構成後、LVSコンテナのeth0側からサービスアドレスにアクセスするとロードバランスされていることが確認された。

    $ curl http://10.10.0.100
    HELLO,This is web1
    $ curl http://10.10.0.100
    HELLO,This is web2

    コンテナ上のiptables/ipvsの設定について

    作成した2つのWebコンテナでiptablesの設定を表示すると確認できるが、それぞれのコンテナで設定が独立していることがわかる。ipvsの設定も同様にコンテナごとに独立したものになる。

    コンテナ上のiptablesのLOGターゲットについて

    コンテナ上の場合、iptablesのLOGターゲットでのログの取得はできないようである。
    これは一般的なカーネル空間のログの問題のようで、今のところカーネル空間のログをそれぞれのコンテナに関連するログごとに分けて記録するような仕組みがない。つまりコンテナからカーネル空間のログを記録する動作をした場合、すべてのコンテナおよびホストで共通になっている場所に記録される(あまり自信がありませんが)。その関係上、コンテナ上ではiptablesを利用してLOGターゲットでカーネル空間にログを出力することは、今のところ意図的にできないようになっているようである。
    コンテナ上でiptablesのログを記録するには、ユーザ空間にログを出力するULOGやNFLOGターゲットを利用する必要がある。

    その他

    検証はしていないが、コンテナ上にインストールして実行するipvsadmやiptablesのコマンドはホストのカーネルバージョンとの互換性がある必要があるとおもわれる。

    まとめ

    • iptableやipvsはコンテナでも同様に利用できる。
      • ただしホスト側での事前のモジュールの読み込みが必要である。
      • またipvsはroot権限でコンテナを実行していないと設定できない。
    • iptablesでログを取得したい場合はULOGかNFLOGを使うこと。 
    これらの点に注意すれば、普通のLinux Boxと同様な方法で、コンテナを利用したロードバランサやファイアフォールをipvsやiptablesを使って構築することが可能である。ただしコンテナの場合、オーバーヘッドがなどの観点から、スループットなどについて別途検証が必要あると思われる。

    参考文献
    • コンテナ上でiptablesのログターゲットが利用できない背景(カーネル空間のログの問題)はここを参考にさせていただきました。
    • 非特権コンテナについてはこちらを参考にさせていただきました(日本語約ページ)



    2015年11月13日金曜日

    最近話題のLinuxコンテナを試してみました。

    Linuxコンテナ

    従来の仮想マシンと比較して軽量な仮想環境としてコンテナが注目されています。仮想マシンのようにまるごと物理マシンをエミュレーションした環境を用意するのでなく、ネットワークやプロセスIDなどのみが独立した環境(コンテナ)を用意してその中でプロセスを実行するタイプのOSレベル仮想環境です。今回はそのコンテナについてもっともベースとなる部分を試してみました。

    LXCのインストール

    最近はコンテナの利用する環境を整えるのにも各ディストリビューションに対応したパッケージをインストールするだけで大丈夫です。 コンテナを利用するための実装にはいくつのかの種類がありますが今回はLXCを利用します。他にはDockerなどが有名です。ただLinuxコンテナの核となる部分はカーネル側の機能なので、実装が違っていてもベースとなる考え方は一緒です。 
     今回はDebian/Jessieを利用しますが、LXCはほとんどのディストリビューションでパッケージ化されていると思います。またカーネルが必要な機能を有効にしてコンパイルされていないとダメなのですが、ディストリビューションの標準カーネルであればまず問題ないはずです。
     DebianのJessieではapt-getでインストールするだけです。
    # apt-get install lxc

    コンテナの作成 


     ではコンテナを作りましょう。一連の作業はrootで実行する必要があります。コンテナの作成においては、コンテナ用のファイルシステムを作成することがメインです。あとはコンテナを実行するためのLXCの設定ファイルも必要です。

    コンテナ用のファイルシステム

    コンテナ内のプロセスからはこのファイルシステムがルートファイルシステム(/)として見え、基本的にここにしかアクセスできません。コンテナ内のプロセスはこのルートファイルシステム上で実行されます。

     コンテナを作成するには先ほどインストールしたLXCのユーティリティに含まれるlxc-createコマンドを利用するのが簡単です。

    lxc-create -n <コンテナ名> -t <テンプレート名> -- <テンプレートオプション>
    例:test1という名前で64bit Debian/Jessieのルートファイルシステムを作成する場合 


    # lxc-create -n test1 -t debian -- --arch amd64 --release=jessie

     lxc-create コマンドは-tオプションで指定したテンプレートに従ってルートファイルシステムを作成します。テンプレートは/usr/share/lxc/templates/lxc-<テンプレート名>という名前で実体が用意されています。必ずしもホストのLinuxと同じディストリビューションのファイルシステムでなくてはいけないということはありませんがアーキテクチャは同じでないといけません。ホストが64bitであるならばルートファイルシステムも64bit用のものを用意します。
     debianテンプレートの場合debootstrapコマンドを利用してネットワーク越しにrootfsを取得してきます

    # lxc-create -n test1 -t debian -- --arch amd64 --release=jessie

     LXCの標準的な構成であればコンテナの保存場所は/var/lib/lxcになります。その場所の<コンテナ名>ディレクトリ以下にコンテナの一連のファイルが作成されます。

    # cd /var/lib/lxc
    # tree -L 1 test1
    test1
    |-- config
    `-- rootfs
    rootfs以下が作成されたルートファイルシステムです。configがLXCの設定ファイルになります。rootfs以下にはdebootstrapで作成された(最小インストールの)Debianのルートファイルシステムが作成されています。

    # ls test1/rootfs/
    bin   dev  home  lib64    mnt  proc  run     selinux  sys  usr
    boot  etc  lib     media    opt  root  sbin  srv      tmp  var

     作成されたコンテナの一覧はlxc-lsコマンドで確認できます。

    # lxc-ls -f
    NAME   STATE    IPV4  IPV6  AUTOSTART 
    -------------------------------------
    test1  STOPPED  -     -     NO        

    まだ、コンテナを作成しただけで実行してはいないのでSTOPPEDになっています。

    コンテナの実行

    早速コンテナを実行してみましょう。コンテナを実行するとはコンテナ内でなんからのプロセスを実行することです。実行するものはなんでも良いのですが、コンテナ内ではコンテナのルートファイルシステムにしかアクセスできませんので、その上にプロセス本体のファイルが存在していることが必要です。本体の実行にライブラリが必要なのであればそれも同様にルートファイルシステム上に存在している必要ががあります。

     デフォルトで作成される設定ファイルは内容がまだスカスカで実用には十分ではありませんがとりあえずコンテナ内でプロセスを実行することはできるはずです。

     ここではコンテナ内でシェル(bash)を実行してみます。コンテナ内でのプログラムの実行するにはlxc-startコマンドを利用します。

    # lxc-start -n test1 -- /bin/bash
    bash: cannot set terminal process group (-1): Inappropriate ioctl for device
    bash: no job control in this shell

     警告が出てしまいますが、シェルをコンテナ内で実行できました。このシェル上で色々確認してみるとこのシェルのプロセスがコンテナ内に閉じ込められていることがわかります。
     ファイルシステムは/var/lib/lxc/test1/rootfs以下の部分にしかアクセスすることができません。そこがコンテナ内ではルートファイルシステム(/)として見えていることが分かります。
    root@test1:/# pwd
    /
    root@test1:/# ls
    bin   dev  home  lib64  mnt  proc  run   selinux  sys  usr
    boot  etc  lib   media  opt  root  sbin  srv      tmp  var
    root@test1:/# cat /etc/hostname
    test1

     psでプロセスを確認してみると自身のシェル(とpsコマンド)しか見えないのがわかります。他に大量に動作しているであろうホスト上のプロセスは確認できません。しかもシェルのPIDがなんと1番になっているのがわかります。

    root@test1:/# ps -ef
    UID        PID  PPID  C STIME TTY          TIME CMD
    root         1     0  0 05:12 ?        00:00:00 /bin/bash
    root        11     1  0 05:40 ?        00:00:00 ps -ef

     ipコマンドでネットワークを確認してみるとネットワーク(eth0)がないことがわかります。ディストリビューションによってはLXCインストール時にコンテナ用のネットワークが用意され有効になっているかもしれません。いずれにしてもホスト上のものとは別のネットワークが見えるはずです。

    root@test1:/# ip addr
    1: lo: <LOOPBACK> mtu 65536 qdisc noop state DOWN group default
        link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00

     シェルから抜けて終了させてみます。するとコンテナも終了します。lxc-lsコマンドで確認してみてもstoppedになっていると思います。コンテナでは基本的にコンテナ内でPID1番に見えるプロセスが終了するとコンテナ自身も終了します。

     再びコンテナ内でbashを実行して、ホスト上の別端末からlxc-lsコマンドで確認してみます。今度はステータスがRUNNINGになっていると思います。
    # lxc-start -n test1 /bin/bash
    bash: cannot set terminal process group (-1): Inappropriate ioctl for device
    bash: no job control in this shell
    root@test1:/#

    別端末から
    # lxc-ls -f
    NAME   STATE    IPV4  IPV6  AUTOSTART 
    -------------------------------------
    test1  RUNNING  -     -     NO


     コンテナの外からコンテナ内で実行しているプロセスがどのようにみえているか確認してみます。bashだとどれがコンテナ内のbashなのか確認しにくいのでコンテナ内のbashから適当なプロセスをさらに実行して目印にしておきます。

    root@test1:/# tail -f /dev/null

     ホスト上でpsコマンド実行するとコンテナ内のプロセスは普通に確認できることがわかります。プロセスIDも他のプロセスと同様のものがちゃんと振られています。コンテナ実行時のlxc-startが親プロセスとしてコンテナ内のbashを実行し、それがコンテナ内ではPID1番(外側では12146番)として扱われています。

    # ps -ef
    UID        PID  PPID  C STIME TTY          TIME CMD
    ...
    root     12142 12081  0 05:47 pts/1    00:00:00 lxc-start -n test1 /bin/bash
    root     12146 12142  0 05:47 pts/1    00:00:00 /bin/bash
    root     12156 12146  0 05:49 pts/1    00:00:00 tail -f /dev/null

    まとめ

    Linuxコンテナとは基本的にはこのようにプロセスを他のプロセスやファイルシステム、ネットワークなどから隔離して実行する技術です。隔離する事によりプロセスの予期せぬ動作からシステムや他のプロセスを保護することができます。