2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

自宅サーバー構築譚:Ubuntu 22.04 LTS on ZFS in デスクトップパソコン(BIOS,MBR)

Last updated at Posted at 2022-12-28

能書き

自宅サーバー構築譚:基本構想に基づく自宅サーバー構築の続き。

以前の記事で Ubuntu 20.04 LTS をZFSにインストールする手順を確立しました。それがあるので Ubuntu 22.04 LTS は見送ろうと考えていたんですが、zfsのバージョンが2.1.3だとの事なので、インストールに踏み切る事にしました。 Ubuntu 20.04 LTS のzfsは0.8.3なので、流石にバージョンが違い過ぎます。

参考文献

参考文献1:自宅サーバー構築譚:Ubuntu on ZFS in デスクトップパソコン(BIOS,MBR)
参考文献2:Ubuntu 22.04 Root on ZFS - OpenZFS Documentation - OpenZFS

インストール環境の整備

ハードウェアの仕様は昔書いた記事の通りです。将来的にはこれをセカンダリサーバにする予定ですが、今回はプライマリサーバとして構築します。

ちなみに暗号化はしない方針です。家庭用なので。

デスクトップインストーラーを起動しsshの環境整備

サーバーをインストールする場合でもデスクトップ版のisoを使用します。Ubuntuのサイトからダウンロードして、USBメモリに焼きます。
私は普段使いのWin10マシンでRufusというツールを使ってみましたが、ここはお好みでどうぞ。

このUSBメモリをインストール対象マシンに挿入して、ここから起動。

GUI インストーラーが立ち上がって Welcome という画面が表示されたら、 TAB キーを押して Try Ubuntu ボタンにフォーカスを移動して(ボタンにオレンジの枠がつきます) Enter キーを押します。

ウィンドウ環境に切り替わったらターミナルを起動しますが、マウスが繋がっていない場合はショートカットキー Ctrl+Alt+T でどうぞ。

主な作業はsshで接続して行いたいので、そのように準備します。sshで接続するのはコマンドをコピペできるから。私もやってみてわかりました。これ良いですな。

ターミナルで下記のコマンドを実行。

sudo apt update

OpenSSHサーバーと、フルのvimをインストール。

sudo apt install --yes openssh-server vim

ssh接続用にユーザー ubuntu のパスワードを設定。

passwd

ssh接続先のIPアドレスを確認します。

ip a

別のマシンから対象のサーバーに ssh してインストール作業を続行

ssh はほとんどのOSで利用可能でしょう。Windows10でもコマンドプロンプトからsshコマンドを実行できます。

ssh ubuntu@接続先のIPアドレス

インストール作業を同じマシンでやり直してたりすると、ここでエラーが出る事があります。そんな時には .ssh\known_hosts を削除してから、sshコマンドを実行します。

del %USERPROFILE%\.ssh\known_hosts

rootユーザーになります。

sudo -i

debootstrapとZFSを Live CD 環境にインストールします。

apt install --yes debootstrap zfsutils-linux
systemctl stop zed

ディスクのフォーマット

起動用のUSBメモリを挿します。ここにブートローダを仕込んで常時付けっ放しにしておく予定。

そのUSBメモリを含めたフォーマット対象ディスクを確認します。

lsblk

今回は下記のように表示されます。

root@ubuntu:~# lsblk
NAME   MAJ:MIN RM    SIZE RO TYPE MOUNTPOINT
loop0    7:0    0    2.1G  1 loop /rofs
loop1    7:1    0     62M  1 loop /snap/core20/1587
loop2    7:2    0   91.7M  1 loop /snap/gtk-common-themes/1535
loop3    7:3    0   45.9M  1 loop /snap/snap-store/582
loop4    7:4    0  163.3M  1 loop /snap/firefox/1635
loop5    7:5    0  400.8M  1 loop /snap/gnome-3-38-2004/112
loop6    7:6    0     47M  1 loop /snap/snapd/16292
loop7    7:7    0    284K  1 loop /snap/snapd-desktop-integration/14
loop8    7:8    0      4K  1 loop /snap/bare/5
sda      8:0    0  465.8G  0 disk
├─sda1   8:1    0  465.8G  0 part
└─sda9   8:9    0      8M  0 part
sdb      8:16   0  465.8G  0 disk
├─sdb1   8:17   0  465.8G  0 part
└─sdb9   8:25   0      8M  0 part
sdc      8:32   1   58.2G  0 disk
└─sdc1   8:33   1   58.2G  0 part /cdrom
sdd      8:48   1   14.7G  0 disk
├─sdd1   8:49   1      1G  0 part
└─sdd2   8:50   1   13.7G  0 part
sr0     11:0    1   1024M  0 rom

