PXEによるディスクレス・クライアント(総集編)

PXE(ピクシー)を使ったディスクレスの実現を試行錯誤しながらやってきたので、もう一度、サラからインストールして整理し、ちょっとまとめておく。なお、Fedora 8の環境での設定であり、他のディストリビューションは勿論、Fedoraの他のバージョンでも設定が異なる場合があるので注意が必要だ。*1

このページで書いたのはFedoraディスクレス・クライアントの実現方法だが、Ubuntuではもっと簡単にディスクレスを構成できることが分かった。⇒“ライブUbuntuをネットワークブートする − ディスクレスサーバ構築

*1:PEXではありません。PXEです。

参考リンク

PXEなどでGoogleと大体このページが上位に来る。良くまとまっている。結局、私も自分なりにまとめていくと、このページの内容に似てしまった。(やっていることが同じなので仕方ないが。)ただし、Fedora Core 6を使っているのでOSの環境とか違い、そのままではFedora 8の環境では利用できないところもあった。

PXEの詳しい仕様が書いてある。Linuxにおけるパッケージのインストールなどで役に立つかは分からないが、細かいところでハマった時には役にたつことがある。(ただ、「仕様」と「実装系」で必ずしも内容が一致しているとは限らないので注意が必要だ。)

英語版だが、syslinux(Linux系でPXEの実装系の元とのなったシステムで、DOSのフロッピー等からLinuxをブートするためのシステム)の解説。大変詳しく書いてある。

syslinuxのコンフィグファイル(PXE環境においてはpxelinux.cfgディレクトリ配下のコンフィグファイル)に関するman page。コンフィグ・ファイルを色々と試す時には役に立つ。

SELinuxについて順序だって書いているので役に立った。(ただ、私にとって「やさしく」はなかった。)細かいところまで解説してくれているので嬉しいが、ページがあちこちに分断されているので、これの要約版があるともっと嬉しい。(それと、この日経のページは広告が多いのか、サーバがしょぼいのかダウンロードに大変時間がかかってもどかしかった。)

ディスクレスブートの概要

今回実現したディスクレスPXEによるネットワークブートを利用した。これは次のような手順による。

  1. 先ずクライアントPCがDHCPを利用してIPアドレスPXEブートサーバのアドレスを得る。
  2. PXEブートサーバからNBP(Network Bootstrap Program)をtftpを使ってダウンロードする。
  3. NBPを使って、アプリケーション(この場合はLinuxカーネル)をダウンロードし、起動する。
  4. LinuxカーネルNFSを使ってルートファイルシステムとそのSnapshotをマウントする。

という流れになる。PXEに関してはインテルのホームページに資料がある。(「Preboot Execution Environment (PXE) Specification」)

それではPXEによるネットワークブートの手順に沿ってそれぞれのソフトウェアをインストールしてゆく。

DHCPのインストールと設定

GNOMEなどを使っている場合は「ソフトウェアの追加と削除」で"dhcp"で検索して該当するパッケージを導入する。コマンドラインからインストールする場合は次の通り。

[root@vmserver ~]# yum install dhcp
	:
	:
[root@vmserver ~]# chkconfig --list dhcpd
dhcpd           0:off   1:off   2:on    3:on    4:on    5:on    6:off

パッケージを導入したら、設定ファイル(/etc/dhcpd.conf)を変更する。このファイルは利用環境によって設定項目が変わって来るが、今回は必要最小限の設定に限定して、以下の内容とした。

[root@vmserver ~]# cat /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	dnsserver02, dnsserver01;

	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:12:34:56:78:9A;
	fixed-address		bishop;
	next-server		vmserver;
	filename		"/linux-install/pxelinux.0";
	default-lease-time	1296000; # 2 weeks
	max-lease-time		2592000; # 4 weeks
}

上の内容は、PXEブート用のDHCPサーバとは別に、DHCPクライアントにアドレスを割当てる通常運用のDHCPサーバが別に存在するケースであり、PXEブート用のDHCPサーバは予めこのファイルにMACアドレスを登録しているクライアントにしかサービスを行なわない。(通常運用のHDCPサーバより、高速のマシンであり先に応答することを前提としている。もし、DHCPサーバ同士がクライアントを取り合いするような場合は通常運用のHDCPサーバに、ディスクレスクライアントに反応しないように設定するか、一時的に停止するしかないだろう。)

