Closed19

Ubuntuをzfsルートにしたときのメモ

κeenκeen

ただのzfsルートだとUbuntu 24.04のインストーラでできるが、raidzもやろうとするとできない。

インストーラが複数メディアへのインストールを想定していないよう。

なのでOpenZFSのドキュメントを見ながら手動でUbuntuをインストールした。
Ubuntu 22.04 Root on ZFS — OpenZFS documentation
debootstrapから構築したのいつぶりだろう。

κeenκeen

基本的にはドキュメント通りにやっていけばよい。英文を読むとRAIDを組むときにコマンドをいじる部分が書いてある。自分はzfsのネイティブ暗号化で構築した。

成功すると↑のようにログインより前にディスクの暗号鍵を訊かれる

ただしブートシステムがlegacyかUEFIか、シングルディスクかマルチディスクかで選択になるコマンドを間違って叩くと破滅する(一敗)。
どれがクリティカルだったのか分からないが、ミスって実行したのは2つ。

1つは /boot もraidに入れてるのにシングルディスク向けのコマンドを叩いてしまった点

mkdir /boot/efi/grub /boot/grub
echo /boot/efi/grub /boot/grub none defaults,bind 0 0 >> /etc/fstab
mount /boot/grub

もう1つはUEFIにしたいのにlegacyのコマンドを叩いてしまった点。

apt install --yes grub-pc linux-image-generic zfs-initramfs zsys

どっちも元に戻したつもりだったが再起動したら動かなかった。多分grub-pcをインストールするときにMBRを書き換えてしまったとかそういう系だと思う。

κeenκeen

あ、あと手順の中で再起動するときにファイルシステムをアンマウントするコマンドが動かなかった

mount | grep -v zfs | tac | awk '/\/mnt/ {print $3}' | \
    xargs -i{} umount -lf {}
zpool export -a

exportでrpoolがbusyって言われる。シェルのカレントディレクトリが/mnt/に入ってて使用中判定されたかなと思ったけどそれでもなかった。
よくわからないのでそのまま再起動したらinitramfsに落ちた。exportできてないのでimportできなかったらしい。強制importが必要。initramfsでもzpoolが使えるので zpool import -alf かそんな感じのコマンドを叩いたら直った。

κeenκeen

ほかにハマった点だとネットワークの設定が上手くいかずに再起動後にaptをインストールできなかった。
仕方ないのでインストールメディアからchrootで入って作業した。その状態でubuntu-desktopさえ入れてしまえばNetworkManagerが入るのでネットワーク設定しなくても自動で管理してくれる。

でもインストールメディアからchrootで入るとDNSが解決できなかったので困った。一旦chrootする前にpingなどでarchive.ubuntu.comのIPアドレスを確かめてから/etc/apt/souces.list.d/ubuntu.sourcesの中の archive.ubuntu.comをIPアドレスに置換した。IPv6はURLでは http://[..]/... のように[]で囲んで書く。そうしないとアドレス中の : がポート番号(など)の指定と区別がつかない。

κeenκeen

で、btrfsでやってたバックアップの仕組みをzfsでも再現しようとして調べ物をした。
やっていたのは2つ。

  • 1時間ごとにスナップショットをとる
  • 1週間ごとに最新のスナップショットからtarを作って~/Dropboxに放り込む

これができるかを調べた。

κeenκeen

後者はスナップショットの中身がファイルシステムとして見えればあとはどうにかなる。
で、実際にそれはできる。
https://docs.oracle.com/cd/E23824_01/html/821-1448/gbciq.html

一旦ホームディレクトリのdatasetに対してlistsnapshotsをonにしておく。

zpool set listsnapshots=on rpool/USERDATA/name_UUID

すると ~/.zfs からアクセスできるようになる。

$ ls ~/.zfs
shares  snapshot
$ ls ~/.zfs/snapshot
autozsys_0d9if2  autozsys_65gxqu  autozsys_blltdr  autozsys_itlpj1  autozsys_mbrnwy  autozsys_t1o84s  autozsys_ys2zk3  test
autozsys_38ce9m  autozsys_8030et  autozsys_f4jwq4  autozsys_ivitc6  autozsys_mqoe9w  autozsys_ulzf75  autozsys_zfpc9b
autozsys_3qv38f  autozsys_aavh0k  autozsys_f8vell  autozsys_jsun4n  autozsys_oq1m7f  autozsys_vaj3ma  autozsys_zqa5ba
autozsys_55tp0o  autozsys_b61cav  autozsys_i31d62  autozsys_len7sx  autozsys_p8r8dm  autozsys_wuvhse  autozsys_zt5hxj

この autozsys_xxx とついているのがスナップショットの名前で、さらにこの中を ls するとスナップショットをとったときのツリーがそのまま見える。これにて後者は解決。

不思議なことに ls にはこの .zfs はでてこない。まあ、出てきても困るんだけど、同名ディレクトリとか作ったらどうなるんだろうね。

