DisklessなLinuxマシンをつくる.ここでdisklessであるとは,
ことを指すことが多いが,その目的・メリットは
のように,
ハードディスクに収まっていたはずのOSをどこから用意するか
ということの実現方法に応じて異なる.
ここでは前者の"集中管理"を目的として,ネットワークブート型のdiskless linuxを実現することにし,以降では
と呼ぶことにする.
なお後者のCD / FDブートの選択肢としては,Knoppix(日本語版)が
などの点で優れている.
いくつか選択肢がある.
今回は,以下の手順で起動させる方法を説明する.
以下では,
として説明を行う(tftp/nfs/dhcpサーバは別々でもよい).
基本的方針は,
という流れ.この節ではサーバのファイルではなく,クライアント用に用意したファイル・ディレクトリを操作している点に注意!(chrootして作業すると,ミスの心配が無くていいかもしれない)
今回は/tftpboot/LinuxをクライアントがNFSでマウントするので,ここにホストの/以下をコピーする(1).
# cd /tftpboot/Linux # cp -a /bin /dev /etc /lib /sbin /usr /var .
次に空のディレクトリを作る
# cd /tftpboot/Linux # mkdir home mnt proc ram root boot sys
ramは,後にramディスクをマウントするために作っておく.
なおディスク容量の都合で/usr/local/tftpbootなど,どこか別の場所を使いたい場合も,mountのbindオプションを使用して/tftpboot以下にマップしておくと何かと間違いが少なくてすむだろう.コマンドラインからは
# mount -o bind /usr/local/tftpboot /tftpboot
とし,起動時に自動的にマウントさせるためにはfstabに以下のように書く.
/usr/local/tftpboot /tftpboot auto bind 0 0
debianの場合,基本的に
となっている.
DHCPでカーネル自身にIP関係の設定をさせるので,一番やっかいなネットワーク関係のファイルは必要ない.よって,
127.0.0.1 localhost ::1 ip6-localhost ip6-loopback fe00::0 ip6-localnet ff00::0 ip6-mcastprefix ff02::1 ip6-allnodes ff02::2 ip6-allrouters ff02::3 ip6-allhosts
# iface lo inet loopback auto lo iface lo inet loopback
# <file system> <mount point> <type> <options> <dump> <pass> proc /proc proc defaults 0 0
mtabには,現在のマウント状況が保存される.つまり,ホスト毎のマウント状況に応じて異なる内容となるので,本来は共有できない.そこでホントはやってはいけないかもしれないが,取り合えず
# ln -sf /proc/mounts mtab
としてしまう.
ifstateには,ネットワークの状況が保存される[7]./dev/nullへのリンクでもOKらしいが,
# ln -sf /ram/ifstate network/ifstate
としてしまう.
varには2種類のデータがある.
この判断に基づいて,先にコピーしたうちの「個別にすべきもの」を退避させる.
# mkdir /tftpboot/Linux/var.ro # mkdir /tftpboot/Linux/var.ro/lib # cd /tftpboot/Linux/var # mv local lock log mail run spool tmp yp ../var.ro/ # mv lib/nfs ../var.ro/lib/nfs
これらは後にramディスクに書き込むようにするので,リンクしておく
# cd /tftpboot/Linux/var
# for i in local lock log mail run spool tmp yp; do ln -s \
/ram/var/${i}; done
# ln -s /ram/var/lib/nfs lib
ここで,"/ram"とする点に注意./tftpboot/Linuxにchrootしたと想定したときに,ちゃんとリンクをたどれるようにするため.
/ram/tmpへのリンクとする.
# cd /tftpboot/Linux # ln -s /ram/tmp
別に/tmp自身をramディスクとしてもいいが,/tmpは起動時にクリーンアップされるので注意.
ここにramディスクをマウントし,個別に用意すべきものを入れる.このためのスクリプトとして
## tmpfs を使用する場合 mount -t tmpfs tmpfs /ram -o size=128m ## 従来の /dev/ram を使用する場合 # /sbin/mke2fs /dev/ram0 # /bin/mount /dev/ram0 /ram # var mkdir /ram/var/ cp -a /var.ro/* /ram/var # tmp mkdir /ram/tmp/ chmod 1777 /ram/tmp
を/tftpboot/Linux/etc/init.d/NFSROOTとして作成する(2).
# cd /tftpboot/Linux/etc/init.d/ # vi NFSROOT # chmod +x NFSROOT
次にetc/rcS.dを眺めると,S35mountall.shでfstabの内容をマウントしているようなので,この直前にNFSROOTスクリプトを実行するようにする.
# cd /tftpboot/Linux/etc/rcS.d # ln -s ../init.d/NFSROOT S34NFSROOT
そしてmountall.shの内容を若干変更する(3).
--- mountall.sh.old Thu Nov 1 18:05:41 2001 +++ mountall.sh Mon Apr 15 22:33:38 2002 @@ -11,8 +11,9 @@ # about this. So we mount "proc" filesystems without -v. # [ "$VERBOSE" != no ] && echo "Mounting local filesystems..." -mount -avt nonfs,nosmbfs,noncpfs,noproc -mount -at proc +#mount -avt nonfs,nosmbfs,noncpfs,noproc +#mount -at proc +mount -av # # We might have mounted something over /dev, see if /dev/initctl is there.
クライアントがブートするためのカーネルを用意する.後にクライアント自身で再コンパイルすることも考えて,/tftpboot/Linux/usr/srcにソースを展開して作業する.
# cd /tftpboot/Linux/usr/src
# rm linux
# wget \
http://ring.astem.or.jp/archives/linux/kernel.org/kernel/v2.4/linux-2.4.25.tar.bz2 \
# tar jxvf linux-2.4.25.tar.bz2
# ln -s linux-2.4.25 linux
# cd linux
次にカーネル設定をする.
# make xconfig
クライアント自身に必要なものの他に,
CONFIG_IP_PNP=y CONFIG_IP_PNP_DHCP=y CONFIG_IP_PNP_BOOTP=y CONFIG_IP_PNP_RARP=y CONFIG_TMPFS=y CONFIG_RAMFS=y CONFIG_ROOT_NFS=y
は必要.基本的にモジュールとしてコンパイルすることは避けること(4).起動時に必要なものをモジュールにしてしまうと,「鶏と卵」状態になるので.こうするとbzImageがフロッピーに入らないくらい大きくなるが,bzImageはtftpでネットワークからダウンロードするので気にしなくてよい.
コンパイルし,必要なものをコピー
# make-kpkg --revision nfsroot.20020415.0 kernel_image # cp arch/i386/boot/bzImage /tftpboot/Linux/boot/vmlinuz-2.4.25 # cp System.map /tftpboot/Linux/boot/System.map-2.4.25 # cd /tftpboot/Linux # ln -s /boot/vmlinuz-2.4.25 vmlinuz
ここでも,最後のシンボリックリンクは/tftpboot/Linuxにchrootしたときにつじつまが合うように注意すること.また,モジュールも作ったのならそれもコピーしておくこと.(5)
用意したnfsroot用のディレクトリをexportするためのサーバを設定する.
まずtftpサーバ.使用したのはtftpd-hpaパッケージのもの.特にPXEの場合,tftpパッケージのものでは不具合があるらしい.
tftp dgram udp wait root /usr/sbin/in.tftpd /usr/sbin/in.tftpd -s /tftpboot
次にnfsサーバ.使用したのはnfs-kernel-serverパッケージのもの.
/tftpboot 192.168.0.0/255.255.255.0(rw,no_root_squash)
最後にdhcpサーバ.使用したのはdhcp3-serverパッケージのもの.
# global params
option domain-name-servers 192.168.0.1;
option domain-name "yourdomain";
option subnet-mask 255.255.255.0;
option broadcast-address 192.168.0.255;
option routers 192.168.0.1;
# for static assign
group {
use-host-decl-names on;
host client1 {
hardware ethernet 12:34:56:78:9a:bc;
fixed-address client1.yourdomain;
}
}
ただし,"client1.yourdomain"がDNSで参照できるようにしておくこと.
あとは各デーモンのリスタートorリロード(6).面倒なときはinitスクリプトで.
# /etc/init.d/inetd reload # /etc/init.d/nfs-kernel-server reload # /etc/init.d/dhcp3-serve restart
基本的にsyslinuxに含まれる/usr/share/doc/syslinux/pxelinux.docに沿って作業を行う.
まずtftpサーバとなるマシンに,syslinuxパッケージをインストールする(7).
あとは/tftpboot以下に必要なものを用意する.
# cp /usr/lib/syslinux/pxelinux.0 /tftpboot # mkdir /tftpboot/pxelinux.cfg # vi /tftpboot/pxelinux.cfg/default
DEFAULT linux LABEL linux KERNEL Linux/boot/vmlinuz-2.4.25 APPEND root=/dev/nfs nfsroot=192.168.0.1:/tftpboot/Linux ip=dhcp IPAPPEND 0
ここで,KERNELで指定するファイル名は,tftpdが/tftpbootにchrootしていることに注意して,そこからの相対パスとする.どうにもうまくいかなければ,/tftpboot直下にコピーして,これを指定すればよい.
また,pxelinuxにはIPAPPENDという便利な機能があるが,ここではホスト名を自動設定するためにip=dhcpとした.
dhcpd.conf (ISC dhcpd ver 3用)を以下のように修正し,再起動させる.
# global params
option domain-name-servers 192.168.0.1;
option domain-name "yourdomain";
option subnet-mask 255.255.255.0;
option broadcast-address 192.168.0.255;
option routers 192.168.0.1;
allow booting;
allow bootp;
# for static assign
group {
# for hostname
use-host-decl-names on;
option vendor-class-identifier "PXEClient";
# この行は不要かも
option vendor-encapsulated-options \
09:0f:80:00:0c:4e:65:74:77:6f:72:6b:20:62:6f:6f:74:0a:07:00:50:72:6f:6d:70:74:06:01:02:08:03:80:00:00:47:04:80:00:00:00:ff; \
next-server 192.168.0.1;
filename "pxelinux.0";
host client1 {
hardware ethernet 12:34:56:78:9a:bc;
fixed-address client1.yourdomain;
}
}
vendor-encapsulated-optionsの値が非常に長い文字列になっているが,改行せずに1行で指定すること.
クライアントがブートするためのフロッピーをつくる.
GNU GRUBをダウンロード,コンパイル,インストール.このとき,ネットワークブート対応のフロッピーを作る点に注意.
debianの場合(作業時のgrubのバージョンは0.91-4),
$ apt-get source grub $ cd grub-0.91 $ dpkg-buildpackage -us -uc -rfakeroot $ su # dpkg -i ../grub_0.91-4_i386.deb
でgrub自身をインストールした後,
$ make clean $ ./configure --enable-diskless --enable-rtl8139
でディスクレスブート可能なstage1とstage2を作る.たいていのカードには対応しているので,詳しくはnetboot/README.netbootを読むこと.
以下の作業では,コマンドとして使用するgrubと,実際にフロッピーに書き込むstage1とstage2をコンパイルしたgrubのバージョンをそろえること.要するに,ソースツリーの./grub/grubを直接起動する.
コマンドはパッケージからインストールしたものを使用し,stage1とstage2は別ソースから作ったりすると,起動できない可能性がある.
残念ながらgrubのバージョン1系列では,1000Base-TのNICには対応していない.しかし最近はオンボードのNICがIntelのEtherExpress Pro/1000アダプタであることも多い.このような場合はオリジナルのgrubにresumo [8]パッチをあてるとconfigureで
が使えるようになる.他にもいくつかパッチがgrubのメーリングリストなどに流れたことがあるが,結局このパッチが一番安定している.
まず,空のフロッピーをフォーマット(この場合はmtoolsを使ってvfat形式).
# superformat -B /dev/fd0 hd
これをマウントし,必要なファイルをコピー.
# mount /dev/fd0 /mnt
# cd /mnt
# mkdir -p boot/grub
# cd boot/grub
# cp ${YOUR_GRUB_SRC_PATH}/stage1/stage1 .
# cp ${YOUR_GRUB_SRC_PATH}/stage2/stage2 .
# cp ${YOUR_GRUB_SRC_PATH}/docs/menu.lst .
このmenu.lstはサンプルなので,これを以下のように編集
# Boot automatically after 30 secs.
timeout 30
# By default, boot the first entry.
default 0
# Fallback to the second entry.
fallback 1
# For installing GRUB into the hard disk
title Linux {tftp,nfsroot,dhcp}@yourhost
dhcp
# override tftp server address if DHCP server is not tftp server
# tftpserver 192.168.0.2
root (nd)
kernel /Linux/vmlinuz root=/dev/nfs nfsroot=192.168.0.1:/tftpboot/Linux \
ip=dhcp
tftpをdhcpとは別のサーバでやっているのなら,
# override tftp server address if DHCP server is not tftp server tftpserver 192.168.0.2
のように指定しておく.inetd.confでtftpサーバからアクセスできる範囲を/tftpboot以下にしたので,パス名が/Linuxから始まることに注意.
最後にブートできるようにフロッピーに書き込む.
# grub grub> root (fd0) grub> setup (fd0) grub> quit
あとは
# fdflush # umount /mnt
で,取り出して終了.
以上で準備は整ったはずなので,PXEあるいはフロッピーから起動してみる.起動しないときは,フロッピーから起動してメニューが表示された段階で「c」キーを押し,コンソールに切り替えて,
まず
>dhcp
としたときに,DHCPでIPが取得できているかどうか.
続いて
>root (nd)
>kernel /Linux/vmlinuz root=/dev/nfs \
nfsroot=192.168.0.1:/tftpboot/Linux ip=dhcp
としたときに,カーネルがダウンロードされるかどうか.ただしtftpサーバがdhcpサーバと別なら,
>tftpserver 192.168.0.2
>root (nd)
>kernel /Linux/vmlinuz root=/dev/nfs \
nfsroot=192.168.0.1:/tftpboot/Linux ip=dhcp
のようにアドレスを指定すること.
最後に
>boot
としてブートが始まるかどうか.
をチェックする.これらは順に
が原因として考えられる.カーネルの起動メッセージをよく観察しましょう.
起動した後は,
# dpkg -i \
/usr/src/kernel-image-2.4.25_nfsroot.20020415.0_i386.deb
など適宜必要なことを.
Wake on LAN (WoL)対応のマザーを使用している場合,LAN上の別のマシン,例えば今回の場合はdhcpサーバなどからマジックパケットを送信することで,リモートから電源を入れることが可能になる.これは特に,PCクラスタを運用しているときに便利.
マジックパケットの送信には,wakeonlanというコマンド(debianパッケージ名もwakeonlan)を使用する.使用方法はシンプルで,
# wakeonlan 01:02:03:04:05:06 ...
のように,起動したいマシンのMACアドレスを必要な数だけ指定すればよい.
クライアントを,ブート後はただのX端末として使用するようにするには,xdmcp接続を設定すればよい.
まず接続先となるホストのxdmが,xdmcp接続を受け付けるようにする.
! コメントアウトする ! DisplayManager.requestPort: 0
* #any host can get a login window
つぎにクライアントのxdmの起動スクリプトを以下のようにする(8).
#!/bin/sh
X=/usr/X11R6/bin/X
H=接続先のホスト名
D=":0 vt7"
PID=/var/run/xdm-remote.pid
EXEC="$X -- $D -query $H"
if [ ! -x $X ]; then
exit 0
fi
case "$1" in
start | restart | force-reload | reload)
start-stop-daemon --start -b -m --pid $PID --exec ${EXEC}
;;
stop)
start-stop-daemon --stop --pid $PID
;;
*)
echo "Usage: $0 {start|stop}"
exit 1
;;
esac
これで「X端末もどき」ができあがる.
ISCのdhcpdではなく,dnsmasqを使う場合は,/etc/dnsmasq.confに
dhcp-boot=pxelinux.0,tftp-server-name,192.168.0.1
という行を追加する.「tftp-server-name」は,tftpサーバのドメイン名.
まずクライアントがnfsrootマウントする際のマウントオプションを以下のようにして設定してみる.
... root=/dev/nfs nfsroot=192.168.0.1:/tftpboot/Linux,rsize=8192,wsize=8192 \
ip=dhcp
もちろん,これにあわせてカーネルをコンパイルしておく必要がある(9).
またクライアントの数が多い場合,サーバ側のnfsデーモンの数を以下のようにして増やしておく.
# Number of servers to start up RPCNFSDCOUNT=16 # Options for rpc.mountd RPCMOUNTDOPTS=
ただし[6]によると,やみくもに増やせばいいというものではないらしい.
現在判明している不具合について.
[症状]
[回避策]
$ su # chroot /tftpboot/Linux # dpkg -i foo.deb ( or apt-get install ... ) # exit
ただし,デーモンをリスタートなんかしたりすると,nfsホスト側のプロセスが普通にchrootで再起動してしまうので,とんでもないことになる可能性が高い.要注意.
| [1] | H. Peter Anvin. SYSLINUX - The Easy-to-use Linux Bootloader. http://syslinux.zytor.com/ |
| [2] | Yoshinori K. Okuji. GNU GRUB - GNU Project - Free Software Foundation (FSF). http://www.gnu.org/software/grub/ |
| [3] | James McKenzie and Chris Lightfoot. RPLD - an RPL/RIPL remote boot server. http://gimel.esc.cam.ac.uk/james/rpld/index.html |
| [4] | Ken Yap and Markus Gutschke. EtherBoot.org. http://etherboot.sourceforge.net/ |
| [5] | Gero Kuhlmann. Netboot. http://netboot.sourceforge.net/ |
| [6] | Tavis Barr et al. Linux NFS-HOWTO. http://www.linux.or.jp/JF/JFdocs/NFS-HOWTO/ |
| [7] | Debian project. Parts of Debian needing help. http://www.nl.debian.org/devel/todo/index.html |
| [8] | NTT Corporation. Resumo. http://resumo.sourceforge.net/ |