2012年07月09日

iPXE導入でサーバ機種にあわせたネットブートを

はてなブックマークに登録

さて、 前回は、iPXEを利用してサーバの機種情報等から動的にパラメータを生成してLinuxを起動する方法を簡単に紹介しました。
今回は、syslinuxのmenu.c32を利用した起動メニューの利用と機種情報によって動的にメニュー設定を変更する方法を紹介していきたいと思います。
(タイトルはそれらしいのにかえてみました(^^;;)

起動メニューを利用するには

DSASでは、PXELINUX+menu.c32を利用して起動時に使用するカーネルやイメージを選択できるようにしており、OSの起動中や起動後に使用する変数などをカーネルパラメータに記述したりしています。
状況によっては、起動時にパラメータを追加したり変更して起動したいケースがあるのですが、前回も書いたように、iPXEに用意されているメニューコマンドを使って作成したメニューでは、起動時にメニューを手動で変更することは現時点では難しいようです。
ですが、menu.c32ファイルやpxelinux.0をiPXEでロードして利用することができます。このことを利用すれば、既存のPXELINUXのメニュー設定の内容をほぼそのまま流用することもできそうですね。
menu.c32を直接ロードする方法とpxelinux.0をロードしてからmenu.c32を利用する2つの方法があるのですが、ここでは、menu.c32を直接ロードする方法を紹介します。

menu.c32を直接ロードする方法ですが、使用するmenu.c32のバージョンは3.86以下という制限があります。(こちらから取得できます。ここでは、syslinux-3.86に同梱されているファイルを使用しています。)
また、デフォルトのundionly.kpxeではCOMBOOTが無効なので、有効にする必要があります。さらに、カーネルパラメータの引き渡しをしてくれないので、修正をする必要があります。具体的には以下のようにしてから、ビルドします。(ソースの取得方法やビルドに関する詳細はiPXEのサイトをご覧ください。)

・COMBOOTを有効にする

# src/config/local/general.h に以下の行を追加 

#define        IMAGE_COMBOOT           /* SYSLINUX COMBOOT image support */

・カーネルパラメータの引き渡し

# src/arch/i386/interface/syslinux/comboot_call.c に以下を追加

$ diff --git a/src/arch/i386/interface/syslinux/comboot_call.c b/src/arch/i386/interface/syslinux/comb
index 7ee5f61..5effa72 100644
--- a/src/arch/i386/interface/syslinux/comboot_call.c
+++ b/src/arch/i386/interface/syslinux/comboot_call.c
@@ -206,6 +206,12 @@ static int comboot_fetch_kernel ( char *kernel_file, char *cmdline ) {
                return rc;
        }
 
+        if ( ( rc = image_set_cmdline ( kernel, cmdline ) ) != 0 ) {
+                DBG ( "COMBOOT: could not set kernel command line: %s\n",
+                      strerror ( rc ) );
+                return rc;
+        }
+
        /* Replace comboot image with kernel */
        if ( ( rc = image_replace ( kernel ) ) != 0 ) {
                DBG ( "COMBOOT: could not replace with kernel: %s\n",

MACアドレスや機種情報に応じてメニューを生成

undionly.kpxeを用意したら、前回配置したものと入れ替えればOKです。
ここでは、他にもいくつかのファイルを用意するのですが、それらの目的とファイルの配置は、以下のようになります。
・特定のMACアドレスをもつサーバの場合には、指定した起動メニューを引き渡し、それ以外のサーバにはデフォルトの起動メニューを引き渡す
・機種毎に異なるIPMIのSOL対応シリアルポートにあわせて起動メニューの内容を変更する

/tftp/cgi-bin/
|-- boot_ipxe.cgi 
`-- menu.cgi 

/tftp/iPXE/
|-- undionly.kpxe
|-- menu.c32
|-- boot.ipxe
`-- menu.ipxe

/tftp/iPXE/menu/
|-- default
`-- xx-xx-xx-xx-xx-xx

スクリプトやCGIの中身は以下のようになります。

・boot.ipxe(前回と同じ)

#!ipxe
imgfree
chain http://${next-server}/cgi-bin/boot_ipxe.cgi?type=${product:uristring}&mac=${mac}

・boot_ipxe.cgi(サーバによって渡す内容を変更するCGI)

#!/bin/bash

# クエリ文字列は、$QUERY_STRINGに格納されている
# 変数type,macをクエリ文字列から生成する
for q in $(echo ${QUERY_STRING} | tr "&" " "); do
  eval $q
done

# "%3A(:)"のままだと扱いにくいので"-"に変更
mac=$(echo ${mac} | sed -e 's/%3A/-/g')

# 機種情報によって、シリアルポートの情報を変更
case $type in
  *Express*)
    port=1
    rate=115200
    ;;
  *)
    # デフォルト
    port=2
    rate=19200
    ;;
esac

echo "Content-type: text/plain"
echo "Connection: close"
echo "Content-Length: $(. /tftp/iPXE/menu.ipxe | wc -c)"
echo ""
. /tftp/iPXE/menu.ipxe

・menu.ipxe(menu.c32をチェーンロードし、機種情報によって設定されたパラメータに応じたメニューを取得するipxeスクリプト)

cat << EOF
#!ipxe
imgfree
chain /iPXE/menu.c32 /cgi-bin/menu.cgi?port=${port}&rate=${rate}&mac=${mac}
EOF

・menu.cgi(渡されたパラメータを元にメニューを生成するCGI)

#!/bin/bash

for q in $(echo ${QUERY_STRING} | tr "&" " "); do
  eval $q
done

if [ -h "/tftp/iPXE/menu/${mac}" ]; then
  # MACアドレスのファイルがある場合
  file=$mac
else
  # デフォルト
  file=default
fi

echo "Content-type: text/plain"
echo "Connection: close"
echo "Content-Length: $(. /tftp/iPXE/menu/${file} | wc -c)"
echo ""

. /tftp/iPXE/menu/${file}

・default(デフォルトメニュー)

serial ${port} ${rate}
timeout 100
prompt  0
menu title Default Boot Menu
default web
label web
  kernel root/web/vmlinuz
  append BOOT_IMAGE=root/web/vmlinuz initrd=pxeinit.gz dsas=web panic=10 console=tty0 console=ttyS${port},${rate}n8 

label db
  kernel root/db/vmlinuz
  append BOOT_IMAGE=root/db/vmlinuz initrd=pxeinit.gz dsas=db panic=10 console=tty0 console=ttyS${port},${rate}n8 ID= 

・xx-xx-xx-xx-xx-xx(MACアドレスがxx-xx-xx-xx-xx-xxのサーバ用メニュー)

serial ${port} ${rate}
timeout 100
prompt  0
menu title Assigned Boot Menu
default db
label db
  kernel root/db/vmlinuz
  append BOOT_IMAGE=root/db/vmlinuz initrd=pxeinit.gz dsas=db panic=10 console=tty0 console=ttyS${port},${rate}n8 ID=101

httpを叩いて、確認してみる

上記によって、MACアドレスがxx-xx-xx-xx-xx-xxのサーバには専用のメニューを表示し、それ以外のサーバにはデフォルトのメニューが表示されます。またメニューの内容は、機種情報にしたがったシリアルポート設定となります。
では、実際の起動の流れを擬似的にhttpアクセスして追ってみましょう。

# iPXEが起動して実行するブート用のiPXEスクリプトを取得
$ wget -q -O -  "http://192.168.0.1/iPXE/boot.ipxe"
#!ipxe
imgfree
chain http://${next-server}/cgi-bin/boot_ipxe.cgi?type=${product:uristring}&mac=${mac}
#上記のスクリプト実行時に変数代入された状態でcgiを叩く
# MACアドレスがxx-xx-xx-xx-xx-xxで、機種情報がExpressの場合
$ wget -q -O -  "http://192.168.0.1/cgi-bin/boo_ipxe.cgi?type=Express&mac=xx%3Axx%3Axx%3Axx%3Axx%3Axx"
#!ipxe
imgfree
chain /iPXE/menu.c32 /cgi-bin/menu.cgi?port=1&rate=115200&mac=xx-xx-xx-xx-xx-xx

# MACアドレスがxx-xx-xx-xx-xx-xx以外で、機種情報がx3550の場合
$ wget -q -O -  "http://192.168.0.1/cgi-bin/boo_ipxe.cgi?type=x3550&mac=yy%3Ayy%3Ayy%3Ayy%3Ayy%3Ayy"
#!ipxe
imgfree
chain /iPXE/menu.c32 /cgi-bin/menu.cgi?port=2&rate=19200&mac=yy-yy-yy-yy-yy-yy
# menu.cgiを叩いて、メニューの内容を確認
# MACアドレスがxx-xx-xx-xx-xx-xxで、機種情報がExpressの場合
$ wget -q -O -  "http://192.168.0.1/cgi-bin/menu.cgi?port=1&rate=115200&mac=xx-xx-xx-xx-xx-xx"
serial 1 115200
timeout 100
prompt  0
menu title Assigned Boot Menu
default db
label db
  kernel root/db/vmlinuz
  append BOOT_IMAGE=root/db/vmlinuz initrd=pxeinit.gz dsas=db panic=10 console=tty0 console=ttyS1,115200n8 ID=101

# MACアドレスがxx-xx-xx-xx-xx-xx以外で、機種情報がx3550の場合
$ wget -q -O -  "http://192.168.0.1/cgi-bin/menu.cgi?port=2&rate=19200&mac=yy-yy-yy-yy-yy-yy"
serial 2 19200
timeout 100
prompt  0
menu title Default Boot Menu
default web
label web
  kernel root/web/vmlinuz
  append BOOT_IMAGE=root/web/vmlinuz initrd=pxeinit.gz dsas=web panic=10 console=tty0 console=ttyS2,19200n8 

label db
  kernel root/db/vmlinuz
  append BOOT_IMAGE=root/db/vmlinuz initrd=pxeinit.gz dsas=db panic=10 console=tty0 console=ttyS2,19200n8 ID= 

機種情報やMACアドレスに基づいて、メニューが動的に変更されているのが確認できました。
あとは、実際に起動して確認することになりますが、wget等で簡単に確認できるのもいいですね。

まとめ

さて、前回の最後に少し書きましたが、DSASでは、IPMIのSOLをよく利用していて、IPMIのSOL対応シリアルポートの情報を起動メニューのパラメータに記述しています。
SOL対応シリアルポートは機種毎に違っていて、ボーレートが速すぎると不安定な機種もあったりします。シリアルポートの設定が機種に応じた設定ではないために、SOL経由でOSの起動メッセージが見えなかったり、文字化けしたりで、機種による違いをどうにかしたいと思っていたことが、iPXE導入のきっかけとなります。
iPXE導入により、起動するサーバの機種にあわせてメニュー設定を書き換える必要がなくなりました。また、新しい機種を導入した場合でも、基本的に一つのCGIファイルを1回編集するだけですみます。
他にも、DMIのAsset Tag情報をサーバの識別IDとして利用して、ipxeスクリプトから${asset:uristring} で取得したりすると、いろいろ便利に使えるかもしれませんね。

klab_gijutsu2 at 20:34│Comments(0)TrackBack(0)

トラックバックURL

この記事にコメントする

名前:
URL:
  情報を記憶: 評価: 顔   
 
 
 
Blog内検索
Archives
このブログについて
DSASとは、KLab が構築し運用しているコンテンツサービス用のLinuxベースのインフラです。現在5ヶ所のデータセンタにて構築し、運用していますが、我々はDSASをより使いやすく、より安全に、そしてより省力で運用できることを目指して、日々改良に勤しんでいます。
このブログでは、そんな DSAS で使っている技術の紹介や、実験してみた結果の報告、トラブルに巻き込まれた時の経験談など、広く深く、色々な話題を織りまぜて紹介していきたいと思います。
最新コメント