「filename」はPXEブートのソフトウェア(NBP)のパスを記入する。tftpのルートディレクトリからのパスで、標準では /tftpbootの下からのパスになる。この場合は、/linux-install/pxelinux.0で、Linuxでのルートからのパスは/tftpboot/linux-install/pxelinux.0となる。("linux-install"というディレクトリ名は後述するネットブート設定ユーティリティが使うので、固定されてしまう。本来、NBPの設置場所はとこでも良い筈だが、netbootを利用する場合は固定される。)

なお、上の/etc/dhcpd.confの例の中で使われている"vmserver", "bishop", "gateway12", "dnsserver02" 等はホスト名で/etc/hostsの中で定義されている必要がある。(ここでは、 "vmserver" がPXEブートサーバとなり、"bishop" がディスクレス・クライアントという想定だ。)IPアドレスで記述すると、IPアドレスの変更があった場合/etc/hostsの他に/etc/dhcpd.conf等の変更も必要となり、設定忘れの原因となりかねないので、できる限りホスト名を使用する。また、"ntp.nict.jp"、"ntp.jst.mfeed.ad.jp"のFQDNDNSで名前解決が可能でなければ当然使えない。

設定が終わったらdhcpdを再起動する。

[root@vmserver ~]# service dhcpd restart
Shutting down dhcpd:                                       [  OK  ]
Starting dhcpd:                                            [  OK  ]

なお、GNOMEのサービスの設定もしくはコマンドラインのchkconfig等でDHCPサービスが該当ランレベルでサービスされるように設定、確認する。

[root@vmserver ~]# chkconfig  --list dhcpd
dhcpd           0:off   1:off   2:on    3:on    4:on    5:on    6:off

この段階で、ディスクレスマシンをPXEブートさせてみる。勿論、まだブートは出来ないがDHCPで確実にIPアドレスを取得することを確認しておく。

TFTPのインストールと設定

GNOMEの「ソフトウェアの追加と削除」で"tftp-server"で検索して該当するパッケージを導入する。コマンドラインからインストールする場合は次の通り。

[root@vmserver ~]# yum install tftp-server
	:
	:
[root@vmserver ~]# chkconfig --list tftp
tftp            off

tftpdはxinetdから起動されるので、tftp-serverパッケージを導入する際に、xinetdが未導入であれば依存解決によりxinetdも同時にインストールされる。また、tftp-serverは後述するsystem-config-netbootパッケージの導入時に一緒に導入できる。(つまりnetbootパッケージの導入だけを先にするのであれば、tftpbootの導入は必要ない。)

次に/etc/xinetd.d/tftpを設定する。

[root@vmserver ~]# cat /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 /tftpboot
	disable			= no
	per_source		= 11
	cps			= 100 2
	flags			= IPv4
}

"disable"行を"no"にする。また任意で"server_args"行に"-v"を加えておくことで/var/log/messagesに詳しいログを取ることができる。

xinetdを起動する。

[root@vmserver ~]# service xinetd start
Starting xinetd:                                           [  OK  ]

ファイヤーウォールでTFTPのポート(69/UDP)を開放することも忘れずに。

さて、tftpdが機能するかどうかテストしてみる。Linuxからテストするにはtftp-serverの他にtftpパッケージが必要となる。tftpはWindows XP Professionalなどでも利用できるので試してみるといい。試験用に適当なファイル(下の例では/etc/dhcpd.confを使っているが何でも構わない)を/tftpbootの下にコピーして、他のPCからtftpでダウンロードできるか試してみる。

TFTPサーバ側

[root@vmserver ~]# cp /etc/dhcpd.conf /tftpboot/

TFTPクライアント側

C:\> tftp vmserver get dhcpd.conf
Transfer successful: 709 bytes in 1 second, 709 bytes/s

(テストが終わったら/tftpboot/の下から試験用ファイル取り除いておく。)

クライアント用のファイルシステムの作成

