iPXE を導入した記念に blog を書いてみたけど、タイトルが悩ましいので、この記事のタイトル募集中!
(自分の書いたタイトルはダメ出しされたので、募集することにしてみました(^^;;記事を読んでいただいて、もし、よいタイトルを思いついたら、ぜひ、コメントにでもお願いしますm(_ _)m。次回のタイトルに使わせていただくかも(^^)
- PXEとは、ネットワークブートのための仕組みの1つ。NIC上のフラッシュROM に書き込まれている。ネットワークブートに必要なファイルの取得には、DHCPとTFTP を用いる
- iPXE(gPXE)とは、PXEを拡張したオープンソースなネットワークブートファームウェア/ローダ
iPXE(gPXE)には、下記のような特徴があります。
- MACアドレスの他にもサーバのDMI情報を取得できる
- コマンドが用意されていてそのコマンドで組んだスクリプトを利用可能
- httpでのリクエストをサポートしている
つまり・・・
- DMI情報を取得できるということは、そのサーバがどんな機種なのか分かる
- スクリプトから取得した機種情報を使ったリクエストをすることができそう
- http+cgiで、リクエストに応じて動的にレスポンスを返すことができそう
どうでしょう。試してみたくなりませんか?
ではでは、これから、実際にiPXEを触っていくとしましょう。
iPXE(gPXE)の紹介
gPXEのほうがよく知られているかもしれませんが、gPXEの開発が止まり、その後釜として始まったプロジェクトがiPXEとなります。
- iPXE: http://ipxe.org/
- gPXE: http://etherboot.org/wiki/start
本来は、PXEと同じくNICのROMに焼いて使用するようですが、そうすると、元からあるPXEは当然消えてしまいますし、数十台、数百台のサーバを運用している場合に、すべてのNICに適用するとしたら、気が遠くなりそうです。しかしながら、よくみてみると、PXEからiPXEをチェインロードできるとあります。この方法を使えば、NICのROMに手を加えることなく、iPXEを利用することができそうです。
iPXEを実際に起動してみて、触ってみよう
PXEからチェインロードする方法でiPXEを試しに起動させてみます。
ここでは、isc-dhcpd,tftpd,thttpd(cgiは、bashスクリプト)を使用し、設定は、以下のようになっているとします。
(ここでは、iPXE以外の細かい設定に関しては、割愛します)
・tftpd,thttpdサーバのIPアドレス
192.168.0.1
・tftpd,thttpdルートディレクトリ
/tftp/
・thttpdのcgiディレクトリ
/tftp/cgi-bin/
・iPXE関連ファイルの格納ディレクトリ
/tftp/iPXE/
まずは、PXEチェインロード用のバイナリであるundionly.kpxeを以下のページ内のリンクからDLし、/tftp/iPXE/undionly.kpxeに保存します。
http://ipxe.org/howto/chainloading
上記ページのリンク先に紹介されているように、DHCPの設定ファイルに以下のように記述を追加します。
if exists user-class and option user-class = "iPXE" { filename "http://192.168.0.1/iPXE/boot.ipxe"; } else { filename "iPXE/undionly.kpxe"; } next-server 192.168.0.1;
filenameの値を、iPXEからのリクエストにはiPXEの起動用スクリプト(boot.ipxe)を返し、iPXE以外のリクエストにはiPXEをロードするためのundionly.kpxeを返すようにしています。
これにより、以下のような流れとなります。
PXE起動
↓
iPXE(undionly.kpxe)を取得してロード
↓
iPXE起動
↓
起動用スクリプト(boot.ipxe)を取得してロード
↓
boot.ipxeの内容を実行
/tftp/iPXE/boot.ipxeは、以下のように記述しておきます。
#!ipxe imgfree chain http://${next-server}/cgi-bin/boot_ipxe.cgi?type=${product:uristring}&mac=${mac}
boot.ipxeの中身の説明はとりあえず一旦おいといて、実際にマシンをPXEブートしてみると、以下のようになります。
Intel(R) Boot Agent GE v1.2.40 Copyright (C) 1997-2006, Intel Corporation CLIENT MAC ADDR: XX XX XX XX XX XX GUID: xxxxxxxxxxxxxxxxxxxxxxxxxxx CLIENT IP: 192.168.0.xx MASK: 255.255.255.0 DHCP IP: 192.168.0.1 GATEWAY IP: 192.168.0.xx PXE->EB: !PXE at 97CA:0070, entry point at 97CA:0106 UNDI code segment 97CA:3F20, data segment 919C:62E0 (582-623kB) UNDI device is PCI 07:00.0, type DIX+802.3 582kB free base memory after PXE unload iPXE initialising devices...ok iPXE 1.0.0+ -- Open Source Network Boot Firmware -- http://ipxe.org Features: HTTP iSCSI DNS TFTP AoE bzImage ELF MBOOT PXE PXEXT Menu Press Ctrl-B for the iPXE command line...
iPXEがチェインロード起動されると、自動的にboot.ipxeを取得して実行となるのですが、インタラクティブモードに入ると、自動実行は行わず、手動でコマンド入力をすることが出きるようになります。"Press Ctrl-B for the iPXE command line..."の表示がされたら、すかさず、Ctrl+Bを入力してみましょう。すると、下記のプロンプトが表示され、コマンドの入力ができるようになります。では、試しに、いくつかコマンドを入力してみましょう。
iPXE> # マックアドレスを表示 iPXE> show mac net0/mac:hex = xx:xx:xx:xx:xx:xx # DHCPにてIPアドレスを取得 iPXE> dhcp DHCP (net0 xx:xx:xx:xx:xx:xx)... ok # IPアドレスを表示 iPXE> show ip net0.dhcp/ip:ipv4 = 192.168.0.xx # DHCPで設定されたfilenameを表示 iPXE> show filename net0.dhcp/filename:string = http://192.168.0.1/iPXE/boot.ipxe # DHCPで設定されたnext-serverを表示 iPXE> show next-server net0.dhcp/next-server:ipv4 = 192.168.0.1 # サーバの機種情報を表示 iPXE> show product smbios/product:string = Express5800/i120Ra-e1 [N8100-1482Y] # urlエンコードして表示 iPXE> show product:uristring smbios/product:uristring = Express5800%2Fi120Ra-e1%20%5BN8100-1482Y%5D
サーバの機種情報も無事取得できているようです。次は、boot.ipxeをhttp経由で取得できるかどうか試してみます。
iPXE> imgfetch ${filename} http://192.168.0.1/iPXE/boot.ipxe.... ok iPXE> imgstat boot.ipxe : 102 bytes
無事、取得できているようですので、boot.ipxeの内容を手動で試してみましょう。ここでは、まだ、cgiを準備していないので、エラーとなりますが、どのようにアクセスされるかの確認ができます。
iPXE> imgfetch http://${next-server}/cgi-bin/boot_ipxe.cgi?type=${product:uristring}&mac=${mac} http://192.168.0.1/cgi-bin/boo_ipxe.cgi?type=Express5800%2Fi120Ra-e1%20%5BN8100-1482Y%5D&mac=xx%3Axx%3Axx%3Axx%3Axx%3Axx... No such file or directory (http://ipxe.org/2d0c613b)
機種情報とMACアドレスが代入されてhttpリクエストをしていることが確認できました。
もうお分かりのようにboot.ipxeは、機種情報とMACアドレスを取得し、それをboot_ipxe.cgiにクエリ文字列として付与して叩き、そのレスポンスの内容を実行するスクリプトということになります。(${product}でも、自動的にurlエンコードされるようですが、念のため、uristringでの出力指定をしています。)
では、サーバ起動用の簡単なiPXEスクリプトを、機種情報やMACアドレスを元にboot_ipxe.cgiで動的に生成して、実際にサーバを起動させてみましょう。
Linuxを起動してみる
MACアドレスと機種情報にしたがって、initrdとkernelを決定して起動するだけの簡単なboot_ipxe.cgiを用意してみます。
ちなみに、iPXEでは確認していませんが、gPXEでは、Content-Lengthを指定しないとうまく動作しなかったため、指定するようにしています。
#!/bin/bash # クエリ文字列は、$QUERY_STRINGに格納されている # 変数type,macをクエリ文字列から生成する for q in $(echo ${QUERY_STRING} | tr "&" " "); do eval $q done case $type in *Express*) initrd_file=initrd.gz ;; esac case $mac in *xx%3Axx%3Axx%3Axx%3Axx%3Axx*) kernel_file=vmlinuz ;; esac body=$(#!ipxe initrd http://\${next-server}/${initrd_file} kernel http://\${next-server}/${kernel_file} boot ) echo "Content-type: text/plain" echo "Connection: close" echo "Content-Length: $(echo -e "${body}" | wc -c)" echo "" echo -e "${body}"
wgetなどで、先ほどのiPXEが出力したパスを叩いて確認してみると、以下のような出力となります。
$ wget -q -O - "http://192.168.0.1/cgi-bin/boo_ipxe.cgi?type=Express5800%2Fi120Ra-e1%20%5BN8100-1482Y%5D&mac=xx%3Axx%3Axx%3Axx%3Axx%3Axx" #!ipxe initrd http://${next-server}/initrd.gz kernel http://${next-server}/vmlinuz boot
では、/tftp/以下に適当なvmlinuzとinitrd.gzを準備して、マシンを再起動させてみます。
Intel(R) Boot Agent GE v1.2.40 Copyright (C) 1997-2006, Intel Corporation CLIENT MAC ADDR: XX XX XX XX XX XX GUID: xxxxxxxxxxxxxxxxxxxxxxxxxxx CLIENT IP: 192.168.0.xx MASK: 255.255.255.0 DHCP IP: 192.168.0.1 GATEWAY IP: 192.168.0.xx PXE->EB: !PXE at 97CA:0070, entry point at 97CA:0106 UNDI code segment 97CA:3F20, data segment 919C:62E0 (582-623kB) UNDI device is PCI 07:00.0, type DIX+802.3 582kB free base memory after PXE unload iPXE initialising devices...ok iPXE 1.0.0+ -- Open Source Network Boot Firmware -- http://ipxe.org Features: HTTP iSCSI DNS TFTP AoE bzImage ELF MBOOT PXE PXEXT Menu net0: xx:xx:xx:xx:xx:xx using undionly on UNDI-PCI07:00.0 (open) DHCP (net0 xx:xx:xx:xx:xx:xx)... ok net0: 192.168.0.xx/255.255.255.0 gw 192.168.0.xx Next server: 192.168.0.1 Filename: http://192.168.0.1/iPXE/boot.ipxe http://192.168.0.1/iPXE/boot.ipxe... ok http://192.168.0.1/cgi-bin/boot_ipxe.cgi?type=type=Express5800%2Fi120Ra-e1%20%5BN8100-1482Y%5D&mac=xx%3Axx%3Axx%3Axx%3Axx%3Axx...ok http://192.168.0.1/initrd.gz... ok http://192.168.0.1/vmlinuz... ok [ 0.000000] Initializing cgroup subsys cpuset [ 0.000000] Initializing cgroup subsys cpu [ 0.000000] Linux version 3.0.21 ..... .... .... ....
カーネルがロードされ、無事起動できたようです。
実際の運用で使ってみるとすると・・・
DSASでは、ほとんどのサーバがPXEブート+PXELINUXを利用してディスクレスサーバとして起動されるようになっています。
また、リモートからのサーバ管理にIPMIを利用しており、SOL(Serial over Lan)対応シリアルポートを、PXELINUXの起動設定ファイルにて記述することにより、IPMIのSOL経由にてPXELINUXの起動メニューの表示/編集やLinuxの起動メッセージの表示ができるようにしています。
iPXEは、独自メニューを作成可能なのですが、残念ながら、PXELINUXやGRUBのように、起動時にインタラクティブに編集することは出来ないようです。
ですが、PXELINUXのpxelinux.0やSYSLINUXのcom32をロードして実行することができます(com32に関しては、SYSLINUXのver4.xxのcom32ファイルの直接実行はできず、ver3.86以下のものを使用する必要があります)。
そこで、pxelinux.0やmenu.c32(com32ファイルで用意されているメニュー用ファイル)を利用し、そのメニュー設定をiPXEで取得できる情報から動的に生成すれば、サーバ機種によって適切な起動カーネルパラメータを指定することができそうです。また、起動時にインタラクティブにパラメータを編集するといったこともいけそうです。
さて、今回は、ここまでとして、次回ではmenu.c32のメニュー機能をiPXEから利用したり、IPMI SOL経由で表示したりする例を紹介できたらと思っています。