ディスクレスで仮想マシンコンソールを実現する

パソコンが1台壊れた。電源を入れるとWindowsのブートを途中まで実行するのだが、HDDが本格に動き始めるとマシン自身がリセットして、また最初の画面(BIOSの起動画面)からやり直す。これの繰返し。多分、電源系の部品、特にコンデンサあたりの劣化ではないだろうか。電源ユニット自身か、マザーボードのリセット回路まわりか。厄介なのはディスプレ一体型のPCなので電源ユニットも、マザーボードも特別仕様になっていてパソコンショップなどで代替部品が手に入り難いことだ。

後日談
マザーボードを調べていくとCPUソケットの直ぐ脇のコンデンサが劣化しているようだった。

同じ容量耐圧のコンデンサを買って来て付け替えてみた。が、症状は改善されなかった。ちょっと目には悪そうな部品は無かったが、1つ表面実装のチップ抵抗が剥がれている形跡を発見した。しかし、この抵抗値はメーカーに聞かなければ分からないし、メーカーが教えてくれるわけもないので、それ以上の修理は諦めた。

大した仕事をさせていたわけでもないので、新しく購入するよりも仮想マシンサーバに1つ仮想マシンとして実現した方が安上がりだ。が、仮想コンソールのPCは必要である。そこでディスクレスマシンとして延命して使うことにした。当面、古くなってジャンク箱にしまってあったノートPCを引っ張り出し、暫定的な仮想コンソール(HDD内蔵)にして、その間に壊れたPCをディスクレスで使えるようにしようとした。

ディスクレスのOSはバンドルされていたWindows 2000でもいいのだが、W2Kをディスクレスで使う方法は知らないので、取りあえずLinuxをOSにつかう方向で考える。(こういったケースではWindowsよりもLinuxベースの方が便利かと思う。仮想マシンが増えてきて、仮想コンソールを動かすPCが必要なるとLinuxの需要も増えるかも。 でも、仮想マシン側でWindowsのライセンスは必要なので、Microsoftは損はしないか。)

Linuxディスクレスの実現方法も幾つかあるようだが、以前、PXEを使うときに色々と調べていたらブートにPXEを使う方法が何処かに載っていたの、先ずはPXEから準備を進めた。

PXEサーバのインストールと設定

以前、PXEを使ったのは、CD-ROMドライバからブートできないノートPCにFedora Core6をインストールするためだった。あくまでも一時的な使用だったので、兎に角Fedoraがブートできればいい、とあまり詳しくは調べなかった。しかし、今回は定常的に使用し、しかも将来的には複数のマシンをブートすることにもなるので、ちゃんと設定しなければと、改めて調べてみた。(「PXEにハマッタ」参照)

以前やったので大体の流れは分かっていた。

  1. DHCPサーバのインストール/設定/起動
  2. PXE(syslinux)のインストール
  3. tftpサーバのインストール/設定/起動

PXEのインストール(とっていもパッケージをインストールして、PXEブート用のソフトを/tftpbootの下にコピーするだけ)とtftpの設定は問題はなさそうである。問題はDHCPの設定だ。PXEの設定で一番手間が掛かるのはDHCPのコンフィグ(/etc/dhcpd.conf)の設定だろう。

PXE用DHCPサーバの設定

単にDHCPLinux上でインストールするのはそれ程、手間のかかることではない。PXEを使えるようにするにはちょっと設定が必要になるのと、なにより今回は、通常使うDHCPPXE用のDHCPの2つのサーバを立てる必要があることだった。

持ち運びの出来るノートPCは一般的にはDHCPでアドレスを割当てる。現在はブロードバンド・ルータをDHCPサーバとしている。ブロードバンド・ルータは家庭内の冷蔵庫と同じで、一旦電源を入れるとほぼ24時間365日動作となりDHCPサーバとしてはうってつけである。しかし、ブロードバンド・ルータのDHCPサーバではきめ細かい設定ができない。例えば、ディスクレスのブート時に必要となるPXEサーバのアドレスを設定することが出来ない。(PXEサーバの指定(正確にはnext-serverの指定)さえできればブロードバンド・ルータのDHCPでもいいのだが。) 仕方ないので、PXEサーバとなるマシンにDHCPサーバをやらせるのが一般的だが、こちらのPCは色々とテストにつかったり、HDDのバックアップのために数時間止めることも考えられる。その間、DHCPクライアントが使えなくなってしまう場合もある。
そこで、通常使うDHCPサーバの他に、PXE用にもう1台DHCPサーバを立てる必要が出てきた。