loop0loop8はインストーラによる設定でしょうか。
sdasdbが内蔵HDDで、以前入れたUbuntuが残っています。
sdcが今回のUbuntuインストーラでしょう。
sddはブートローダを仕込む為のUSBメモリです。
sr0はCR-ROMドライブと思われますが、今回は無関係です。

ディスクの指定にはIDを使います。

ls -l /dev/disk/by-id

これを変数に設定するのがubuntu流らしいですが、ここは私の流儀で取得する事にします。

BOOTDISK=$(cd /dev/disk/by-id; ls ata-* usb-* | while read d; do if [ "$(readlink -f $d)" = "/dev/sdd" ]; then echo "/dev/disk/by-id/$d"; fi; done)
DISK1=$(cd /dev/disk/by-id; ls ata-* usb-* | while read d; do if [ "$(readlink -f $d)" = "/dev/sda" ]; then echo "/dev/disk/by-id/$d"; fi; done)
DISK2=$(cd /dev/disk/by-id; ls ata-* usb-* | while read d; do if [ "$(readlink -f $d)" = "/dev/sdb" ]; then echo "/dev/disk/by-id/$d"; fi; done)

スワップパーティションが使用されていない事を確認します。

swapoff --all

ブート用USBメモリのパーティションを全削除します。

wipefs -a $BOOTDISK

ブート用USBメモリにパーティションを作成。GPTではなくてMBRにします。

sfdisk $BOOTDISK <<___
,1G,bf
,
___

設定を確認するコマンドは下記になります。

sfdisk -l $BOOTDISK

$DISK1$DISK2はパーティションに分けません。

wipefs -a $DISK1 $DISK2

スワップについて。
参考文献によると、zvolにスワップを置くとデッドロックの危険性があるので非推奨だそうです。バグレポートが上がっているらしい。と言う訳でスワップは無効にします。本当は有効にした方が、メモリ管理の都合上、良いらしいですが。諦めます。

いよいよzfsフォーマットします。ここが今回最大のコピペポイント!これをコピペする為にssh経由で接続していると言っても過言ではありません。

因みにこのzpool名はbpool固定らしい。変更したい場合はupdate-grub後に/etc/grub.d/10_linux_zfsを修正すればいいらしいのですが、試していません。

※なおインストール2回目以降でエラーが出る際には、コマンドの末尾かどこかに -f オプションを付加します。

zpool create \
    -o ashift=12 \
    -o autotrim=on \
    -o cachefile=/etc/zfs/zpool.cache \
    -o compatibility=grub2 \
    -o feature@livelist=enabled \
    -o feature@zpool_checkpoint=enabled \
    -O devices=off \
    -O acltype=posixacl -O xattr=sa \
    -O compression=lz4 \
    -O normalization=formD \
    -O relatime=on \
    -O canmount=off -O mountpoint=/boot -R /mnt \
    bpool ${BOOTDISK}-part1

エラー「not in specified 'compatibility' feature set.」(指定された「互換性」機能セットにない)は無視します。

そして内蔵HDDもzfsフォーマットします。2つ1組のHDDをミラーリングに設定します。

こちらのzpool名は何でも良いそうです。zfsの伝統に則ってtankにしてみました。

zpool create \
    -o ashift=12 \
    -o autotrim=on \
    -O acltype=posixacl \
    -O xattr=sa -O dnodesize=auto \
    -O compression=lz4 \
    -O normalization=formD \
    -O relatime=on \
    -O canmount=off -O mountpoint=/ -R /mnt \
    tank mirror ${DISK1} ${DISK2}

作成したプール一覧の確認は下記。このコマンドはコピペではなくて zpool list zpool statusと手打ちでお願いします。別に良いよねこの位は。

