ディスクレスシステム
- ディスクレスノード (またはディスクレスワークステーション) とは、ディスクドライブを使わずに、ネットワークブートを利用してサーバーからオペレーティングシステムをロードするワークステーション、またはパーソナルコンピュータのことである。
目次
サーバー設定
まず最初に、以下をインストールする必要があります:
- ディスクレスノードに IP アドレスを割り当てるための DHCP サーバー。
- ブートイメージを転送するための TFTP サーバー (全ての PXE オプション ROM の必須要件)。
- Arch 環境をディスクレスノードにエクスポートするためのネットワークストレージ (NFS または NBD)。
DHCP
ISC dhcp をインストールして設定:
/etc/dhcpd.conf
allow booting; allow bootp; authoritative; option domain-name-servers 10.0.0.1; option architecture code 93 = unsigned integer 16; group { next-server 10.0.0.1; if option architecture = 00:07 { filename "/grub/x86_64-efi/core.efi"; } else { filename "/grub/i386-pc/core.0"; } subnet 10.0.0.0 netmask 255.255.255.0 { option routers 10.0.0.1; range 10.0.0.128 10.0.0.254; } }
RFC 4578 には "Client System Architecture Type" dhcp オプションが定義されています。上記の設定の場合、PXE クライアントが x86_64-efi バイナリ (タイプ 0x7) をリクエストした場合、適切に返答し、そうでない場合はレガシーなバイナリを使います。これによって、同一のネットワークセグメント上で同時に UEFI とレガシーな BIOS のクライアントを起動できるようにしています。
ISC DHCP の systemd サービスを起動してください。
TFTP
TFTP サーバーはブートローダーやカーネル、initramfs などをクライアントに転送にするのに使います。
TFTP の root は /srv/arch/boot
に設定してください。詳しくは TFTP を参照。
ネットワークストレージ
NFS と NBD どちらを使用する場合でも複数のクライアントを扱うことができますが、大きな違いとして、NBD では (ファイルシステムを直接操作するため) copyonwrite
モードを使う必要があります。そのため、クライアントが切断すると全ての書き込みが破棄されます。ただし、場合によってはこれが望ましいということも考えられます。
NFS
サーバーに nfs-utils をインストールしてください。
Arch 環境の root を NFS の exports に追加する必要があります:
/etc/exports
/srv *(rw,fsid=0,no_root_squash,no_subtree_check) /srv/arch *(rw,no_root_squash,no_subtree_check)
そして、NFS サービスを起動してください: rpc-idmapd
rpc-mountd
。
NBD
nbd をインストールして設定します。
# vim /etc/nbd-server/config
[generic] user = nbd group = nbd [arch] exportname = /srv/arch.img copyonwrite = false
nbd
systemd サービスを起動してください。
クライアントのインストール
次に、サーバーのサブディレクトリに完全な Arch Linux 環境を構築します。起動時、ディスクレスノードは DHCP サーバーから IP アドレスを取得して、PXE を使ってホストから起動し、構築した環境を root としてマウントします。
ディレクトリのセットアップ
最低でも1ギガバイトのスパースファイルを作成して、ファイル上に btrfs ファイルシステムを作成してください (もちろん、必要であればブロックデバイスや LVM を使うこともできます)。
# truncate -s 1G /srv/arch.img # mkfs.btrfs /srv/arch.img # export root=/srv/arch # mkdir -p "$root" # mount -o loop,discard,compress=lzo /srv/arch.img "$root"
ブートストラップのインストール
devtools と arch-install-scripts をインストールしてから mkarchroot
を実行してください。
# pacstrap -d "$root" base mkinitcpio-nfs-utils nfs-utils
そして initramfs を生成してください。
NFS
NFSv4 のマウントをするためには net
フックに細かい修正を加える必要があります (net
フックのデフォルトである nfsmount
はサポートされていません)。
# sed s/nfsmount/mount.nfs4/ "$root/usr/lib/initcpio/hooks/net" > "$root/usr/lib/initcpio/hooks/net_nfs4" # cp $root/usr/lib/initcpio/install/net{,_nfs4}
クライアント側で mkinitcpio-nfs-utils がアップデートされたときに上書きされないように net
のコピーを作成する必要があります。
$root/etc/mkinitcpio.conf
を編集して MODULES
に nfsv4
を、HOOKS
に net_nfs4
を、BINARIES
に /usr/bin/mount.nfs4
を追加してください。
そして、作成した環境に chroot して mkinitcpio を実行します:
# arch-chroot "$root" mkinitcpio -p linux
NBD
クライアントに mkinitcpio-nbdAUR パッケージをインストールする必要があります。makepkg でビルドしてインストールしてください:
# pacman --root "$root" --dbpath "$root/var/lib/pacman" -U mkinitcpio-nbd-0.4-1-any.pkg.tar.xz
HOOKS
行の net
の後ろに nbd
を追加する必要があります。net
はネットワークの設定を行いますが、カーネル行で nfsroot
が指定されていない場合 NFS のマウントは行いません。
クライアント設定
以下の設定の他に、ホストネーム、タイムゾーン、ロケール、キーマップなども設定する必要があります。インストールガイドを見て下さい。
ブートローダー
GRUB
ドキュメントで明記はされていませんが、GRUB は PXE によるロードをサポートしています。
# pacman --root "$root" --dbpath "$root/var/lib/pacman" -S grub
Create a grub prefix on the target installation for both architectures using grub-mknetdir
.
# arch-chroot "$root" grub-mknetdir --net-directory=/boot --subdir=grub
Luckily for us, grub-mknetdir creates prefixes for all currently compiled/installed targets, and the grub maintainers were nice enough to give us both in the same package, thus grub-mknetdir only needs to be run once.
以下のような GRUB の設定を作成します:
# vim "$root/boot/grub/grub.cfg"
menuentry "Arch Linux" { linux /vmlinuz-linux quiet add_efi_memmap ip=:::::eth0:dhcp nfsroot=10.0.0.1:/arch initrd /initramfs-linux.img }
GRUB の黒魔術によって set root=(tftp,10.0.0.1)
が自動的に設定されるため、特に設定をしなくてもカーネルと initramfs は TFTP で転送されます。TFTP 以外のメニューエントリが必要な場合、明示的に設定すると良いでしょう。
Pxelinux
syslinux には Pxelinux が含まれています。詳しくは Syslinux#Pxelinux を参照。
マウントポイントの追加
NBD root
In late boot, you will want to switch your root filesystem mount to both rw
, and enable compress=lzo
, for much improved disk performance in comparison to NFS.
# vim "$root/etc/fstab"
/dev/nbd0 / btrfs rw,noatime,discard,compress=lzo 0 0
Program state directories
You could mount /var/log
, for example, as tmpfs so that logs from multiple hosts do not mix unpredictably, and do the same with /var/spool/cups
, so the 20 instances of cups using the same spool do not fight with each other and make 1,498 print jobs and eat an entire ream of paper (or worse: toner cartridge) overnight.
# vim "$root/etc/fstab"
tmpfs /var/log tmpfs nodev,nosuid 0 0 tmpfs /var/spool/cups tmpfs nodev,nosuid 0 0
It would be best to configure software that has some sort of state/database to use unique state/database storage directories for each host. If you wanted to run puppet, for example, you could simply use the %H
specifier in the puppet unit file:
# vim "$root/etc/systemd/system/puppetagent.service"
[Unit] Description=Puppet agent Wants=basic.target After=basic.target network.target [Service] Type=forking PIDFile=/run/puppet/agent.pid ExecStartPre=/usr/bin/install -d -o puppet -m 755 /run/puppet ExecStart=/usr/bin/puppet agent --vardir=/var/lib/puppet-%H --ssldir=/etc/puppet/ssl-%H [Install] WantedBy=multi-user.target
Puppet-agent creates vardir and ssldir if they do not exist.
If neither of these approaches are appropriate, the last sane option would be to create a systemd generator that creates a mount unit specific to the current host (specifiers are not allowed in mount units, unfortunately).
クライアントの起動
NBD
NBD を使用する場合、クライアントを起動する前に arch.img
をアンマウントする必要があります。
This makes things particularly interesting when it comes to kernel updates. You cannot have your client filesystem mounted while you are booting a client, but that also means you need to use a kernel separate from your client filesystem in order to build it.
You will need to first copy $root/boot
from the client installation to your tftp root (i.e. /srv/boot
).
# cp -r "$root/boot" /srv/boot
You will then need to umount $root
before you start the client.
# umount "$root"