同一LAN上で複数のDHCPを併用する

PXEの利用記事をみると、どれも「今使っているDHCPサーバはOFFにしてPXE用にDHCPサーバを設定する」と書いてある。私も以前はその通りにした。CD-ROMドライブの無いマシンに一時的にPXEを設定してインストールに使う、といった場合はこれでもOKである。しかし、上のような理由で今回は「今使っている」HDCPサーバをOFFにすることはやりたくない。

ブロードバンドルータなどの現行DHCPPXEDHCPが併用できないのは「DHCPクライアントを取り合って、どちらのDHCPサーバからサービスを受けるか分からないから」というのが一般的な理由だ。しかし、サービスを受けるDHCPを設定(もしくは固定)できるのであれば2台(もしくは複数台)のDHCPサーバを混在できる筈だ。サービスの運用で使うのであれば1台のDHCPに集中させるのは良い方法ではないし、当然、複数台に分散しているだろう。1つのブロードキャスト・セグメントにDHCPが1台しか設置できないのは不都合だ。(繰返しになるが、ブロードバンド・ルータのDHCPサーバでPXEサーバ(next-server)の指定が出来れば、何も2台も設定する必要はないのだが。)

ということで、dhcpd.confを見ていくと、かなり詳しい設定ができることが分かった。ある条件で特定のマシンだけをグループ化して、そのマシンだけにサービスすることが可能だ。今回の環境の場合、ブロードバンド・ルータのDHCPサーバは反応が遅く、PXE用のDHCPサーバはCore2 Duo 3GHz搭載なので反応が早い(意味は無いがClockによる単純計算では200倍は速い)。まず、PXEDHCPがパケットを見て自分が処理するクライアントからのものでなければ無視すれば、その内ブロードバンド・ルータのDHCPサーバが反応してくれる。(あくまで確率上の話しなので、本来PXEDHCPサーバが処理しなければならないクライアントを先にブロードバンド・ルータのDHCPサーバが捕捉してしまうこともあるが、実質的にあまりあり得ないし。)

/etc/dhcpd.conf

最終的に作成した /etc/dhcpd.conf は以下のとおり。

ddns-update-style	none;
ignore		client-updates;

subnet 192.168.1.0 netmask 255.255.255.0 {
	option routers		gateway12;
	option subnet-mask		255.255.255.0;

	option nis-domain		"localdomain";
	option domain-name		"localdomain";
	option domain-name-servers	gateway12, gateway01;

	option time-offset		32400;  # Japan Standard Time
	option ntp-servers		ntp.nict.jp, ntp.jst.mfeed.ad.jp;

	deny	unknown-clients; # デフォルトで allow
}

host bishop {
	hardware ethernet	00:67:89:AB:CD:EF;
	fixed-address		bishop;
##	option vendor-class-identifier  "PXEClient"; # この行は要らない。あるとNG
	next-server		192.168.1.10; # ホスト名ではNG
	filename		"/bishop/pxelinux.0";
##	allow			booting; # デフォルトで allow
	default-lease-time	1296000; # 2 weeks
	max-lease-time		2592000; # 4 weeks
}

「bishop」というのはPXEを使ってブートさせるクライアントのホスト名である。/etc/hostsでIPアドレスを定義してある。同様に「gateway12」はデフォルト・ゲートウェイのホスト名である。ネットなどでdhcpd.confの例を見ると直接IPアドレスを書き込んでいるケースが多いが、IPアドレスを変更する際に/etc/hostsと/etc/dhcpd.confの両方を変更しなければならないので設定ミスの元となりかねない。

このdhcpd.confでは2つセクションを定義している。1つは現在使っているサブネット(192.168.1.0/24)の情報である。デフォルトゲートウェイDNSサーバ、ドメイン名、NTPサーバ名などを定義している。DHCPサーバは「この」サブネットからの要求があると、これらの情報を渡すことになる。ここで注目なのは

	deny	unknown-clients; # デフォルトで allow