system-config-netbootの設定を行なう前に、クライアント用のファイルシステムを作成し、"/tftpboot/任意のディレクトリ/root"に置いておく。(ここではFedora 8をクライアント用に使ったので、/tftpboot/f8/rootというディレクトリの下に置く。)また、後述するnetbootで利用するsnapshotディレクトリも作る。(ここでは/tftpboot/f8/snapshotというディレクトリになる。)

一番簡単なのは、現在稼動しているDHCPクライアントなどのマシンを雛形マシンとしてルートファイルをコピーする方法だろう。手頃なマシンがあれば良いが、無ければ仮想マシンを一台仕立てて、不必要なオプションを削ってディスクレス用のファイルシステムとして構成するのが便利だ。今回、ディスクレスマシンはリモートデスクトップのコンソールとして使うのが目的なので、OSとして要求される機能は最小限で良いし、また仮想記憶無しで動かしたかったので、思い切って不必要機能を削って雛形を作った。

なお、雛形となるLinuxには「busybox-anaconda」というパッケージをインストールして置く必要がある。「アプリケーションの追加と削除」もしくはyumコマンドでインストールしておく。(busybox-anacondaの関連メモ「3種類のbusyboxは何が違うのか?」)

[root@fedora8 ~]# yum install busybox-anaconda

雛形のファイルシステムが用意できたら、ネットワークを経由してファイルをコピーして来る。方法は幾つかあるが、rsyncを使う方法はお手軽かも知れない。まず、rootとsnapshotというディレクトリを作っておく。

[root@vmserver ~]# mkdir /tftpboot/f8
[root@vmserver ~]# mkdir /tftpboot/f8/root
[root@vmserver ~]# mkdir /tftpboot/f8/snapshot

入れ物(/tftpboot/f8/root)が用意できたら、そこへルートファイルシステムをコピーする。

[root@vmserver ~]# rsync -v -a -e ssh \
	--exclude='/proc/*' --exclude='/sys/*' --exclude='/dev/*' --exclude='/media/*' --exclude='/tmp/*' \
	雛形マシンのIPアドレス:/ /tftpboot/f8/root/
root@雛形マシンのIPアドレス's password:
receiving file list ... done
	:
	:
sent 1566535 bytes  received 1691035675 bytes  3699676.96 bytes/sec
total size is 1685756852  speedup is 1.00

rsyncコマンドを使うと操作は簡単だが、後述するとおり、SELinuxのコンテキストをコピーできず、/tftpbootのサブディレクトリにコピーするために全てのファイルファイルが"tftpdir_t"のラベルになってしまう。

[root@vmserver ~]# ls -Z /tftpboot/f8/root
drwxr-xr-x  root root system_u:object_r:tftpdir_t:s0   bin
drwxr-xr-x  root root system_u:object_r:tftpdir_t:s0   boot
	:
	:
drwxr-xr-x  root root system_u:object_r:tftpdir_t:s0   usr
drwxr-xr-x  root root system_u:object_r:tftpdir_t:s0   var

SELinuxのコンテキストもオリジナルと同様にコピーする場合はdumpコマンドとrestoreコマンドを使う方法がある。

[root@vmserver ~]# cd /tftpboot/f8/root
[root@vmserver f8]# ssh 雛形マシンのIPアドレス \(cd / \; dump -0 -b 1024 -f - . \) | restore -rv -b 1024 -f -
Verify tape and initialize maps
Input is from a local file/pipe
root@雛形マシンのIPアドレス's password:
  DUMP: Date of this level 0 dump: Tue Jan 29 09:01:25 2008
	:
	:
Set directory mode, owner, and times.
Check the symbol table.
Check pointing the restore
[root@vmserver f8]# rm restoresymtable
rm: remove regular file `restoresymtable'? y
[root@vmserver f8]#

ここでdumpする時に「/」からの相対パスになるようにしている。restoreする先が「/」ではなく「/tftpboot/f8/root/」だからだ。restoreする時に書き出すルートディレクトリを変更することができるかどうか確認する時間がなかったので、この様な方法で安全策をとった。

dump&restoreでコピーした場合は、SELinuxのコンテキストも再現される。

[root@vmserver ~]# ls -Z /tftpboot/f8/root/
drwxr-xr-x  root root system_u:object_r:bin_t:s0       bin
drwxr-xr-x  root root system_u:object_r:boot_t:s0      boot
	:
	:
drwxr-xr-x  root root system_u:object_r:usr_t:s0       usr
drwxr-xr-x  root root system_u:object_r:var_t:s0       var

反面、dump&resotreではコピーファイルの選択ができず、全てのファイルをコピーして来てしまうので、コピー後に不必要なファイルを消去して置く方が良い。(ただし、/proc/* /sys/* /dev/*に関してはコピーされないので、/tmpや/varの下の不要なファイルのみを消せば良い。)また、クライアントのカーネルが起動する過程で/dev/consoleだけは予め作ってある必要があるので、consoleを作成しておく。

[root@vmserver ~]# cd /tftpboot/f8/root
[root@vmserver root]# rm .[^.]* .??*
rm: remove regular empty file `.autofsck'? y
[root@vmserver root]# rm -rf tmp/.[^.]* tmp/.??* tmp/*

[root@vmserver root]# mknod ./dev/console c 5 1
[root@vmserver root]# chmod 600 ./dev/console
[root@vmserver root]# chcon -t console_device_t ./dev/console

クライアントのファイルシステムを1つのファイルにまとめる

運用方針にも依るが /tftpbootは一般的にルート・ファイルシステムに属し、またルート・ファイルシステムはそれ程大きな容量のHDDパーティションに置かれることは少ないのではないだろうか。しかし、PXEブートによるディスクレス・クライアントは/tftpbootの配下にもう一つクライアント用のファイルシステムを飲み込むことになり、サーバのルート・ファイルシステムを圧迫する。
それを回避するには、例えば、/tftpboot/f8 を /home/tftpboot/f8 などにシンボリックリンクする方法もあるが、管理なども考えると、クライアント用のファイルシステムを1つのイメージファイルにまとめておいて/tftpboot/f8へマウントする方法がお勧めである。この方法であればクライアントのファイルシステムの本体は、サーバ上の任意のディレクトリ(ファイルシステム)に置くことができ、かつクライアントのバックアップもイメージファイルのコピーで済んでしまう。

[root@vmserver ~]# : 先ずファイルシステムを格納するファイルを作る
[root@vmserver ~]# dd if=/dev/zero of=/home/f8_diskless.img bs=2400M count=1
0+1 records in
0+1 records out
2147479552 bytes (2.1 GB) copied, 85.5222 s, 25.1 MB/s
[root@vmserver ~]# ls -l /home/f8_diskless.img
 -rw-r--r-- 1 root root 2147479552 2008-01-29 08:42 /home/f8_diskless.img

[root@vmserver ~]# : 次にファイルシステムとしてmkfsをかける
[root@vmserver ~]# mkfs -t ext3 /home/f8_diskless.img
mke2fs 1.40.2 (12-Jul-2007)
/home/f8_diskless.img is not a block special device.
Proceed anyway? (y,n) y
	:
	:

[root@vmserver ~]# : 作成したファイルシステムをマウントしてroot/とsnapshot/を作る
[root@vmserver ~]# mkdir /tftpboot/f8
[root@vmserver ~]# mount -o loop /home/f8_diskless.img /tftpboot/f8
[root@vmserver ~]# ls /tftpboot/f8
lost+found
[root@vmserver ~]# mkdir /tftpboot/f8/root
[root@vmserver ~]# mkdir /tftpboot/f8/snapshot
[root@vmserver ~]# ls /tftpboot/f8/
lost+found  root  snapshot

あとは、rsyncなりdumo&resotreなりでファイルをコピーしてくればいい。

NFSのインストールと設定

ディスクレス・クライアントはNFSを使ってサーバの/tftpboot/f8/rootを自分のルート・ファイルシステムとしてマウントする。複数のディスクレスで共有できるように"サーバ:/tftpboot/f8/root"はread onlyでマウントするため書き込みは出来ない。核クライアントに個別のファイルは"サーバ:/tftpboot/f8/snapshot/クライアント名"をread/writeでマウントする。すなわち、各クライアント毎の設定は"/tftpboot/f8/snapshot/クライアント名"の下に格納される。
これらのディレクトリをクライアントからNFSマウントできるように設定する必要がある。

