LoginSignup
1
1

私的サーバー構築日誌:Ubuntu 22.04 LTS on ZFS in デスクトップパソコン(UEFI,GPT)

Posted at

能書き

私的サーバー構築日誌:仕切り直しからの自宅サーバー構築の続き。

目標

私の憧れだった Intel NUC の最新マシン NUC13ANHI5000 に、Ubuntu 22.04 をインストールしてサーバーマシンに仕立てます。

ストレージの暗号化はしない方針です。家庭用なので。

参考文献

インストール環境の整備

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

サーバーをインストールする場合でもデスクトップ版のisoを使用します。2023/08/15の最新版は22.04.3のようですな。これをUbuntuのサイトからダウンロードして、USBメモリに焼きます。

私は普段使いのWin10マシンでRufusというツールを使いましたが、ここはお好みでどうぞ。

image.png

image.png

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

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

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

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

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

sudo apt update

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

sudo apt install -y 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 -y debootstrap zfsutils-linux
systemctl stop zed

ディスクのフォーマット

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

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

lsblk

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

# lsblk
NAME    MAJ:MIN RM   SIZE RO TYPE MOUNTPOINTS
loop0     7:0    0     3G  1 loop /rofs
loop1     7:1    0     4K  1 loop /snap/bare/5
loop2     7:2    0  63.4M  1 loop /snap/core20/1974
loop3     7:3    0 237.2M  1 loop /snap/firefox/2987
loop4     7:4    0  73.9M  1 loop /snap/core22/858
loop5     7:5    0 349.7M  1 loop /snap/gnome-3-38-2004/143
loop6     7:6    0 485.5M  1 loop /snap/gnome-42-2204/120
loop7     7:7    0  91.7M  1 loop /snap/gtk-common-themes/1535
loop8     7:8    0  53.3M  1 loop /snap/snapd/19457
loop9     7:9    0   452K  1 loop /snap/snapd-desktop-integration/83
loop10    7:10   0  12.3M  1 loop /snap/snap-store/959
sda       8:0    1  58.2G  0 disk
└─sda1    8:1    1  58.2G  0 part /cdrom
sdb       8:16   1   7.5G  0 disk
nvme0n1 259:0    0   1.9T  0 disk

loop0loop10はインストーラによる設定でしょうか。
sdaが今回のUbuntuインストーラでしょう。
sdbはブートローダを仕込む為のUSBメモリです。
nvme0n1は内蔵させたSSDと思われます。

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

ls -l /dev/disk/by-id

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

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

SSDは何故か2つ登録されているので、片方のみ選択します。

DISK=$(cd /dev/disk/by-id; ls nvme-* usb-* | while read d; do if [ "$(readlink -f $d)" = "/dev/nvme0n1" ]; then echo "/dev/disk/by-id/$d"; fi; done | tail -n1)

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

swapoff --all

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

wipefs -a $BOOTDISK

ブート用USBメモリにパーティションを作成。GPTにします。

まずはパーティションテーブルをクリアします。

sgdisk --zap-all $BOOTDISK

ブートローダー パーティションを作成します。

sgdisk -n1:1M:+512M -t1:EF00 $BOOTDISK

ブートプールパーティションを作成します。以前領域不足になった事があるので、十分多目に確保しておきます。

sgdisk -n2:0:+4G -t2:BE00 $BOOTDISK

残りを確保しておきます。

sgdisk -n3:0:0 -t3:8300 $BOOTDISK

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

sgdisk -p $BOOTDISK

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

wipefs -a $DISK

スワップについて。
参考文献によると、zvolにスワップを置くとデッドロックの危険性があるので非推奨だそうです。バグレポートが上がっているらしい。

更に今回はSSDです。ここにスワップ領域を確保するのは危険です。SSDの場合は書き込み回数の上限が結構少ないとの事なので。

と言う訳でスワップは無効にします。本当は有効にした方が、Linuxメモリ管理の都合上、良いらしいですが。諦めます。

いよいよ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}-part2

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

そして内蔵SSDもzfsフォーマットします。

こちらの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 ${DISK}

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

# zpool list
NAME    SIZE  ALLOC   FREE  CKPOINT  EXPANDSZ   FRAG    CAP  DEDUP    HEALTH  ALTROOT
bpool   480M   612K   479M        -         -     0%     0%  1.00x    ONLINE  /mnt
tank   1.86T   416K  1.86T        -         -     0%     0%  1.00x    ONLINE  /mnt
# 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/compatibility.d.
config:

        NAME                                                      STATE     READ WRITE CKSUM
        bpool                                                     ONLINE       0     0     0
          usb-SanDisk__Cruzer_Fit_00006706073021110149-0:0-part2  ONLINE       0     0     0

errors: No known data errors

  pool: tank
 state: ONLINE
config:

        NAME                                        STATE     READ WRITE CKSUM
        tank                                        ONLINE       0     0     0
          nvme-SUNEAST_SE900NVG3_2048G_30096680360  ONLINE       0     0     0