の部分。これは素性の知れない(ネット的にはMACアドレスとかが既知でない)マシンからのサービスには受け付けない、という設定である。今回のPXEクライアントは全てMACアドレスを予め登録することを前提とするので、それ以外のマシンからの要求には応えないようにする。従って、一般的なdhcpd.confの記述される次のような

	range dynamic-bootp	192.168.1.128 192.168.1.254;

「range」は必要ない。

もう一つのセクションは「bishop」というマシンについての処理を記述した部分である。最初、このセクションは、上のサブネットのセクションのサブセクションとして定義していた。(「bishop」は192.168.1.0/24に属しているので。)しかし、dhcpdコマンドでdhcpd.confの設定確認をすると

# dhcpd -t -d
WARNING: Host declarations are global.  They are not limited to the scope you declared them in.

と怒られてしまう。Host宣言は「global」扱いでサブネットセクションに置くな、と言うことらしい。素直にホスト・セクションをサブネット・セクションから外側に出してglobalとした。これで警告メッセージは出なくなった。

ここの部分は「bishop」に関するMACアドレスIPアドレスなどを定義している。注意点は2点。
ネット調べると「option vendor-class-identifier "PXEClient"」の記述は”必ず必要”とあったが、この行があると動作しなかった。これが分かるまで随分時間を喰ってしまった。この記述があるとDHCPでアドレスは割り振られるが、PXEでのブートファイルを見つけ出せなくなる。本来記述が要らないのか、現行のdhcpdのバグなのかは分からない。

もう一点は、「next-server」の指定ではホスト名ではなく直接IPアドレスを記述しなければならない。

その他設定

あとは、この記述に合うように /tftpboot/bishop/ というディレクトリを作りその下に、幾つかファイルをコピーすれば良い。(取りあえず、Linuxインストール用のカーネルとRAMイメージをコピーして実験してみた。ディスクレスの設定はこれから。)

# cp "Fedora 8のインストールCD"/images/pxeboot/vmlinuz /tftpboot/bishop/
# cp "Fedora 8のインストールCD"/images/pxeboot/initrd.img /tftpboot/bishop/
# cp /usr/lib/syslinux/pxelinux.0 /tftpboot/bishop/

/tftpboot/bishop/pxelinux.cfg/defaultはいたってシンプル

default f8
# prompt 1
# timeout 100

label f8
	kernel vmlinuz
	append load initrd=initrd.img devfs=nomount

なお、今回はbishopというマシンだけだったので、/tftpboot/bishop/ というパスにしたが、ディスクレスが数台ある場合は、、/tftpboot/linuxboot/ 見たいなパス名にして、カーネルに渡すパラメータ(例えば、ルートファイルシステムなどの指定)は 、/tftpboot/bishop/pxelinux.cfg/ の下にマシンごとのコンフィグファイルを作った方が良いと思う。PXEでは各マシンの”01-MACアドレス"、"IPアドレスの16進表現"と同じ名前のファイルを順番に探して、見当たらなければ最後に「default」を参照する。例えば、bishopの場合は、/tftpboot/bishop/pxelinux.cfg/01-00-67-89-ab-cd-ef というファイルを先に参照する。

tftpのテストをするときはFirewallをOFFに

ブート時にソフトウェアをtftpでダウンロードする時は関係ないが、PXEの設定途中などでtftpのテストする際は注意が必要だ。tftpクライアント側ファイヤーウォールを一旦OFFにしておいた方がいい。(tftpの動作確認が出来ずに、ここでもちょっと手間取った)
tftpサーバ側でtftpポート(69番)を開けておくのは当然だが、クライアント側でも設定を変える必要がある。テスト目的であれば一時的にファイヤーウォールをOFFにした方が手っ取り早い。

追記(2008/01/29)

PXEによるディスクレス・クライアント(総集編)」にまとめた。もう一度、最初からインストールして整理してある。ただし、手順の流れを重視したので、詳細は以下を参考にして欲しい。

tftpのルートディレクトリが変更できない?

vmserver(仮想マシンのホストマシン名)のルートファイルシステムの大きさは7GBしかない。現在約50%を使って残り3GBちょっとは残っているが、フンダンにあるわけではないので /ftfpboot を /home/TFTPboot へ引っ越そうと思った。簡単に出来る....
筈だった。