先ずは、NFSをインストールする。

[root@vmserver ~]# yum install nfs-utils

次にクライアントからNFSでマウントできるように/etc/exportsに次の行を追加する。

/tftpboot/f8/root       192.168.0.0/24(ro,sync,no_root_squash)
/tftpboot/f8/snapshot   192.168.0.0/24(rw,sync,no_root_squash)

次にNFSの為にファイヤーウォールを設定する必要がある。NFSのためにポート2049/TCP、2049/UDPを空けるのは必須だが、関連してsunrpcポート111/TCP、111/UDP、更にRPCで使われるポートの開放も必要になる。RPCで使われるポートは標準では固定されていないので、ファイヤーウォールを使う環境ではこれらのポートを固定して、該当するポート番号を開放する。
RPCに使うポートの固定化はGNOMEのsystem-config-nfsの"Server Settings"ボタンから設定できる。

rpc.lockd(TCP): 48620
rpc.lockd(UDP): 48620
rpc.mountd(TCP): 48621
rpc.statd(TCP): 48622

また、/etc/sysconfig/nfsに次の項目を追加する。

LOCKD_TCPPORT=48620
LOCKD_UDPPORT=48620
MOUNTD_PORT=48621
STATD_PORT=48622

なお、RPCのポートの固定化において、一般的に決ったポート番号はないようだ。現在使用していないRegistered Port(1024-49151)のどれかを使うようだが、上の48620-48622を使った技術的根拠はない。敢えて言えば、Fedora 8の/etc/servicesで定義されているのが48619までだったことだ。
設定中はどの番号がどのポートか覚えていても設定が終わって1ヵ月もすれば「このポートは何でファイヤウォールで開放しているのだろう?」と忘れてしまうので/etc/servicesに名前を登録して置いた方がいい。/etc/servicesの最後の追加して置く。/etc/servicesで定義しておけば「ファイヤウォールの設定ツール」等でポート番号だけでなくポート名でも表示されるので分かりやすい。

(以下はtailコマンドで/etc/servicesを確認している様子。)

[root@vmserver ~]# tail /etc/services
com-bardac-dw	48556/tcp	# com-bardac-dw
com-bardac-dw	48556/udp	# com-bardac-dw
iqobject	48619/tcp	# iqobject
iqobject	48619/udp	# iqobject
# Local services
rpc.lockd	48620/tcp
rpc.lockd	48620/udp
rpc.mountd	48621/tcp
rpc.mountd	48621/udp
rpc.statd	48622/tcp

これらのポートに合わせてファイヤーウォールでポートを開放する。(ただし、rpc.mountd(48621)はTCPの筈だが、"-v"オプションつけてmountを実行するとUDPでリクエストを出している。そのためUDPポートを開放しないと通信が出来なかった。)現在、ファイヤーウォールPXEブート関連でポートを開放しているのは以下の通り。

tftp		69/UDP
sunrpc		111/TCP,UDP
nfs4		2049/TCP,UDP
rpc.lockd	48620/TCP,UDP
rpc.mountd	48621/TCP,UDP
rpc.statd	48622/TCP

いよいよNFSサービスを起動する。

[root@vmserver ~]# service nfs start
Starting NFS services:					[  OK  ]
Starting NFS quotas:					[  OK  ]
Starting NFS daemon:					[  OK  ]
Starting NFS mountd:					[  OK  ]

以降、該当ランレベルNFSデーモンが起動するように設定する。

[root@vmserver ~]# chkconfig --list | grep nfs
nfs             0:off   1:off   2:off   3:off   4:off   5:off   6:off
nfslock         0:off   1:off   2:off   3:on    4:on    5:on    6:off
[root@vmserver ~]# chkconfig --level 345 nfs on
[root@vmserver ~]# chkconfig --list | grep nfs
nfs             0:off   1:off   2:off   3:on    4:on    5:on    6:off
nfslock         0:off   1:off   2:off   3:on    4:on    5:on    6:off

netbootのインストールと設定

周りの環境が準備できたので、いよいよPXEブートの管理ツール system-config-netbootを導入して、設定を行なう。コマンドラインによる導入は以下の通り。