root@ubuntu:~# zpool list
NAME    SIZE  ALLOC   FREE  CKPOINT  EXPANDSZ   FRAG    CAP  DEDUP    HEALTH  ALTROOT
bpool   960M   576K   959M        -         -     0%     0%  1.00x    ONLINE  /mnt
tank    464G   480K   464G        -         -     0%     0%  1.00x    ONLINE  /mnt
root@ubuntu:~# zpool status
  pool: bpool
 state: ONLINE
status: One or more features are enabled on the pool despite not being
        requested by the 'compatibility' property.
action: Consider setting 'compatibility' to an appropriate value, or
        adding needed features to the relevant file in
        /etc/zfs/compatibility.d or /usr/share/zfs/compativility.d.
config:
        NAME                                                      STATE     READ WRITE CKSUM
        bpool                                                     ONLINE       0     0     0
          usb-SanDisk__Cruzer_Fit_4C530000180129117161-0:0-part1  ONLINE       0     0     0

errors: No known data errors

  pool: tank
 state: ONLINE
  scan: none requested
config:

        NAME                                            STATE     READ WRITE CKSUM
        tank                                            ONLINE       0     0     0
          mirror-0                                      ONLINE       0     0     0
            ata-WDC_WD5003ABYX-50WERA1_WD-WMAYP7972470  ONLINE       0     0     0
            ata-WDC_WD5003ABYX-50WERA1_WD-WMAYP7949276  ONLINE       0     0     0

errors: No known data errors

システムのインストール

ディレクトリ構造に合わせたデータセット作成

Linuxのディレクトリ構造については、大昔にちょっと調べただけで実はあんまり良く分かっていません。その為なるべく参考文献通りにしています。

コンテナとして機能するファイルシステムデータセットを作成します。

zfs create -o canmount=off -o mountpoint=none tank/ROOT
zfs create -o canmount=off -o mountpoint=none bpool/BOOT

ルートおよびブート ファイル システムのファイル システム データセットを作成します。

参考文献はUUID(っぽいランダムな6文字)を付加したデータセット名にしていますが、これをやると後々とっても扱いづらくなります。ubuntu以外はインストールしないし、複数インストールもしない予定なので、UUIDは無しの方向にしました。

zfs create -o mountpoint=/ \
    -o com.ubuntu.zsys:bootfs=yes \
    -o com.ubuntu.zsys:last-used=$(date +%s) tank/ROOT/ubuntu

zfs create -o mountpoint=/boot bpool/BOOT/ubuntu

データセットを作成します。

zfs create -o com.ubuntu.zsys:bootfs=no -o canmount=off tank/ROOT/ubuntu/usr
zfs create -o com.ubuntu.zsys:bootfs=no -o canmount=off tank/ROOT/ubuntu/var
zfs create tank/ROOT/ubuntu/var/lib
zfs create tank/ROOT/ubuntu/var/log
zfs create tank/ROOT/ubuntu/var/spool

zfs create -o canmount=off -o mountpoint=/ tank/USERDATA
zfs create -o com.ubuntu.zsys:bootfs-datasets=tank/ROOT/ubuntu \
    -o canmount=on -o mountpoint=/root tank/USERDATA/root
chmod 700 /mnt/root

参考文献から、今回必要なデータセットのオプションを選んで設定します。

zfs create tank/ROOT/ubuntu/var/lib/apt
zfs create tank/ROOT/ubuntu/var/lib/dpkg
zfs create -o com.ubuntu.zsys:bootfs=no tank/ROOT/ubuntu/srv
zfs create tank/ROOT/ubuntu/var/lib/docker
zfs create tank/ROOT/ubuntu/var/www

このマシンはHDDがミラー構成なので、次のデータセットを作成します。

zfs create -o com.ubuntu.zsys:bootfs=no bpool/grub

/runに tmpfs をマウントします。

mkdir /mnt/run
mount -t tmpfs tmpfs /mnt/run
mkdir /mnt/run/lock

なお/homeはユーザー追加時に作成します。

debootstrap

Ubuntu 22.04 LTS 通称 jammy をインストール。

debootstrap jammy /mnt

終わったら以下のコマンドを実行します。

mkdir /mnt/etc/zfs
cp /etc/zfs/zpool.cache /mnt/etc/zfs/

システム構成

マシン名

まずはホスト名を決めます。

hostname ホスト名
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は使わないようにするので下記のようにしてみました。