$ ls -a ~/ | grep zfs
$
κeenκeen

で、↑で出てきた autozsys_xxx なんだけど、そもそもUbuntu側で勝手にスナップショットを撮ってるみたい。zsysという仕組み。
https://github.com/ubuntu/zsys

システムディレクトリに関してはブートに成功したりaptとかでシステムに変更を加えたりのタイミングで、ユーザデータに関しては1時間ごとにスナップショットを撮っている。

この仕組みはsystemdのタイマーで設定されている。

$ systemctl --user list-timers zsys-user-savestate
NEXT                        LEFT LAST                           PASSED UNIT                      ACTIVATES
Sun 2024-04-28 10:08:11 JST  32s Sun 2024-04-28 09:08:10 JST 59min ago zsys-user-savestate.timer zsys-user-savestate.service

1 timers listed.
Pass --all to see loaded but inactive timers, too.
$ ls /etc/systemd/user/timers.target.wants
launchpadlib-cache-clean.timer  zsys-user-savestate.timer
/usr/lib/systemd/user/zsys-user-savestate.service
[Unit]
Description=Save current user state periodically

# We can't run it in a container
ConditionVirtualization=!container

[Service]
Type=oneshot
ExecStart=/sbin/zsysctl state save
/etc/systemd/user/timers.target.wants/zsys-user-savestate.timer
[Unit]
Description=Save current user state periodically
ConditionUser=!@system

[Timer]
OnStartupSec=1min
OnUnitActiveSec=1h

[Install]
WantedBy=timers.targe
κeenκeen

そしてzsysの設定ファイルはデフォルトでは存在しない。バイナリにこの設定が埋め込まれている。

https://github.com/ubuntu/zsys/blob/dfe2f0482c69670683fa34a4a1525b1699b4460a/internal/config/zsys.conf

設定を変えたかったらコピペして /etc/zsys.conf に置いていじることになるが、デフォルト設定が変わったときの挙動とかで影響受けそうだし明示的に置いといてほしかったなという思いも。

κeenκeen

とりあえず、1時間ごとにスナップショットをとる仕組みは存在するので考えることは減った。

あとは

  • 最新のスナップショットを取得したい
  • ~/Dropbox はzsysに管理してほしくない

をやっていきたい。前者はなんか頑張ればできそう。
後者はzsysの仕組みの理解が必要。

κeenκeen

zsysは解説ブログがある。↓の記事から始まる一連の記事。
https://didrocks.fr/2020/06/04/zfs-focus-on-ubuntu-20.04-lts-zsys-state-collection/

その中でもこの記事が多分欲しかった情報。

https://didrocks.fr/2020/06/16/zfs-focus-on-ubuntu-20.04-lts-zsys-dataset-layout/

ROOT BOOT USERDATA下にあるデータセットはzsysが管理するので、管理から外したければそれ以外に置けばいい。記事中でPersistent datasetsと呼ばれているもの。

今まだDropboxが同期中で作業できないので後で試す。

κeenκeen

creationが日本語で表示されるのはロケールの問題なんだろうと思ったけど LANG=C でも日本語だった。多分これ値を入れる時点で日本語で入れてるな

$ LANG=C zfs get creation rpool/USERDATA/shun_wfj4mu@autozsys_0d9if2
NAME                                        PROPERTY  VALUE                    SOURCE
rpool/USERDATA/shun_wfj4mu@autozsys_0d9if2  creation  日  4月 28  2:12 2024  -
κeenκeen

いや、さすがにそんなことなかった。zfs getに-pつけると数値で出してくれた

$ zfs get -p creation rpool/USERDATA/shun_wfj4mu@autozsys_0d9if2
NAME                                        PROPERTY  VALUE                    SOURCE
rpool/USERDATA/shun_wfj4mu@autozsys_0d9if2  creation  1714237933               -
κeenκeen

zfs list-S を渡すとその値でソートしてくれるからそれ使えば最新のを取得はできそう。

$ zfs list -S creation -o name | grep -m1 "rpool/USERDATA/${USER}_.*@autozsys_.*"
rpool/USERDATA/shun_wfj4mu@autozsys_gcfdtp
κeenκeen

Dropboxの同期が終わったのでデータセットを別のものにしてみた。
これを先にやってからDropboxの同期すればよかったな。

最初にこれをやったら思ったとおりにならなかった。

$ sudo zfs create -p -ocanmount=off rpool/home/shun/Dropbox
$ sudo zfs set canmount=on rpool/home/shun/Dropbox