[root@vmserver ~]# yum install system-config-netboot

環境の設定

まず、クライアントに依存しない共通の環境を定義する。GNOMEのメニュー([System]⇒[Administration]⇒[Server Settings]⇒[Network Booting Servie])からsystem-config-netbootを起動する、初回の起動では「First Time Druid」というダイアログ形式のウィンドウが現れる。先ずDisklessを選らぶ。

次に、上で設定して来たとこを終わらせているかの確認画面が出るので[Forward]をクリックして次へ。

「Diskless Identifier」のウィンドウではこれから設定する環境の名前を入力する。今回は以下の通りとした。

  • Name: Fedora-8-Diskless
  • Description: Fedora 8, for diskless clients

[Forward]をクリックして次へ。

「Enter the NFS Information」というウィンドウでは、NFSサーバとマウントポイントの情報を入力する。

  • Server IP Address: 192.168.0.1
  • Directory: /tftpboot/f8/root

ここで注意が必要なのが、「Directory」で"/tftpboot"で始まって"/root"で終わる必要があるらしい。(ソースコードは確認していないが、他のパス名で実験して上手くいかなかった。)
[Forward]をクリックして次へ。

次に「Select the kernel for the diskless clients」というフォームが出る。/tftpboot/f8/rootの下に複数のkernelが存在する時はどれにするかを選択できるようになっている。(1つの場合は、1つのエントリしか出ない)適切なカーネルを選択し[Forward]をクリックして次へ。

最後に確認のウィンドウが出るので[Apply]をクリックして初期設定を終了する。

するとネットブートの管理画面が現るが、まだ、クライアントの設定をしていないので空の状態だ。

この段階で次の確認をする。

  • /tftpbootの下に"linux-install"というディレクトリが作成され、そこにPXEブート用のファイルが格納されている。そこには今定義した環境名(Fedora-8-Diskless)という名前のサブディレクトリが作られ、カーネルとRAMイメージがある。
[root@vmserver ~]# ls /tftpboot/linux-install/
Fedora-8-Diskless  msgs  pxelinux.0  pxelinux.cfg
  • /tftpboot/f8/root/の下に".oldroot"、".snapshot/"というディレクトリが作られている。
[root@vmserver ~]# ls /tftpboot/f8/root/
bin/        home/       misc/       opt/        selinux/    tmp/
boot/       lib/        mnt/        proc/       .snapshot/  usr/
dev/        lost+found/ net/        root/       srv/        var/
etc/        media/      .oldroot/   sbin/       sys/
  • /tftpboot/f8/snapshot/の下にfilesというファイルが作られ、各クライアント毎に個別に持つ必要があるファイルやディレクトリの一覧が格納されている。このファイルはシステムで使用するので、もし追加でクライアント毎の設定が必要な場合は/tftpboot/f8/snapshot/files.customというファイルを作り追加する。
[root@vmserver ~]# cat /tftpboot/f8/snapshot/files
#
# This file contains the list of files/directories to be stored in the
# snapshot directory for each diskless client.  Please do not edit this file,
# as Red Hat will be updating it with each release. If you wish to
# add files please create a files.custom in this directory and add entries to it.
#
/boot/kernel.h
/dev/
/etc/resolv.conf
	:
	:
/var/lib/ntp/
/var/yp/binding/
/root/

クライアントの設定

次にクライアントの設定を行なう。ネットブートの管理画面で[New]をクリックしてクライアントの情報を入力する。最低限必要なのはクライアントのホスト名(もしくはIPアドレス)を入力することである。あと、[Generate]というチェックボックスが選択されていることを確認して[OK]を押すだけである(後の項目は必要に応じて設定)。

すると、設定したクライアントのエントリが表示されている。

この時点では以下のことを確認する。

  • /tftpboot/f8/snapshot/の下にクライアント名のディレクトリが作成され、その下にクライアント固有のファイルやディレクトリが格納されてる。