このマシンはNICを2枚持っています。片方はオンボードで、もう片方はギガビットイーサのPCIネットワークカードです。オンボードの方は遅いのでケーブルを外してあります。

root@ubuntu:~# ip addr show
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
    inet 127.0.0.1/8 scope host lo
       valid_lft forever preferred_lft forever
    inet6 ::1/128 scope host
       valid_lft forever preferred_lft forever
2: enp2s1: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
    link/ether 00:16:01:5c:19:df brd ff:ff:ff:ff:ff:ff
    inet 172.16.2.22/16 brd 172.16.255.255 scope global dynamic noprefixroute enp2s1
       valid_lft 79109sec preferred_lft 79109sec
    inet6 fe80::d711:2541:6143:727e/64 scope link noprefixroute
       valid_lft forever preferred_lft forever
3: enp0s25: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc fq_codel state DOWN group default qlen 1000
    link/ether 00:21:9b:1a:5f:94 brd ff:ff:ff:ff:ff:ff

以前の記事の通りにIPアドレスを割り振ります。

参考文献:固定IPアドレスの割当(IPv4、IPv6) - Netplanの使い方 - komeの備忘録

cat > /mnt/etc/netplan/01-netcfg.yaml <<___
network:
  version: 2
  renderer: networkd
  ethernets:
    enp2s1:
      dhcp4: no
      addresses: [172.16.1.3/16]
      gateway4: 172.16.2.1
      nameservers:
        addresses: [172.16.2.1]
    enp0s25:
      dhcp4: no
      addresses: [172.16.1.4/16]
      gateway4: 172.16.2.1
      nameservers:
        addresses: [172.16.2.1]
___

パッケージソース

cat >/mnt/etc/apt/sources.list <<___
deb http://archive.ubuntu.com/ubuntu jammy main restricted universe multiverse
deb http://archive.ubuntu.com/ubuntu jammy-updates main restricted universe multiverse
deb http://archive.ubuntu.com/ubuntu jammy-backports main restricted universe multiverse
deb http://security.ubuntu.com/ubuntu jammy-security main restricted universe multiverse
___

chroot

Live CD 環境の仮想ファイルシステムをバインドマウントして、上記でセットアップした環境に chroot します( --bind ではなく --rbind を使っていることに注意)。

mount --make-private --rbind /dev  /mnt/dev
mount --make-private --rbind /proc /mnt/proc
mount --make-private --rbind /sys  /mnt/sys
chroot /mnt /usr/bin/env BOOTDISK=$BOOTDISK bash --login

chroot 環境内の apt のインデクスを更新します。

apt update

ロケール

en_US.UTF-8 と ja_JP.UTF-8 と、後は個人的な好みで。私は ja_JP.EUC-JP を入れます。

locale-gen --purge en_US.UTF-8 ja_JP.UTF-8 ja_JP.EUC-JP

エディタ

個人的な好みで vi です。

apt install --yes vim

タイムゾーン

参考文献には書かれていませんが、タイムゾーンを設定します。
日本なら Asia/Tokyo です。

ln -sf /usr/share/zoneinfo/Asia/Tokyo /etc/localtime
dpkg-reconfigure -f noninteractive tzdata

カーネルイメージなど

古いマシンなのでEFIは設定しません。

Linux のカーネルイメージと ZFS を chroot 環境にインストールします。

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

Windowsなど他のOSを入れる予定は無いので、os-proberを削除します。

apt purge --yes os-prober

ここで下記のエラーが出ますが、これは無視して良さそうです。多分。

ERROR couldn't connect to zsys daemon: connection error: desc = "transport: Error while dialing dial unix /run/zsysd.sock: connect: no such file or directory"

rootパスワード

パスワードを設定します。

passwd

スワップ無し

スワップは諦めたので、該当手順は実施しません。

tmpfs

次回起動時に tmpfs を /tmp にマウントするようにします。

cp /usr/share/systemd/tmp.mount /etc/systemd/system/
systemctl enable tmp.mount

システムグループ

無くてもいいかなと思ったけれど、一応Ubuntuなので、念の為に作成しておきます。

addgroup --system lpadmin
addgroup --system lxd
addgroup --system sambashare

SSH

sshに関しては少々考えている事がありまして、このタイミングでのインストールは避けます。

GRUB のインストール

ZFSの認識

ZFS のブートファイルシステムが認識されていることを確認します。zfs と出力されれば OK です。