errors: No known data errors

システムのインストール

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

Linuxのディレクトリ構造については、大昔にちょっと調べただけで実はあんまり良く分かっていません。その為なるべく参考文献通りにしていたんですが、やたらめったら細かく分かれています。ハッキリ言って管理し切れません。そのため必要最小限にしました。

また、スナップショットを撮る時にこのパスを入力する事になります。その際、英大文字があるとキーボードを打ちづらくなります。その為ROOTBOOTroot bootと小文字にしてみました。

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

最小限のデータセットを作成します。ここでもUSERDATAは英小文字`userdata゛にしました。

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

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

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

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

ネットワーク関連

以前の記事に基づいてIPアドレスを割り振ります。

IPADDR=172.16.1.2

hostsファイルを修正。

sed -i -e"/^127.0.0.1/a $IPADDR\t$(hostname)" /mnt/etc/hosts

ネットワークインターフェイス名を確認。どうやらenp86s0のようですな。wlo1は無線LANでしょう、今回は無視します。

# ip a
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: enp86s0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc mq state UP group default qlen 1000
    link/ether 48:21:0b:58:8d:a2 brd ff:ff:ff:ff:ff:ff
    inet 172.16.2.29/16 brd 172.16.255.255 scope global dynamic noprefixroute enp86s0
       valid_lft 80956sec preferred_lft 80956sec
    inet6 fe80::30c5:b1ed:5cb6:80f6/64 scope link noprefixroute
       valid_lft forever preferred_lft forever
3: wlo1: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default qlen 1000
    link/ether b0:dc:ef:9e:7f:50 brd ff:ff:ff:ff:ff:ff
    altname wlp0s20f3

netplan のネットワーク設定ファイル/mnt/etc/netplan/01-netcfg.yamlを作成します。今回はIPv6は使わないようにするので下記のようにしてみました。

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

cat > /mnt/etc/netplan/01-netcfg.yaml <<___
network:
  version: 2
  renderer: networkd
  ethernets:
    enp86s0:
      dhcp4: no
      addresses: [$IPADDR/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 -y vim

タイムゾーン

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

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

EFI ファイルシステム

EFI ファイルシステムを作成します。

apt install -y dosfstools
mkdosfs -F 32 -s 1 -n EFI ${BOOTDISK}-part1
mkdir /boot/efi
echo /dev/disk/by-uuid/$(blkid -s UUID -o value ${BOOTDISK}-part1) /boot/efi vfat defaults 0 0 >> /etc/fstab

/etc/fstabを設定したらすぐにmountしたい所ですが、連続して実行するとなぜかエラーが発生します。一瞬の間が必要なようです。理由は不明。
と言う訳で下記mountコマンドは分けておきます。

mount /boot/efi

/boot/grubを設定します。

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

カーネルイメージなど

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

apt install -y grub-efi-amd64 grub-efi-amd64-signed linux-image-generic shim-signed zfs-initramfs zsys

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

apt purge -y 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 をインストールします。

apt install -y openssh-server

ここでも下記のエラーが出ますな。無視。

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ログインできるように設定。

sed -i -e"/^#PermitRootLogin /a PermitRootLogin yes" /etc/ssh/sshd_config

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

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

UEFI 用に GRUB をインストールします。

grub-install --target=x86_64-efi --efi-directory=/boot/efi --bootloader-id=ubuntu --recheck --no-floppy

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

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

grub

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

zpool import -f tank
exit

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

rootログイン

SSHサーバを入れたのでsshで接続できます。rootユーザーでパスワードを入力してログインします。

ssh root@172.16.1.2

日本語キーボード配列

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

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

コマンドは下記。

dpkg-reconfigure keyboard-configuration

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

setupcon

ユーザーアカウントの作成

管理者を作成します。

username=管理者アカウント名
zfs create -o com.ubuntu.zsys:bootfs-datasets=tank/root/ubuntu -o canmount=on -o mountpoint=/home/$username tank/userdata/$username
adduser $username
cp -a /etc/skel/. /home/$username
chown -R $username:$username /home/$username
usermod -a -G adm,cdrom,dip,lpadmin,lxd,plugdev,sambashare,sudo $username

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

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

apt dist-upgrade -y

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

apt install -y ubuntu-standard

再起動して確認

reboot

サーバーコンソールでログインします。
そして色々確認。

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

root 無効化

引き続きサーバーコンソールで作業するか、あるいはssh接続。
そしてrootパスワードを無効にします。

usermod -p '*' root

rootでのSSHログインを無効にします。

sed -i -e"/^PermitRootLogin /s/yes/no/" /etc/ssh/sshd_config

一度ログアウトして、rootではログインできない事を確認します。

スナップショット

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

sudo zfs snapshot -r tank/root/ubuntu@$(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の上にセットアップできました。

1
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
1
1