私はこれで ArchLinux を止めました。
声高に宣言するような話でもありませんが。
今年2022年の1月、archisoにzfsを埋め込む事に失敗し、私の中で何かが切れました。
こんなのもう嫌だ!ジリジリなジリ貧もビリビリな閃きでガチガチのバチバチでうおおおお!
そして閃いた、訳ではありませんが。世界一無難だと思われるUbuntuに乗り換える事にしました。今まで ArchLinux on ZFS を楽しみにしていた方々には大変申し訳ありません。そんな奇特な方々がいらっしゃったとも思えませんけど。
参考文献
Ubuntu on ZFS も、少ないながら先行事例があるようです。日本語の記事も少々。
参考文献:ルートパーティションをZFSにしてUbuntu 20.04 LTSをインストールしてみた
これと全く同じでも面白くないので一捻りします。ストレージを2台用意して、メインのディスクはパーティションを切らずに丸ごと全部zfsに任せます。その方が良いと言っていた参考文献、今は消滅してしまったようですね。残念。
環境
ホストマシン
Windows10Proです。これで使えるHyper-Vにインストールを試みます。以前の記事を参照。
ゲストマシン
- Hyper-V。上述の通り。
- 第1世代(BIOS起動)
- メモリ: 1024MB、動的メモリを有効にする
- 仮想プロセッサの数: 1
- ハードドライブ: 16GB を2台。異なる容量にすると
/dev/sda
/dev/sdb
が思った形にならないようなので、同容量を2台にしました。インストール手順の確認が目的なら十分かと。 - チェックポイント: どーでもいいんですが、自動チェックポイントは使用しない方向で。
インストール環境の整備
デスクトップインストーラーを起動しsshの環境整備
サーバーをインストールする場合でもデスクトップ版のisoを使用します。
尚、sshで接続するのはコマンドをコピペできるから。私もやってみてわかりましたが、これ良いですな。
GUI インストーラーが立ち上がって Welcome という画面が表示されたら、 TAB キーを押して Try Ubuntu ボタンにフォーカスを移動して(ボタンにオレンジの枠がつきます) Enter キーを押します。
ウィンドウ環境に切り替わったらターミナルを起動しますが、マウスが繋がっていない場合はショートカットキー Ctrl+Alt+T でどうぞ。
そして下記の2つのコマンドを実行。
sudo apt-add-repository universe
sudo apt update
OpenSSHサーバーをインストール。
sudo apt install --yes openssh-server
ssh接続先のIPアドレスを確認。
ip a
ssh接続用にユーザー ubuntu のパスワードを設定します。
passwd
別のマシンから対象のサーバーに ssh してインストール作業を続行
ssh はほとんどのOSで利用可能でしょう。Windows10でもコマンドプロンプトからsshコマンドを実行できます。
ssh ubuntu@接続先のIPアドレス
rootユーザーになります。
sudo -i
ディスクのフォーマット
まずはフォーマットすべきディスクを確認します。
lsblk
ディスクの指定にはIDを使います。
ls -l /dev/disk/by-id
これを変数に設定するのがubuntu流らしいですが、長大で無意味な文字の羅列を間違い無く打つのが苦痛なので、私の流儀で取得する事にします。
因みにHyper-Vの場合、BOOTDISKは /dev/sda
でないと駄目のようです。/dev/sdb
にしたら起動しなくなりました。
BOOTDISK=$(cd /dev/disk/by-id; ls ata-* scsi-* | while read d; do if [ "$(readlink -f $d)" = "/dev/sda" ]; then echo "/dev/disk/by-id/$d"; fi; done)
DISK=$(cd /dev/disk/by-id; ls ata-* scsi-* | while read d; do if [ "$(readlink -f $d)" = "/dev/sdb" ]; then echo "/dev/disk/by-id/$d"; fi; done)
ディスクのパーティションを全削除します。
wipefs -a $BOOTDISK
sgdisk --zap-all $BOOTDISK
パーティションを作成。
sgdisk -a1 -n1:24K:+1000K -t1:EF02 $BOOTDISK
sgdisk -n2:0:+1G -t2:BF01 $BOOTDISK
sgdisk -n3:0:0 -t3:0700 $BOOTDISK
設定を確認するコマンドは下記になります。
sgdisk -p $BOOTDISK
$DISK
はパーティションに分けません。
wipefs -a $DISK
いよいよzfsフォーマットします。ここが今回最大のコピペポイント!これをコピペする為にssh経由で接続していると言っても過言ではありません。
zpool create -o ashift=12 -d \
-o feature@async_destroy=enabled \
-o feature@bookmarks=enabled \
-o feature@embedded_data=enabled \
-o feature@empty_bpobj=enabled \
-o feature@enabled_txg=enabled \
-o feature@extensible_dataset=enabled \
-o feature@filesystem_limits=enabled \
-o feature@hole_birth=enabled \
-o feature@large_blocks=enabled \
-o feature@spacemap_histogram=enabled \
-o feature@userobj_accounting=enabled \
-O acltype=posixacl -O canmount=off -O devices=off \
-O normalization=formD -O relatime=on -O xattr=sa \
-O mountpoint=/ -R /mnt bpool $BOOTDISK-part2
参考文献には下記のように書かれていました。
normalization=formD
は Unicode の normalization の NFD に相当します。 昔 Subversion で Windows は NFC, Mac OS X は NFD と違うせいで全角カナの濁点が分かれない、分かれるで苦労したので NFC にしようかと思いましたが、 formD でも Windows と mac から繋いで問題ないと聞いたので formD にしておきました。
私は最近この件で苦労したのでformCにしたいのですが、そもそものwikiには改変しない方が良いと書いてあったので止めておきます。
そしてもう1つのディスクもzfsフォーマットします。こちらはオプションがすっきりしてます。
zpool create -o ashift=12 \
-O acltype=posixacl -O canmount=off \
-O dnodesize=auto -O normalization=formD -O relatime=on -O xattr=sa \
-O mountpoint=/ -R /mnt tank $DISK
作成したプール一覧の確認は下記。ここはコピペではなくて zpool list
と手打ちでお願いします。
# zpool list
NAME SIZE ALLOC FREE CKPOINT EXPANDSZ FRAG CAP DEDUP HEALTH ALTROOT
bpool 960M 540K 959M - - 0% 0% 1.00x ONLINE /mnt
tank 125G 648K 125G - - 0% 0% 1.00x ONLINE /mnt
システムのインストール
ディレクトリ構造に合わせたデータセット作成
ルート用データセットを作成します。
zfs create -o canmount=off -o mountpoint=none tank/main
zfs create -o canmount=noauto -o mountpoint=/ tank/main/ubuntu
zfs mount tank/main/ubuntu
ブート用データセットを作成します。
zfs create -o canmount=off -o mountpoint=none bpool/boot
zfs create -o canmount=noauto -o mountpoint=/boot bpool/boot/ubuntu
zfs mount bpool/boot/ubuntu
一般的なデータセットを作成します。
zfs create -o canmount=off tank/sub0
zfs create -o mountpoint=/home tank/sub0/home
zfs create -o mountpoint=/root tank/sub0/root
zfs create -o canmount=off tank/sub0/var
zfs create -o canmount=off tank/sub0/var/lib
zfs create -o mountpoint=/var/log tank/sub0/var/log
zfs create -o mountpoint=/var/spool tank/sub0/var/spool
zfs create -o mountpoint=/var/snap tank/sub0/var/snap
zfs create -o canmount=off tank/sub0/usr
zfs create -o mountpoint=/usr/local tank/sub0/usr/local
zfs create -o com.sun:auto-snapshot=false -o mountpoint=/var/lib/docker tank/sub0/var/lib/docker
debootstrap
debootstrap
ではなくてmmdebstrap
を使ってみようかと考えたのですが、残念ながら失敗しました。mdebstrap
ではインストール先ディレクトリが空でなければならないようです。
参考文献:第594回 mmdebstrapで最小のルートファイルシステムを作る - Ubuntu Weekly Recipe
そういう訳で、debootstrap
を入れてから Ubuntu 20.04 LTS 通称 focal をインストール。
apt install --yes debootstrap
debootstrap focal /mnt
終わったら以下のコマンドを実行します。
zfs set devices=off tank
システム設定
マシン名
まずはマシン名を決めます。
HOSTNAME=<マシン名>
echo $HOSTNAME >/mnt/etc/hostname
ネットワーク関連
hostsファイルを修正。
sed -i -e"/^127.0.0.1/a 127.0.1.1\t$HOSTNAME" /mnt/etc/hosts
netplan のネットワーク設定ファイル/mnt/etc/netplan/01-netcfg.yaml
を作成します。今回はIPv6は使わないようにするので下記のようにしてみました。
我が家のIPアドレス事情に基づき、ひとまずIPv4アドレスは固定で、172.16.5.10 とします。
参考文献:固定IPアドレスの割当(IPv4、IPv6) - Netplanの使い方 - komeの備忘録
cat > /mnt/etc/netplan/01-netcfg.yaml <<___
network:
version: 2
renderer: networkd
ethernets:
$(for d in `find /sys/devices -name net | grep -v virtual`; do ls $d; done | head -n1):
dhcp4: no
addresses: [172.16.5.10/16]
gateway4: 172.16.0.1
nameservers:
addresses: [172.16.0.1]
___
参考文献には/mnt/etc/apt/sources.list
の変更に言及がありますが、省略可との事ですし、今回は省略します。
chroot
Live CD 環境の仮想ファイルシステムをバインドマウントして、上記でセットアップした環境に chroot します( --bind ではなく --rbind を使っていることに注意)。
mount --rbind /dev /mnt/dev
mount --rbind /proc /mnt/proc
mount --rbind /sys /mnt/sys
chroot /mnt /usr/bin/env DISK=$DISK BOOTDISK=$BOOTDISK bash --login
chroot 環境内の apt のインデクスを更新します。
apt update
ロケール
en_US.UTF-8 と ja_JP.UTF-8 と、後は個人的な好みで。
locale-gen --purge en_US.UTF-8 ja_JP.UTF-8 ja_JP.EUC-JP
update-locale LANG=en_US.UTF-8 LANGUAGE=en_US
dpkg-reconfigure --frontend noninteractive locales
タイムゾーン
日本なら Asia/Tokyo です。
ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime
dpkg-reconfigure -f noninteractive tzdata
カーネルイメージなど
Linux のカーネルイメージと ZFS を chroot 環境にインストールします。
apt install --yes --no-install-recommends linux-image-generic zfs-initramfs
上記のコマンド実行の出力の最後に以下のようなメッセージが出ます。 update-initramfs
が/boot/initrd.img-5.4.0-26-generic
を生成したという点が重要だそうです。この後 grub のインストール時に必要になる為です。
update-initramfs: Generating /boot/initrd.img-5.4.0-26-generic
GRUB をレガシー BIOS 用にインストール
参考文献に従って以下のコマンドを実行。
DEBIAN_FRONTEND=noninteractive apt-get -y -o Dpkg::Options::="--force-confdef" -o Dpkg::Options::="--force-confold" install grub-pc
rootパスワード
パスワードを設定します。
passwd
zfsのzpool関係
bpool を確実にインポートするためのサービスのユニットファイルを作成します。
cat >/etc/systemd/system/zfs-import-bpool.service <<___
[Unit]
DefaultDependencies=no
Before=zfs-import-scan.service
Before=zfs-import-cache.service
[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/sbin/zpool import -N -o cachefile=none bpool
[Install]
WantedBy=zfs-import.target
___
このサービスの自動起動を有効にします。
systemctl enable zfs-import-bpool.service
tmpfs
次回起動時に tmpfs を /tmp にマウントするようにします。
cp /usr/share/systemd/tmp.mount /etc/systemd/system/
systemctl enable tmp.mount
GRUB のインストール
ZFS のブートファイルシステムが認識されていることを確認します。zfs
と出力されれば OK です。
grub-probe /boot
grub の設定ファイルを修正します。sed コマンドにすると少々複雑ですが。
sed -i -e '/^GRUB_TIMEOUT=/{s/=.*/=5/;a\
GRUB_RECORDFAIL_TIMEOUT=5
}
/^GRUB_CMDLINE_LINUX_DEFAULT=/s/quiet splash//
s|^GRUB_CMDLINE_LINUX=.*|GRUB_CMDLINE_LINUX="root=ZFS=tank/main/ubuntu"|
/^#GRUB_TERMINAL=console/s/#//
' /etc/default/grub
修正結果は下記の通り。
# If you change this file, run 'update-grub' afterwards to update
# /boot/grub/grub.cfg.
# For full documentation of the options in this file, see:
# info -f grub -n 'Simple configuration'
GRUB_DEFAULT=0
GRUB_TIMEOUT_STYLE=hidden
GRUB_TIMEOUT=5
GRUB_RECORDFAIL_TIMEOUT=5
GRUB_DISTRIBUTOR=`lsb_release -i -s 2> /dev/null || echo Debian`
GRUB_CMDLINE_LINUX_DEFAULT=""
GRUB_CMDLINE_LINUX="root=ZFS=tank/main/ubuntu"
# Uncomment to enable BadRAM filtering, modify to suit your needs
# This works with Linux (no patch required) and with any kernel that obtains
# the memory map information from GRUB (GNU Mach, kernel of FreeBSD ...)
#GRUB_BADRAM="0x01234567,0xfefefefe,0x89abcdef,0xefefefef"
# Uncomment to disable graphical terminal (grub-pc only)
GRUB_TERMINAL=console
# The resolution used on graphical terminal
# note that you can use only modes which your graphic card supports via VBE
# you can see them in real GRUB with the command `vbeinfo'
#GRUB_GFXMODE=640x480
# Uncomment if you don't want GRUB to pass "root=UUID=xxx" parameter to Linux
#GRUB_DISABLE_LINUX_UUID=true
# Uncomment to disable generation of recovery mode menu entries
#GRUB_DISABLE_RECOVERY="true"
# Uncomment to get a beep at grub start
#GRUB_INIT_TUNE="480 440 1"
この設定変更を反映します。
update-grub
が、この結果はエラーが発生します。osprober でbusyエラーが出ますが OK らしい。Found linux image と Found initrd image の行が出ていれば大丈夫との事。
# update-grub
Sourcing file `/etc/default/grub'
Sourcing file `/etc/default/grub.d/init-select.cfg'
Generating grub configuration file ...
Found linux image: vmlinuz-5.4.0-26-generic in rpool/ROOT/ubuntu
Found initrd image: initrd.img-5.4.0-26-generic in rpool/ROOT/ubuntu
device-mapper: reload ioctl on osprober-linux-sda3 failed: Device or resource busy
Command failed.
done
レガシー BIOS 用に GRUB をインストールします。
grub-install $BOOTDISK
ZFS のモジュールがインストールされていることを確認します。
ls /boot/grub/*/zfs.mod
初回のブート
スナップショット
初回インストールのスナップショットを作成しておきます。こういう事をしたいが為にZFSを使うのです。
zfs snapshot bpool/boot/ubuntu@$(date +%Y%m%d_%H%M%S)_install
zfs snapshot tank/main/ubuntu@$(date +%Y%m%d_%H%M%S)_install
zfs snapshot -r tank/sub0@$(date +%Y%m%d_%H%M%S)_install
スナップショットの一覧を表示して確認します。
zfs list -t snapshot
リブート
chroot 環境から抜けて Live CD 環境に戻ります。
exit
Live CD 環境でマウント中のファイルシステムを全てアンマウントします。
mount | grep -v zfs | tac | awk '/\/mnt/ {print $3}' | xargs -n 1 -r umount -lf
zpool export -a
そしてシャットダウン。
shutdown -h now
その後、インストールメディアを取り出して、それからマシンの電源を入れます。
rootログイン
ここからはsshは使えません。
サーバーのコンソールで root ユーザーでパスワードを入力してログインします。
日本語キーボード配列
記号を打ってみるとわかりますが、英語配列になっています。日本語配列に変更する手順は以下の参考文献を参照。バージョンは古いですが、画面キャプチャがあるのでわかりやすいです。
参考文献:Ubuntuでキーボードレイアウト変更 - Ragnite Blue
コマンドは下記。
dpkg-reconfigure keyboard-configuration
設定後、次のコマンドを打つ必要があるようです。
setupcon
スワップ
物理メモリを十分に積んでいてもスワップは重要だそうです。
容量(4G
の箇所)はマシンの状況に合わせて検討して下さい。
zfs create -V 4G -b $(getconf PAGESIZE) \
-o logbias=throughput -o sync=always \
-o primarycache=metadata -o secondarycache=none \
-o com.sun:auto-snapshot=false tank/swap
次にスワップを設定します。
mkswap -f /dev/zvol/tank/swap
echo /dev/zvol/tank/swap none swap discard 0 0 >> /etc/fstab
echo RESUME=none > /etc/initramfs-tools/conf.d/resume
スワップを有効にします。
swapon -av
有効になったかどうか確認。
swapon --show
フルのソフトウェアインストール
最小インストールをアップグレードします。
apt dist-upgrade -y
サーバ用としてコマンドライン環境のみをインストールします。
apt install -y ubuntu-standard
再起動して確認
reboot
まだ一般ユーザーが居ないので、rootでログインします。
そして色々確認。
- キーボードが日本の配列になっている事。アットマーク @ を打ってみて確認。
- スワップが有効になっている事。上述の
swapon --show
コマンドで確認。 - ネットワ-クが有効になっている事。仮想環境など状況によってNICの名称が変わる事があり、その場合は上述の設定
/etc/netplan/01-network.yaml
のNIC名eth0
を変更する必要があります。
ネットワークに関しては、次のようなコマンドを試してみればわかります。
※ example.com はドメインの例示の際に使うべしとRFC2606で定められています。何か適当なサーバーを選んで下さい。
ping -c2 example.com
失敗した場合には、上述のネットワーク設定ファイル/mnt/etc/netplan/01-netcfg.yaml
を修正します。その為のNIC名取得は下記のコマンドで。
参考文献:Linux から認識されている、すべてのネットワークインターフェイス名だけを取得する - Qiita
for d in `find /sys/devices -name net | grep -v virtual`; do ls $d; done
手打ちのコマンドとしてはip a
の方が簡単ですが、上記のコマンドならNIC名だけを取り出せますので自動化が可能です。
結び
これで本当に最小限の、起動するカーネルに毛が生えた程度のシステムになりました。ここから本当に必要なツールだけ1つずつ入れて育てていく予定です。
え?そんなのUbuntuじゃない?
良いんです。元々ArchLinuxの代わりとして選択したディストリビューションなので。
これでいいのだ