grub-probe /boot

initrd更新

initrdファイルを更新します。

update-initramfs -c -k all

設定ファイル

メモリのゼロ化を無効にします。

sed -i -e'/^GRUB_CMDLINE_LINUX_DEFAULT=/s/"$/ init_on_alloc=0"/' /etc/default/grub

ブート構成を更新します。

update-grub

ブートローダーをインストール

レガシー BIOS 用に GRUB をインストールします。

grub-install $BOOTDISK

ZFS のモジュールがインストールされていることを確認します。

ls /boot/grub/*/zfs.mod

grub-initrd-fallback.serviceを無効にします。

systemctl mask grub-initrd-fallback.service

ファイルシステムのマウント順序を修正

zfs-mount-generatorを有効にする必要があります。これによりsystemdは個別のマウントポイントを認識します。これは/var/log/var/tmpなどにとって重要です。また、rsyslog.servicelocal-fs.targetを介してvar-log.mountに依存し、systemdのPrivateTmp機能を使用するサービスは自動的にAfter=var-tmp.mountを使うようになります。
……との事。

mkdir /etc/zfs/zfs-list.cache
touch /etc/zfs/zfs-list.cache/bpool
touch /etc/zfs/zfs-list.cache/tank
zed -F &

これらが空でない事をチェックして、キャッシュが更新された事を確認します。
空だった場合の対応は参考文献を参照。

cat /etc/zfs/zfs-list.cache/bpool
cat /etc/zfs/zfs-list.cache/tank

キャッシュにデータが含まれたらzedを停止します。

fg
(Ctrl-C)

パス/mntを除去するように修正します。

sed -Ei "s|/mnt/?|/|" /etc/zfs/zfs-list.cache/*

chroot終了

chroot環境を終了して LiveCD 環境に戻ります。

exit

初回のブート

LiveCD 環境で次のコマンドを実行して、すべてのファイルシステムをアンマウントします。

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

なぜかエラーが出ます。原因不明。仕方が無いので放置します。

root@ubuntu:~# zpool export -a
cannot export 'tank': pool is busy

そのままシャットダウン。

shutdown -h now

その後、インストールメディアを取り出して、それからマシンの電源を入れます。

これ以降はsshは使えません。

grub

案の定、grubでエラーが出ます。
ここで慌てず騒がず、grubのプロンプトで普通にzpoolをimportします。

zpool import -f tank
exit

今度はちゃんと起動します。

rootログイン

サーバーのコンソールで root ユーザーでパスワードを入力してログインします。

日本語キーボード配列

記号を打ってみるとわかりますが、英語配列になっています。日本語配列に変更する手順は以下の参考文献を参照。バージョンは古いですが、画面キャプチャがあるのでわかりやすいです。

参考文献:Ubuntuでキーボードレイアウト変更 - Ragnite Blue

コマンドは下記。

dpkg-reconfigure keyboard-configuration

設定後、次のコマンドを打つ必要があるようです。

setupcon

フルのソフトウェアインストール

ミニマムインストールをアップグレードします。

apt dist-upgrade --yes

サーバ用としてコマンドライン環境のみをインストールします。

apt install --yes ubuntu-standard

再起動して確認

reboot

まだ一般ユーザーが居ないので、rootでログインします。
そして色々確認。

  • キーボードが日本の配列になっている事。アットマーク @ を打ってみて確認。
  • ネットワ-クが有効になっている事。仮想環境など状況によって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名だけを取り出せますので自動化が可能です。

スナップショット

初回インストールのスナップショットを作成しておきます。こういう事をしたいが為にZFSを使うのです。

zfs snapshot -r tank@$(date +%Y%m%d_%H%M%S)_install

スナップショットの一覧を表示して確認します。

zfs list -t snapshot

ただ、どうも、自動的にsnapshotを撮られているようです。apt-getのタイミングなんでしょうかね。自分で手動snapshotした分を表示するには下記コマンドが良さそうです。

zfs list -t snapshot | grep -v autozsys

仕舞い

これで最小限のUbuntuサーバをZFSの上にセットアップできました。
この後は下記の記事に従って整備します。

更に、OpenLDAPやオレオレ認証局については少々考えている事があるので別記事を立てるとして、これで大体追い付きましたか。やったね:thumbsup_tone1:

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?