[root@vmserver ~]# ls /tftpboot/f8/snapshot/bishop/
boot  dev  etc  lib  root  var
  • /tftpboot/linux-install/pxelinux.cfg/の下にクライアントのIPアドレスを16進表示したファイルが作られ、そこにクライアントのブート方法が記述されている。(以下の例はクライアントのIPアドレスが192.168.0.100(C0A80064)の場合。)
[root@vmserver ~]# cat /tftpboot/linux-install/pxelinux.cfg/C0A80064
default Fedora-8-Diskless

label Fedora-8-Diskless
    kernel Fedora-8-Diskless/vmlinuz
    append  initrd=Fedora-8-Diskless/initrd.img root=/dev/ram0 init=disklessrc NFSROOT=192.168.0.1:/tftpboot/f8 ramdisk_size=20920 ETHERNET=eth0 SNAPSHOT=

クライアントの起動

以上で、*ほぼ*サーバでの設定が出来たのでクライアントに電源を入れてPXEブートをさせる。しかし、期待に反して"Could not find kernel image"というメッセージと共にブートができない。

SELinuxの設定

サーバのDesktopをみるとsetroubleshootがメッセージを出している筈だ。アイコンもしくはバルーンをクリックするとsetroubleshootのウィンドウが開き、詳細を確認できる。

setroubleshoot browserを開きメッセージを確認すると

SELinux prevented /usr/sbin/in.tftpd from reading files stored on a NFS filesytem.

書かれて、対処策として

Changing the "use_nfs_home_dirs" boolean to true will allow this access: "setsebool -P use_nfs_home_dirs=1"
The following command will allow this access:setsebool -P use_nfs_home_dirs=1

と書いてある。そこでメッセージに従い次のコマンドを実行する。

[root@vmserver ~]# setsebool -P use_nfs_home_dirs=1

気を取り直して、再度クライアントをブートしてみよう。しかし、また"Could not find kernel image"というメッセージと共にブートができない。再び、SELinuxがブロックしている。メッセージを見ると前回と同じだ。どうも「booleanパラメータ」の変更だけでは回避できないようだ。

ここからは次のどちらかの方法を取る必要がある。

  • SELinux を permissive か disabled にする
  • SELinuxにローカルポリシーを追加する

ここではローカルポリシーの追加について述べる。

まず、一旦、SELinuxを permissiveに変更し、クライアントをブートする。途中、エラーメッセージが色々とですが、進められるところまで進める。何処まで進むかは環境に依ってことなる。カーネルの起動の途中までかデーモンの起動のところで固まるか、もしくはログインまで進むかは環境と設定による。今回はautomountデーモンの起動のところで一回ひっかりはしたが、キーを押すことで先へ進み、ログインのプロンプトまで確認できた。(ただし、Xウィンドウは立ち上がらなかった。)

この状態で、サーバで次のコマンドを実行しローカルポリシーを作る。

[root@vmserver ~]# mkdir tmp
[root@vmserver ~]# cd tmp
[root@vmserver tmp]# audit2allow -a -l -m vmserver > vmserver.te
[root@vmserver tmp]# cat vmserver.te

module vmserver 1.0;

require {
        type lvm_control_t;
        type tftpd_t;
        type nfsd_t;
        type nfs_t;
        class chr_file write;
        class file { read getattr };
}

#============= nfsd_t ==============
allow nfsd_t lvm_control_t:chr_file write;

#============= tftpd_t ==============
allow tftpd_t nfs_t:file { read getattr };

このテキストベースのポリシーを元に、バイナリ形式(.pp)を生成する。

[root@vmserver tmp]# 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 tmp/vmserver.mod.fc
[root@vmserver tmp]# ls
tmp  vmserver.fc  vmserver.if  vmserver.pp  vmserver.te

そして、このポリシーをシステムに登録する。

[root@vmserver tmp]# semodule -i vmserver.pp
[root@vmserver tmp]# semodule -l | grep vmserver
vmserver        1.0

さて、もう一度、クライアントをブートする。やはり先程と同じところまで進む筈だが、SELinuxの警告は出ていない。これでSELinuxの設定をEnforcingにしてもOKだ。

クライアントのSELinuxはdisabledに

クライアントのSELinuxはdisabledにした方が良い。NFSを通すと全てのファイルのコンテキストがタイプが"nfs_t"になってしまう。通常ルート直下ディレクトリのコンテキストは次のようになっている。