/home/shunrpool/home/shunrpool/USERDATA/shun 両方がマウントしようとしてしまうし、 rpool/home/shun/Dropboxrpool/home/shun にしかマウントしなかった。 ``rpool/home/shun` はcanmount=offのはずなんだけどなあ。結局上で作ったやつは全部destroyして以下で作り直した。

$ sudo zfs create -omountpoint=/home/shun/Dropbox rpool/home-shun-Dropbox

既にディレクトリがある状態なのでちょっと怪しいかも

$ mv Dropbox Dropbox.bk

したあとに新しく作った Dropbox のマウントポイントが生えてきた。

そのあとは mv した。

$ mv Dropbox.bk/* Dropbox

autozsysのスナップショットのせいでディスクスペースが足りなくなったので先にスナップショットは削除しといた方がいい。
ディスクスペースで詰まったあとはmv先にディレクトリがあったりしてmvできなくなるのでrsyncを使った。

$ rsync -r --remove-source-files --verbose -p  ./Dropbox2/ Dropbox/

ただ、これだとmtimeとかが上書きされてしまうので -a オプションをつけるべきだった。

κeenκeen

最後、この記事の内容をzfsに移植する。
https://keens.github.io/blog/2022/04/30/tarwotsukattabakkuappuwomaishuutoru/

最新のスナップショットからtarを作るというは骨子は変わらないのでそこまで変更はない。

#!/bin/sh
# templated by http://qiita.com/blackenedgold/items/c9e60e089974392878c8
usage() {
    cat <<HELP
NAME:
   $0 -- backup home

SYNOPSIS:
  $0 [-h|--help]
  $0 [--verbose]

DESCRIPTION:
   Backup home from the latest snapshot. It logs to $LOG_FILE

  -h  --help      Print this help.
      --verbose   Enables verbose mode.
HELP
}

main() {
    SCRIPT_DIR="$(cd $(dirname "$0"); pwd)"

    while [ $# -gt 0 ]; do
        case "$1" in
            --help) usage; exit 0;;
            --verbose) set -x; shift;;
            --) shift; break;;
            -*)
                OPTIND=1
                while getopts h OPT "$1"; do
                    case "$OPT" in
                        h) usage; exit 0;;
                    esac
                done
                shift
                ;;
            *) break;;
        esac
    done

    NAME=shun
    mv -f /home/${NAME}/Dropbox/backup/home.tar.xz /home/${NAME}/Dropbox/backup/home.old.tar.xz
    mv -f /home/${NAME}/Dropbox/backup/home.tar.xz.sha1 /home/${NAME}/Dropbox/backup/home.old.tar.xz.sha1
    chown -f ${NAME}:${NAME} /home/${NAME}/Dropbox/backup/home.old.tar.xz /home/${NAME}/Dropbox/backup/home.old.tar.xz.sha1
    latest_snapshot="$(zfs list -S creation -o name | grep -m1 "rpool/USERDATA/${NAME}_.*@autozsys_.*" | grep -o 'autozsys.*')"
    nice tar cvf /home/${NAME}/Dropbox/backup/home.tar.xz \
        --sparse \
        --use-compress-prog=pixz  \
        -p --xattrs \
        --exclude=./Dropbox \
        --exclude=./.cache \
        -C "/home/${NAME}/.zfs/snapshot/$latest_snapshot/" \
        .
    sha1sum /home/${NAME}/Dropbox/backup/home.tar.xz > /home/${NAME}/Dropbox/backup/home.tar.xz.sha1
    chown ${NAME}:${NAME} /home/${NAME}/Dropbox/backup/home.tar.xz /home/${NAME}/Dropbox/backup/home.tar.xz.sha1
}
set -e
export PATH=/usr/bin:/usr/sbin
LOG_FILE=/var/log/backup-home.log
start_time="$(date +%s)"
main "$@" 2>&1 > $LOG_FILE
end_time="$(date +%s)"
echo "$(($end_time - $start_time)) seconds" >> $LOG_FILE

あとはlogrotateも書く。zfsを作るときにcompressionをonにしているのでcompressはつけない。

/var/log/backup-home.log {
        weekly
        missingok
        rotate 7
        notifempty
        copytruncate
}
κeenκeen

ところで前まで気付いてなくてやられたんだけど、tarのexcludeは部分一致っぽい。

こういうディレクトリを用意して、

$ tree -a dir
dir
├── .cache
├── hoge
│   └── .cache
└── test

dir/.cache を除外するつもりで --exclude=.cache と書いていた。しかしこれだと hoge/.cache まで除外されてしまう。

$ tar cvf dir.tar --exclude=.cache -C dir .
./
./hoge/
./test

正しくは ./.cache だった。

$ tar cvf dir.tar --exclude=./.cache -C dir .
./
./hoge/
./hoge/.cache
./test
κeenκeen

ところでzfsにしてからやたらメモリ使用量が多い。

slabtop -sc でトップに zfs_znode_cache が上にくるから恐らくzfsのキャッシュのせいだろう。

κeenκeen

多分これでトピックは終わりかな。次あるとしたらPC移行時だろうけど、そのときはまた別スクラップを作ろう。

このスクラップは21日前にクローズされました