ディレクトリを用意しておいて、/etc/xinetd.d/tftp でルートパスを設定すればいい。

# default: off
# description: The tftp server serves files using the trivial file transfer \
#       protocol.  The tftp protocol is often used to boot diskless \
#       workstations, download configuration files to network-aware printers, \
#       and to start the installation process for some operating systems.
service tftp
{
        socket_type             = dgram
        protocol                = udp
        wait                    = yes
        user                    = root
        server                  = /usr/sbin/in.tftpd
        server_args             = -v -s /home/TFTPboot # ←ここを変更
        disable                 = no
        per_source              = 11
        cps                     = 100 2
        flags                   = IPv4
}

これで xinetdを再起動するだけで終わる筈だった。
ところが、また、上手く動かない。DHCPでアドレスは取得できるが、TFTPでPEXローダをダウンロードできない。
SELinuxが文句を言っている。SELinuxは本当に鬼門だ。今までSELinuxを避けて通って来たが、今回は無理そうだったので、仕方なくSELinuxについて調べてみた。(「第一人者がやさしく教える新SELinux入門」を参照した。私にとってはちょっと難しかったが。)

tftpdプロセスには tftpd_t というドメインが割り振られているが、どうもSELinuxのログによると /homeディレクトリの home_root_t というタイプにアクセスできないといっている。tftpd には /home ではなく /home/TFTPboot を指定しているのに。念のため /home/TFTPboot のラベルを確認してみると tftpdir_t となっていて、このタイプが割り振ってあれば tftpd_t からアクセスできる筈なのに。

# ls -aZ /home/TFTPboot/
drwxr-xr-x  root root system_u:object_r:tftpdir_t:s0   .
drwxr-xr-x  root root system_u:object_r:home_root_t:s0 ..
drwxr-xr-x  root root system_u:object_r:tftpdir_t:s0   bishop

tftpdがchrootをする際に、行き成り与えられたパスではなく、上位のディレクトリの情報を読んでいるらしい。

/homeのタイプをtftpdir_tにするわけにもいかない。(実験的に変えてみたが、するとtftpは使えてもsambaもvmwareもアクセスできなくなってしまった。)bool設定でも回避できない。あと残る手段としては、

  1. SELinuxを「enforcing」から「permissive」に変更する。
  2. tftpd_tドメインがhome_root_tタイプにアクセスできるようにローカルポリシーを設定する。

しかなさそうだ。おうちサーバだからセキュリティはそれ程高くする必要はない。しかしSELinuxをpermissiveにするのは、Linuxオタクとしては屈辱的である。ということで、初めてポリシーの作成したみた。

まず、適当な作業ディレクトリでTEファイルを作成する。一旦、SELinuxをpermissiveにしてtftpをかけて警告をださせる。その後でaudit2allowコマンドでTEファイルを作る。

# audit2allow -a -l -m vmserver > vmserver.te

# cat vmserver.te
module vmserver 1.0;

require {
        type home_root_t;
        type tftpd_t;
        class dir search;
}

#============= tftpd_t ==============
allow tftpd_t home_root_t:dir search;

tftpdが/home直下のファイルに対して自由に読み書きできるようになるのは宜しくないので、/homeというディレクトリの情報だけを読める(searchできる)ように設定する。

このTEファイルからバイナリのポリシーファイルを作成する。

# ls
vmserver.te

# make -f /usr/share/selinux/devel/Makefile
Compiling targeted vmserver module
/usr/bin/checkmodule:  loading policy configuration from tmp/vmserver.tmp
/usr/bin/checkmodule:  policy configuration loaded
/usr/bin/checkmodule:  writing binary representation (version 6) to tmp/vmserver.mod
Creating targeted vmserver.pp policy package
rm tmp/vmserver.mod.fc tmp/vmserver.mod

# ls
tmp  vmserver.fc  vmserver.if  vmserver.pp  vmserver.te

つぎにこのローカルポリシーvmserver.ppをシステムに登録する。

# semodlue -i vmserver.pp

さて、SELinuxをEnforcingに設定して、tftpをかけてみると見事に成功した。