# ls -Z /tftpboot/f8/root/
drwxr-xr-x  root root system_u:object_r:bin_t:s0       bin
drwxr-xr-x  root root system_u:object_r:boot_t:s0      boot
drwxr-xr-x  root root system_u:object_r:root_t:s0      dev
	:
	:
drwxr-xr-x  root root system_u:object_r:usr_t:s0       usr
drwxr-xr-x  root root system_u:object_r:var_t:s0       var

しかし、NFSを通してアクセスするクライアントで実行すると次のようになってしまう。

# ls -Z /
drwxr-xr-x  root root system_u:object_r:nfs_t:s0       bin
drwxr-xr-x  root root system_u:object_r:nfs_t:s0       boot
drwxr-xr-x  root root system_u:object_r:tmpfs_t:s0     dev
	:
	:
drwxr-xr-x  root root system_u:object_r:nfs_t:s0       usr
drwxr-xr-x  root root system_u:object_r:nfs_t:s0       var

これは明らかのおかしい話しではあるが、これを解決する方法は見つからなかった。NFSを通しても元のコンテキストでアクセスできないとネットワーク環境でファイルを透過的に使えなくなってしまう。デフォルトが透過的ではなくてパラメータの設定によって変更できるのか探してみたが見つからなかった。となると私が知っている唯一の方法はクライアントはSELinuxをdisabledにする方法である。

クライアントのSELinuxをdisabledにするにはサーバ側で/tftpboot/f8/root/etc/selinux/configの中のSELINUXをdisabledに変更する。

[root@vmserver ~]# cat /tftpboot/f8/root/etc/selinux/config
# This file controls the state of SELinux on the system.
# SELINUX= can take one of these three values:
#       enforcing - SELinux security policy is enforced.
#       permissive - SELinux prints warnings instead of enforcing.
#       disabled - No SELinux policy is loaded.
SELINUX=disabled
# SELINUXTYPE= can take one of these two values:
#       targeted - Targeted processes are protected,
#       mls - Multi Level Security protection.
SELINUXTYPE=targeted
# SETLOCALDEFS= Check local definition changes
SETLOCALDEFS=0

細かい設定

クライアントの設定ファイルの修正

snapshotにあるもの以外、クライアントからは書き込み禁止になっているので、もし、設定ファイルの変更が必要であれば、サーバ側で /tftpboot/f8/root/の下のファイルを変更する。例えば、passwdファイルやhostsファイルを変更する時は、/tftpboot/f8/root/etc/passwdや/tftpboot/f8/root/etc/hostsを変更する必要がある。

ホームディレクト

/tftpboot/f8/root/homeは書き込み禁止である。従って、ホームを使えるようにするには次の用にするのが最適だろう。
まず、サーバ側の/etc/exportsでクライアントから/homeをマウントできるよう設定を追加し、サービスを再起動する。

[root@vmserver etc]# cat /etc/exports
/tftpboot/f8/root       192.168.0.0/24(ro,sync,no_root_squash)
/tftpboot/f8/snapshot   192.168.0.0/24(rw,sync,no_root_squash)
/home                   192.168.0.0/24(rw,sync)

[root@vmserver etc]# service nfs restart

次に、クライアントの/etc/fstab(/tftpboot/f8/snapshot/クライアント名/etc/fstab)にサーバにマウントするように記述しておく。

[root@vmserver etc]# cat /tftpboot/f8/snapshot/bishop/etc/fstab
# /etc/fstab for diskless clients, written by system-config-netboot
none			/dev/pts	devpts  gid=5,mode=620  0 0
none			/dev/shm	tmpfs   defaults        0 0
none			/tmp		tmpfs   defaults        0 0
/dev/cdrom		/media/cdrom	iso9660 noauto,owner,kudzu,ro 0 0
/dev/fd0		/media/floppy	auto    noauto,owner,kudzu 0 0
#
192.168.0.1:/home	/home		nfs	rw 0 0

この他に、/homeをsnapshotにする(/tftpboot/f8/snapshot/files.customで記述する)という方法もあるが、これだとクライアント毎に/homeの内容が別々になってしまう。