この記事は何か
Ubuntu 18.04.2のrootをZFS+LUKS上に構築した実録である。
ZFSに至るまで
個人的に最近Linux熱が高まっているのだが、筆者の萌えポイントはZFSである。Solarisに実装された時には非常に興奮したことを覚えているが、当時悩んだ末に、グラフィック性能が必要だったため結局SUNではなくSilicon GraphicsのIndigoを購入した。
そんなわけでZFSを利用する機会は失ったのだが、つい最近、LinuxのカーネルモジュールとしてZFSが使えるようになっていることを知った。
参考にした記事
この記事は以下のドキュメントを参考に筆者が実際にノートPCにインストールした実録記事である。タイトルにあるとおりroot、すなわちシステム全体をZFSに乗せることを目的としている。
またLUKS(Linux Unified Key Setup)を組み合わせてファイルシステムを暗号化している。
上記記事は英語である上に非暗号化、暗号化の両方について説明しているので、ストレートに暗号化ZFSのHOWTOが、それも日本語で必要な人に参考としてもらえればありがたい。
環境及び前提条件
この記事は全てのPCへのインストール方法を記述したものでは無い。筆者の環境及びインストール要件、前提とした条件を整理する。
インストール環境
インストールした環境は以下のようなものである。
Item | Configuration |
---|---|
PC | Let's note CF-SZ6 |
CPU | Intel Core™ i5-7300U vPro™ 2.60GHz |
Memory | 8GB LPDDR3 SDRAM |
Disk | 256GB SSD |
System Software | UEFI |
OS | Ubuntu 18.04.2 LTS Desktop |
Encryption | LUKS |
インストールの前提条件
- ディスク(SSD)全体をZFSでフォーマットする。デュアルブートは一切考慮していない。
- ディスクは1台でミラーリングやRAIDZは考慮していない。
- 起動OSはUbuntuのDesktop版を用いる。Server版ではないので注意のこと。
暗号化について
オリジナルのZFSはそれ自体に暗号化機能を含んでいるが、Linux版はまだ暗号化機能は実装途中で正式版としてはリリースされていない。
このため本記事ではLinuxで広く用いられているLUKSを利用してディスク全体を暗号化した。このチュートリアルでは、ブートローダー、カーネル、initrd以外の全て、すなわちOS、スワップ、ホームディレクトリなど全てを暗号化する。
なおLUKSでは起動時に復号のためのパスワードを求められるため、コンソールを操作できないリモート環境では利用できない。
インストール手順
インストール環境の準備
1.1. UbuntuのLiveイメージからブートする。筆者はUSBメモリにインストールしたイメージから起動した。メニューが現れたらインストールではなくTry Ubuntuを選択する。デスクトップが起動したらCtrl-Alt-Tを押下してターミナルを開く。
1.2. リポジトリを設定する。
$ sudo apt-add-repository universe
$ sudo apt update
1.3. 他の端末からインストール操作を行うためSSHのインストールを行う。
$ passwd
$ sudo apt install --yes openssh-server
コンソールで# ip a | grep inet
としてIPアドレスを調べ、他の端末から# ssh ubuntu@IPADDRESS
で接続する。
1.4. ルートになってLive環境にZFS関連のツールのインストールを行う。
$ sudo -i
# apt install --yes debootstrap gdisk zfs-initramfs
ディスクのフォーマット
2.1. ディスクが再利用の場合には既存のパーティションを削除しておく。
# sgdisk --zap-all /dev/sda
2.2. ディスクのUUIDを調べ、環境変数にセットする。
# ls -la /dev/disk/by-id | grep sda
# export DISK=ata-SAMSUNG_MZNLN256HMHQ-XXXXXX
2.3. パーティションを切る。
# sgdisk -n2:1M:+512M -t2:EF00 /dev/disk/by-id/$DISK
# sgdisk -n3:0:+512M -t3:BF01 /dev/disk/by-id/$DISK
# sgdisk -n4:0:0 -t4:8300 /dev/disk/by-id/$DISK
2.4. boot用のプールを作成する。
# zpool create -f -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@lz4_compress=enabled \
-o feature@spacemap_histogram=enabled \
-o feature@userobj_accounting=enabled \
-O acltype=posixacl -O canmount=off -O compression=lz4 -O devices=off \
-O normalization=formD -O relatime=on -O xattr=sa \
-O mountpoint=/ -R /mnt \
bpool /dev/disk/by-id/$DISK-part3
2.5. root用のプールを作成する。
# cryptsetup luksFormat -c aes-xts-plain64 -s 256 -h sha256 \
/dev/disk/by-id/$DISK-part4
# cryptsetup luksOpen /dev/disk/by-id/$DISK-part4 luks1
# zpool create -o ashift=12 \
-O acltype=posixacl -O canmount=off -O compression=lz4 \
-O dnodesize=auto -O normalization=formD -O relatime=on -O xattr=sa \
-O mountpoint=/ -R /mnt \
rpool /dev/mapper/luks1
システムのインストール
3.1. コンテナとなるデータセットを作成する。
# zfs create -o canmount=off -o mountpoint=none rpool/ROOT
# zfs create -o canmount=off -o mountpoint=none bpool/BOOT
3.2. ルートとブートファイルシステムのためのデータセットを作成する。
# zfs create -o canmount=noauto -o mountpoint=/ rpool/ROOT/ubuntu
# zfs mount rpool/ROOT/ubuntu
# zfs create -o canmount=noauto -o mountpoint=/boot bpool/BOOT/ubuntu
# zfs mount bpool/BOOT/ubuntu
3.3. 各ディレクトリ用のデータセットを作成する。
# zfs create rpool/home
# zfs create -o mountpoint=/root rpool/home/root
# zfs create -o canmount=off rpool/var
# zfs create -o canmount=off rpool/var/lib
# zfs create rpool/var/log
# zfs create rpool/var/spool
スナップショット作成から除外するデータセットの作成。
# zfs create -o com.sun:auto-snapshot=false rpool/var/cache
# zfs create -o com.sun:auto-snapshot=false rpool/var/tmp
# chmod 1777 /mnt/var/tmp
3.4. 最小システムをインストールする。
# debootstrap bionic /mnt
# zfs set devices=off rpool
システムの設定
4.1. ホストネームを設定する。HOSTNAME、FQDNはそれぞれホストネーム、ドメインネームとする。
# echo $HOSTNAME > /mnt/etc/hostname
# echo "127.0.1.1 $FQDN $HOSTNAME" >> /mnt/etc/hosts
4.2. ネットワークインタフェースの設定を行う。# ip a
としてインタフェース名を調べる。以下、INTERFACEは調べたインタフェース名とする。
# nano /etc/netplan/01-netcfg.yaml
network:
version: 2
ethernets:
$INTERFACE:
dhcp4: true
4.3. パッケージ取得のソースリストを設定する。
# nano /mnt/etc/apt/sources.list
deb http://archive.ubuntu.com/ubuntu bionic main universe
deb-src http://archive.ubuntu.com/ubuntu bionic main universe
deb http://security.ubuntu.com/ubuntu bionic-security main universe
deb-src http://security.ubuntu.com/ubuntu bionic-security main universe
deb http://archive.ubuntu.com/ubuntu bionic-updates main universe
deb-src http://archive.ubuntu.com/ubuntu bionic-updates main universe
4.4. ライブ環境から新しいシステムの環境へ移行する。
# mount --rbind /dev /mnt/dev
# mount --rbind /proc /mnt/proc
# mount --rbind /sys /mnt/sys
# chroot /mnt /bin/bash --login
4.5. 基本的な環境を設定する。
# ln -s /proc/self/mounts /etc/mtab
# apt update
# dpkg-reconfigure locales
# dpkg-reconfigure tzdata
日本語ロケールを選択するにしても、必ずen_US.UTF-8
も選択する。
viは辛いのでnanoをインストールしておいた。
# apt install --yes nano
4.6. chrootした新しい環境にZFS関連のツールをインストールする。
# apt install --yes --no-install-recommends linux-image-generic
# apt install --yes zfs-initramfs
4.7. LUKSのセットアップを行う。
# apt install --yes cryptsetup
# echo luks1 UUID=$(blkid -s UUID -o value \
/dev/disk/by-id/$DISK-part4) none \
luks,discard,initramfs > /etc/crypttab
4.8. ブートローダーをインストールする。
# apt install dosfstools
# mkdosfs -F 32 -s 1 -n EFI /dev/disk/by-id/$DISK-part2
# mkdir /boot/efi
# echo PARTUUID=$(blkid -s PARTUUID -o value \
/dev/disk/by-id/$DISK-part2) \
/boot/efi vfat nofail,x-systemd.device-timeout=1 0 1 >> /etc/fstab
# mount /boot/efi
# apt install --yes grub-efi-amd64-signed shim-signed
4.9. ルートパスワードを設定する。
passwd
4.10. bpoolが常に読み込まれることを確実にする。
# cat >> /etc/systemd/system/zfs-import-bpool.service << EOF
[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
EOF
# systemctl enable zfs-import-bpool.service
4.11. tmpfs(RAMファイルシステム)を/tmpにマウントする。
# cp /usr/share/systemd/tmp.mount /etc/systemd/system/
# systemctl enable tmp.mount
ブートローダーのインストール
5.1. ZFSがブートシステムとして認識されていることを確認する。
# grub-probe /boot
zfs
5.2. initrdファイルをリフレッシュする。
# update-initramfs -u -k all
このときWARNINGがでるが、気にしなくて良い。
5.3. デバッグしやすくするためにGRUBの設定を変更する。
Set: GRUB_CMDLINE_LINUX="root=ZFS=rpool/ROOT/ubuntu"
Comment out: GRUB_TIMEOUT_STYLE=hidden
Set: GRUB_TIMEOUT=5
Below GRUB_TIMEOUT, add: GRUB_RECORDFAIL_TIMEOUT=5
Remove quiet and splash from: GRUB_CMDLINE_LINUX_DEFAULT
Uncomment: GRUB_TERMINAL=console
5.4. GRUBの設定をアップデートする。
# update-grub
5.5. GRUBをインストールする。
# grub-install --target=x86_64-efi --efi-directory=/boot/efi \
--bootloader-id=ubuntu --recheck --no-floppy
5.6. ZFSモジュールがインストールされていることを確認する。
ls /boot/grub/*/zfs.mod
5.7. ファイルシステムのマウント順序を修正する。
# umount /boot/efi
# zfs set mountpoint=legacy bpool/BOOT/ubuntu
# echo bpool/BOOT/ubuntu /boot zfs \
nodev,relatime,x-systemd.requires=zfs-import-bpool.service 0 0 >> /etc/fstab
# zfs set mountpoint=legacy rpool/var/log
# echo rpool/var/log /var/log zfs nodev,relatime 0 0 >> /etc/fstab
# zfs set mountpoint=legacy rpool/var/spool
# echo rpool/var/spool /var/spool zfs nodev,relatime 0 0 >> /etc/fstab
# zfs set mountpoint=legacy rpool/var/tmp
# echo rpool/tmp /tmp zfs nodev,relatime 0 0 >> /etc/fstab
最初の起動
6.1. これまでの状態のスナップショットを取っておく。
# zfs snapshot bpool/BOOT/ubuntu@install
# zfs snapshot rpool/ROOT/ubuntu@install
6.2. chroot環境から抜ける。
# exit
6.3. 全てのファイルシステムをアンマウントする。
# mount | grep -v zfs | tac | awk '/\/mnt/ {print $3}' | xargs -i{} umount -lf {}
# zpool export -a
6.4. リブート!
# reboot
A dependency job for reboot.target failed. See 'journalctl -xe' for details.
ところが筆者の環境では上のようなメッセージが表示されリブートが止まってしまった。journalctl -xe
で詳細を見てもよくわからなかったので、電源長押しで強制的にシャットダウンを行ったが何事もなくブートしてくれた。
6.5. LUKSのパスワードを入力して起動後、rootでログインする。
6.6. ユーザーアカウントを作成する。$YOURUSERNAMEはアカウント名である。
# zfs create rpool/home/$YOURUSERNAME
# adduser $YOURUSERNAME
# cp -a /etc/skel/.[!.]* /home/$YOURUSERNAME
# chown -R $YOURUSERNAME:$YOURUSERNAME /home/$YOURUSERNAME
6.7. アカウントを管理者グループに追加する。グループはお好みで。
# usermod -a -G adm,cdrom,dip,lpadmin,plugdev,sambashare,sudo YOURUSERNAME
スワップの設定
7.1. スワップのためのデータセットを作成する。
# zfs create -V 4G -b $(getconf PAGESIZE) -o compression=zle \
-o logbias=throughput -o sync=always \
-o primarycache=metadata -o secondarycache=none \
-o com.sun:auto-snapshot=false rpool/swap
7.2. スワップを設定する。
# mkswap -f /dev/zvol/rpool/swap
# echo /dev/zvol/rpool/swap none swap defaults 0 0 >> /etc/fstab
# echo RESUME=none > /etc/initramfs-tools/conf.d/resume
7.3. スワップを有効化する。
# swapon -av
7.4. 設定したZFSはファイルシステムそのものが圧縮を行っているため、logrotateが圧縮を行わないように設定する。
# for file in /etc/logrotate.d/* ; do
if grep -Eq "(^|[^#y])compress" "$file" ; then
sed -i -r "s/(^|[^#y])(compress)/\1#\2/" "$file"
fi
done
7.5. リブートする。
# reboot
最後のクリーンアップ
8.1. インストール時に作成したスナップショットを削除する。
$ sudo zfs destroy bpool/BOOT/ubuntu@install
$ sudo zfs destroy rpool/ROOT/ubuntu@install
8.2. rootのパスワードを無効化する。
sudo usermod -p '*' root
8.3. GRUBのグラフィカルインタフェースを有効にする。
$ sudo nano /etc/default/grub
Uncomment: GRUB_TIMEOUT_STYLE=hidden
Add quiet and splash to: GRUB_CMDLINE_LINUX_DEFAULT
Comment out: GRUB_TERMINAL=console
Save and quit.
$ sudo update-grub
おわりに
とても長い道のりだったがこれで最小構成のubuntu on ZFSがインストールできたことになる。あとはサーバー系のソフトウェアを入れるなり、デスクトップ環境を構築するなり、各自でカスタマイズして欲しい。