俺様サーバー構築記 - ZFSをarchisoに埋め込む(linux-lts)@VirtualBox(BIOS)

「[俺様サーバー構築記 - 基本方針](https://qiita.com/katz_engineer/items/dbabcff4e14e9db2b10f)」に基づいてZFS上にArchLinuxをインストールしてきて、LTS版Linuxカーネルを使用しての再構築を試みています。

個人的な都合により、VirtualBoxの仮想マシンのみでサーバとクライアントの構築を試みました。これからしばらく、その流れでの作業の記録です。

# download

[Arch Linux をダウンロード](https://www.archlinux.jp/download/)のページから、適当なミラーを選択しましょう。私は何も考えずにリストの最上位 jaist.ac.jp を選択しました。テキトーに、ランダムに選ぶのが良いかも知れません。

そして今日の時点での ArchLinux インストーラー最新版をダウンロードします。今回は archlinux-2020.07.01-x86_64.iso です。

# VirtualBox

Windows10 にインストールした VirtualBox を使用し、新規作成します。
私の VirtualBox のバージョンは 6.1.10 r138449 (Qt5.6.2) でした。

今回、というかしばらくはVirtualBoxで作業します。ホストマシンは Windows10 Home ですので、残念ながらHyper-Vは使えません。WSL2が使えるようになったので、いずれ研究してみますかね。

仮想マシンはごく普通の設定です。強いて言えばHDDが少ないです。単に、ホストマシンがSSD搭載のノートパソコンで、空き容量がだいぶ心細いので減らしただけです。
タイプ: Linux
バージョン: Arch Linux (64-bit)
メモリーサイズ: 3072MB
仮想ハードディスクを作成する
　ファイルサイズ: 50.00GB
　ハードディスクのタイプ: VDI (VirtualBox Disk Image)
　物理ハードディスクにあるストレージ: 可変サイズ

以上で作成した後、設定によって少々いじります。
システム:
　拡張機能: EFIは無効にしておく、それ以外はデフォルトのまま
　プロセッサー数: 2
ストレージ:
　コントローラー: （ダウンロードした archlinux-2020.07.01-x86_64.iso を選択）
オーディオ: オーディオを無効にする
ネットワーク: ネットワークアダプターを有効化、割り当て=NAT （外につながれば何でも良い、ホストマシンが無線LANを使用している場合はブリッジアダプターではゲストのネットワークがうまくつながらない）

ちゃんと想定通り動くならEFIでいいんですけどね。VirtualBoxのEFIは何だか色々おかしいので、今回はBIOSにしておきます。

そして起動！ここからがインストールの本番です。

# インストールの準備

## 署名の検証

省略します。最初は ArchLinux 環境が無いって事で。

## キーボード

```console
# loadkeys jp106
```

## コンソールフォント

コンソールフォントはそのまま変更しません。日本語が表示されればそれなりに便利そうだけども、当面は必要無いと判断。

## 起動モードの確認

VirtualBox仮想マシンの設定でBIOSにしましたが、念の為。エラーになればOK。

```console
# ls /sys/firmware/efi/efivars
ls: cannot access '/sys/firmware/efi/efivars': No such file or directory
```

## パーティション

一応 HDD を確認しておきます。

```console
# ls /dev/sd*
/dev/sda
```

lsblkコマンドを使うと、多少整理されて見えます。

```console
# lsblk
NAME  MAJ:MIN RM   SIZE RO TYPE MOUNTPOINT
loop0   7:0    0 529.7M  1 loop /run/archiso/sfs/airootfs
sda     8:0    0    50G  0 disk
sr0    11:0    1   647M  0 rom  /run/archiso/bootmnt
```

ディスク構成が複雑な場合は ```/dev/disk/by-id``` を見ると、ファイル名（＝デバイスID）からもう少し情報を得られる可能性があるんですが。今回は VirtualBox なので省略します。

デバイスを確認した所で、HDDにパーティションを切ります。今回の用途の場合、最低でもbootパーティションを分ける必要があります。まぁ、すぐに廃棄するのでいい加減で大丈夫です。

[パーティショニング - ArchWiki](https://wiki.archlinux.jp/index.php/パーティショニング#.E3.82.B9.E3.83.AF.E3.83.83.E3.83.97)の[パーティションの大きさはどうすればいいですか？]に下記のような記述があります。

> 大容量のメモリ（1024MB 以上）を積んでいるときは、スワップパーティションは小さく、または作らなくてもかまわないでしょう。2GB 以上の物理 RAM を持っているなら、スワップパーティションがないほうが一般的に良いパフォーマンスを発揮すると思われます。

これを信じてスワップパーティションは作りません。

また一応、HDDフォーマットの前に ```wipefs``` コマンドを実行します。

```console
# wipefs -a /dev/sda
# sfdisk /dev/sda <<___
\`heredoc> ,512M
\`heredoc> ,
\`heredoc>___
Checking that no-one is using this disk right now ... OK
〈以下、長いので省略〉
```

確認。

```console
# sfdisk -l /dev/sda
Disk model: VBOX HARDDISK
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x8ef99707

Device      Boot   Start       End   Sectors  Size Id Type
/dev/sda1           2048   1050623   1048576  512M 83 Linux
/dev/sda2        1050624 104857599 103806976 49.5G 83 Linux
# ls -l /dev/sd*
brw-rw---- 1 root disk 8, 0 Jul 24 02:36 /dev/sda
brw-rw---- 1 root disk 8, 1 Jul 24 02:36 /dev/sda1
brw-rw---- 1 root disk 8, 2 Jul 24 02:36 /dev/sda2
```

## パーティションのフォーマット

bootパーティションはFAT32。ルートは…ハッキリ言って何でもいい。すぐにzfsで再インストールしますので。

```console
# mkfs.fat -F32 /dev/sda1
mkfs.fat 4.1 (2017-01-24)
# mkfs.ext4 /dev/sda2
mke2fs 1.45.6 (20-Mar-2020)
Creating filesystem with 12975872 4k blocks and 3244032 inodes
Filesystem UUID: 8ffb5424-418e-48b8-86d8-abd59261c654
Superblock backups stored on blocks:
        32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208,
        4096000, 7962624, 11239424

Allocating group tables: done
Writing inode tables: done
Creating journal (65536 blocks): done
Writing superblocks and filesystem accounting information: done
```

## パーティションのマウント

```console
# mount /dev/sda2 /mnt
# mkdir /mnt/boot
# mount /dev/sda1 /mnt/boot
```

## インターネットへの接続

ネットワーク環境が確立しているかどうか、外部へのpingによって確認します。

```console
# ping -c2 archlinux.jp
PING archlinux.jp (160.16.119.98) 56(84) bytes of data.
64 bytes from tk2-235-27344.vs.sakura.ne.jp (160.16.119.98): icmp_seq=1 ttl=51 time=11.9 ms
64 bytes from tk2-235-27344.vs.sakura.ne.jp (160.16.119.98): icmp_seq=2 ttl=51 time=185 ms

--- archlinux.jp ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 1004ms
rtt min/avg/max/mdev = 11.921/98.505/185.089/86.584 ms
```

## システムクロックの更新

ntpサーバは自分で設定したい。日本ならntp.nict.jpが鉄板です。特殊事情が無ければこの一択。システム推奨なんか知りませ～ん。

```console
# cd /etc/systemd
# sed -i -e"s/^#NTP=.*$/NTP=ntp.nict.jp/" timesyncd.conf
# timedatectl set-ntp true
# timedatectl status
                      Local time: Fri 2020-07-24 02:50:12 UTC
                  Universal time: Fri 2020-07-24 02:50:12 UTC
                        RTC time: Fri 2020-07-24 02:50:12
                       Time zone: UTC (UTC, +0000)
       System clock synchronized: yes
systemd-timesyncd.service active: active
                 RTC in local TZ: no
# systemctl status systemd-timesyncd
  systemd-timesyncd.service - Network Time Synchronization
   Loaded: loaded (/usr/lib/systemd/system/systemd-timesyncd.service; enabled; vendor preset: ena>
   Active: active (running) since Fri 2020-07-24 02:50:08 UTC; 1min 17s ago
     Docs: man:systemd-timesyncd.service(8)
 Main PID: 829 (systemd-timesyn)
   Status: "Initial synchronization to time server 133.243.238.163:123 (ntp.nict.jp)."
    Tasks: 2 (limit: 3531)
   Memory: 1.6M
   CGroup: /system.slice/systemd-timesyncd.service
           └─829 /usr/lib/systemd/systemd-timesyncd

Jul 24 02:50:08 archiso systemd[1]: Starting Network Time Synchronization...
Jul 24 02:50:08 archiso systemd[1]: Started Network Time Synchronization.
Jul 24 02:50:09 archiso systemd-timesyncd[829]: Initial syncronization to time server 133.243.238.>
```

# インストール

## ミラーの選択

日本ならJapanをリスト先頭に持ってきたい、んですけど。なんだか注釈として国名を付けるのを止めたのかな、自動で抜き出せなくなりました… なんだかなぁ。

ちょっと調べてみると、どうもデフォルトのまま放っておいて良いような。下記の参考文献1を踏まえて ```head mirrorlist``` してみますとね…

参考文献1: [3.1	速度で並び替える - 3 ミラーをソートする - ミラー - ArchWiki](https://wiki.archlinux.jp/index.php/%E3%83%9F%E3%83%A9%E3%83%BC#.E9.80.9F.E5.BA.A6.E3.81.A7.E4.B8.A6.E3.81.B3.E6.9B.BF.E3.81.88.E3.82.8B)

しかしやっぱり日本のミラーを使いたい。と考えた場合、どうやら日本のミラーサイトは非公式だったようですな。それで ```mirrorlist``` から除外されたのかなぁ。良くわかりません。

参考文献2: [5.8	日本 - 5 非公式ミラー - ミラー - ArchWiki](https://wiki.archlinux.jp/index.php/%E3%83%9F%E3%83%A9%E3%83%BC#.E9.80.9F.E5.BA.A6.E3.81.A7.E4.B8.A6.E3.81.B3.E6.9B.BF.E3.81.88.E3.82.8B)

今回は、この非公式ミラーを設定してみます。面倒だったらそのまま放置で構わないかと。

```console
# cd /etc/pacman.d
# cat >mirrorlist <<'___'
\`heredoc> Server = http://mirror.archlinuxjp.org/$repo/os/$arch
\`heredoc> ___
```

## ベースシステムのインストール

BIOSブートに必要なパッケージも同時に落としてきます。この時点では、カーネルは通常版で良いようです。

今時は、CPUのデバッグ用パッチもOSが面倒を見るらしい。その為のパッケージ```intel-ucode```も落としておきます。

とりあえず現時点で必要最小限のパッケージはこれだけ。他に必要なパッケージは、必要に迫られた時に追加する事にします。

※パッケージの構成が昔とは少し変わっています。
※特にテキストエディタが入っていません。何でも良いんですが、個人的な好みで vi を入れます。
※ man も入らないようです。インストールセットには要らないだろうと判断してそのままです。

```console
# pacstrap /mnt base linux linux-firmware vi intel-ucode syslinux
〈表示省略〉
```

# システムの設定

## fstab

```console
# genfstab -U /mnt >>/mnt/etc/fstab
```

## chroot、タイムゾーン

```console
# arch-chroot /mnt
# ln -s /usr/share/zoneinfo/Japan /etc/localtime
# hwclock --systohc --utc
```

## ロケール

個人的にUnicodeが嫌いなのでEUCを基本にしたい。けど現在の情勢では無視できないので、選択肢としてUTF-8も使えるようにしました。

```console
# sed -i -e"s/^#\(ja_JP\.\)/\1/" /etc/locale.gen
# locale-gen
Generating locales...
  ja_JP.EUC-JP... done
  ja_JP.UTF-8... done
Generation complete.
# echo LANG=C >/etc/locale.conf
# echo KEYMAP=jp106 >/etc/vconsole.conf
```

日本語フォントが入っていない場合は LANG=C にしておきましょう。文字化けが非常に鬱陶しい事になります。正しくは en_US.UTF-8 らしいですけども、まあいいかなと。

## ホストネーム

マシンに名前を付けます。こういうのはセンスが出ますよね。なんて思うのは私だけ？

```console
# echo 〈ホスト名〉 >/etc/hostname
```

ArchWiki では同じ名前を /etc/hosts にも記述する事になってますけど、今回はインストーラですし、要らないでしょう。

## Initramfs

```console
# mkinitcpio -p linux
〈表示省略〉
但し、途中で警告が出た:
==> WARNING: Possibly missing firmware for module: wd719x
==> WARNING: Possibly missing firmware for module: aic94xx
良くわからないが、ひとまず無視
```

##　Rootパスワード

```console
# passwd
New password: 〈root用パスワード〉
Retype new password: 〈root用パスワード〉
passwd: password updated successfully
```

## ブートローダー

今回は syslinux を使いたい。いえ特別な理由は無いんですけど、grubはデカいという噂を時折耳にしますので。小さい事は良い事です。

参考文献: [1.2	インストール - 1	BIOS 環境 - Syslinux - ArchWiki](https://wiki.archlinux.jp/index.php/Syslinux#.E3.82.A4.E3.83.B3.E3.82.B9.E3.83.88.E3.83.BC.E3.83.AB)

```console
# syslinux-install_update -i -a -m
Syslinux BIOS install successful
/usr/bin/syslinux-install_update: line 117: warning: command substitution: ignored null byte in input
Boot Flag Set - /dev/sda1
Installed MBR (/usr/lib/syslinux/bios/mbr.bin) to /dev/sda
```

syslinuxの設定ファイルを弄ります。
なぜか```/dev/sda3```をrootにしようとしてるので直したり、Intelのマイクロコードのアップデートを有効にしたり。

参考文献:
* [systemd-boot - サンプル - マイクロコードのアップデート - ArchWiki](https://wiki.archlinux.jp/index.php/マイクロコード#systemd-boot)
* [3 設定 - Syslinux - ArchWiki](https://wiki.archlinux.jp/index.php/Syslinux)

```console
# cd /boot/syslinux
# cp -p syslinux.cfg syslinux.cfg.org
# sed -i -e"s,^\([[:space:]]*APPEND\).*$,\1 root=UUID=$(blkid --match-tag UUID -o value /dev/sda2) rw," -e"/ INITRD / i \    ../intel-ucode.img" syslinux.cfg
# vi syslinux.cfg
# diff -U3 syslinux.cfg{.org,}
--- syslinux.cfg.org    2019-11-21 17:02:28.000000000 +0900
+++ syslinux.cfg        2020-07-24 20:35:28.000000000 +0900
@@ -51,13 +51,15 @@
 LABEL arch
     MENU LABEL Arch Linux
     LINUX ../vmlinuz-linux
-    APPEND root=/dev/sda3 rw
+    APPEND root=UUID=8ffb5424-418e-48b8-86d8-abd59261c654 rw
+    INITRD ../intel-ucode.img
     INITRD ../initramfs-linux.img

 LABEL archfallback
     MENU LABEL Arch Linux Fallback
     LINUX ../vmlinuz-linux
-    APPEND root=/dev/sda3 rw
+    APPEND root=UUID=8ffb5424-418e-48b8-86d8-abd59261c654 rw
+    INITRD ../intel-ucode.img
     INITRD ../initramfs-linux-fallback.img

 #LABEL windows
```

## ネットワーク

デバイス名の固定は考えません。すぐにzfsで再インストールしますので。と言っても systemd を使うと勝手に固定してくれるようですが。

```console
# cat >/etc/systemd/network/all.network <<___
> [Match]
> Name=*
>
> [Network]
> DHCP=ipv4
> ___
# systemctl enable systemd-networkd
Created symlink /etc/systemd/system/dbus-org.freedesktop.network1.service -> /usr/lib/systemd/system/systemd-networkd.service.
Created symlink /etc/systemd/system/multi-user.target.wants/systemd-networkd.service -> /usr/lib/systemd/system/systemd-networkd.service.
Created symlink /etc/systemd/system/sockets.target.wants/systemd-networkd.socket -> /usr/lib/systemd/system/systemd-networkd.socket.
Created symlink /etc/systemd/system/network-online.target.wants/systemd-networkd-wait-online.service -> /usr/lib/systemd/system/systemd-networkd-wait-online.service.
```

そしてリゾルバは ```systemd-resolved``` を有効にしておきます。```/etc/resolv.conf``` の調整だけではうまくいかなくなったようです。

```console
# systemctl enable systemd-resolved
Created symlink /etc/systemd/system/dbus-org.freedesktop.resolve1.service -> /usr/lib/systemd/system/systemd-resolved.service.
Created symlink /etc/systemd/system/multi-user.target.wants/systemd-resolved.service -> /usr/lib/systemd/system/systemd-resolved.service.
```

## 再起動

終了。

```console
# exit
exit
arch-chroot /mnt  13.30s user 4.10s system 0% cpu 8:29:37.01 total
```

仮想マシンをシャットダウン。

```console
# umount -R /mnt
# shutdown -h now
```

そして、VirtualBoxのストレージからインストールメディアを除去した後に再起動します。

# rootログイン

再起動してログイン画面になったら、rootユーザーでログインします。パスワードは先ほどpasswdコマンドで設定した通り。

```console

Arch Linux 5.7.10-arch1-1 (tty1)

〈ホスト名〉 login: root
Password: 〈root用パスワード〉
```

# archzfsパッケージをarchisoに埋め込む

さてここからが勝負所です。

参考文献: [8.1 archzfs パッケージを archiso に埋め込む - 8
ヒントとテクニック - ZFS - ArchWiki](https://wiki.archlinux.jp/index.php/ZFS#archzfs_.E3.83.91.E3.83.83.E3.82.B1.E3.83.BC.E3.82.B8.E3.82.92_archiso_.E3.81.AB.E5.9F.8B.E3.82.81.E8.BE.BC.E3.82.80)

まずはarchisoパッケージをダウンロード。

```console
# pacman -Syy
〈省略〉
# pacman -S archiso --noconfirm --noprogressbar
```

次に、[ArchWiki](https://wiki.archlinux.jp/index.php/ZFS#archzfs_.E3.83.91.E3.83.83.E3.82.B1.E3.83.BC.E3.82.B8.E3.82.92_archiso_.E3.81.AB.E5.9F.8B.E3.82.81.E8.BE.BC.E3.82.80)には「プロセスを開始」って書いてあるんだけど…意味がよくわかりません。とりあえず書いてあるコピーコマンドを実行。

```console
# cp -r /usr/share/archiso/configs/releng /root/media
```

packages.x86_64 ファイルに追記。ここでLTS版を指定します。

```console
# cd /root/media
# cat >>packages.x86_64 <<___
> zfs-linux-lts
> ___
```

pacman.conf ファイルに追記。

```console
# cat >>pacman.conf <<'___'
>
> [archzfs]
> SigLevel = Never
> Server = http://archzfs.com/$repo/x86_64
> ___
```

LTS版カーネルを含むisoを作成するには、build.shに直接手を加える必要がある模様。

```console
# sed -i -e"s/vmlinuz-linux/vmlinuz-linux-lts/g" build.sh
```

イメージ作成。ここで、結構な時間が掛かります。

```console
# ./build.sh -v
〈省略〉
[mkarchiso] INFO: Done! | 722M out/archlinux-2020.07.24-x86_64.iso
```

## エラー: バージョン不一致

今日はまた、zfsとカーネルでバージョン不一致が発生しました。もういやッ！

```console
# ./build.sh -v
〈省略〉
warning: cannot resolve "linux-lts=5.4.52-1", a dependency of "zfs-linux-lts"
:: The following package cannot be upgraded due to unresolvable dependencies:
      zfs-linux-lts

:: Do you want to skip the above package for this upgrade? [y/N]
error: failed to prepare transaction (could not satisfy dependencies)
:: unalbe to satisfy dependency 'linux-lts=5.4.52-1' required by zfs-linux-lts
==> ERROR: Failed to install packages to new root
```

ArchWikiなどで、今の時点の[linux-lts パッケージ](https://www.archlinux.org/packages/core/x86_64/linux-lts/)のパージョンを確認しました。linux-lts 5.4.53-1でした…

恐らく、数日の差でzfsのバージョンアップが間に合ってないのでしょう。きちんとバージョンが揃うのを待つ手もあります。しかし今回は、リポジトリを数日遡ればバージョンが揃っていただろう事を期待して、coreリポジトリの変更を試みました。

[Arch Linux Archive](https://wiki.archlinux.jp/index.php/Arch_Linux_Archive)という、公式リポジトリのスナップショットを保存する場所があるそうです。[そこ](https://archive.archlinux.org/repos/)の一番新しい日付のリポジトリから順に（手作業で）調べて、```zfs-linux-lts```が要求する```linux-lts```のバージョンが存在する場所を探します。今回は https://archive.archlinux.org/repos/2020/07/23/core/os/x86_64/ が該当の場所でした。

```console
# cat >/etc/pacman.d/mirrorlist <<'___'
> Server = https://archive.archlinux.org/repos/2020/07/23/$repo/os/$arch
> ___
# cd
# rm -r /root/media
# cp -r /usr/share/archiso/configs/releng /root/media
# cd /root/media
# cat >>packages.x86_64 <<___
> zfs-linux-lts
> ___
# cat >>pacman.conf <<'___'
>
> [archzfs]
> SigLevel = Never
> Server = http://archzfs.com/$repo/x86_64
> ___
# sed -i -e"s/vmlinuz-linux/vmlinuz-linux-lts/g" build.sh
# ./build.sh -v
```

## エラー: キー

キーに関するエラーが出た場合。

```console
# ./build.sh -v
〈省略〉
(113/113) checking keys in keyring
:: Import PGP key 3B94A80E50A477C7, "人の名前 <メールアドレス>"? [Y/n]
error: key "3B94A80E50A477C7" could not be looked up remotely
:: Import PGP key 3B94A80E50A477C7, "人の名前 <メールアドレス>"? [Y/n]
error: key "3B94A80E50A477C7" could not be looked up remotely
error: required key missing from keyring
error: failed to commit transaction (unexpected error)
Errors occurred, no packages were upgraded.
==> ERROR: Failed to install packages to new root
```

何だか盛大にエラーエラーと叫んでくれていますが。
参考文献に従い、下記コマンドで成功しました。

参考文献: [「キーリングに必要なキーがありません」の対処法](https://qiita.com/musaprg/items/8a1914a66c3117f2f949)

```console
# pacman -S archlinux-keyring
〈省略〉
# pacman -Syu
〈省略〉
# ./build.sh -v
```

# isoイメージをUSBメモリに焼く

ホストマシンにUSBメモリを挿して、VirtualBoxゲストマシン（今ArchLinuxを実行している仮想マシン）に割り当てます。

```console
# lsblk -dpo NAME,FSTYPE
NAME     FSTYPE
/dev/sda
/dev/sdb iso9660
/dev/sr0
```

```/dev/sdb``` が増えました。もしも既に何やら入っていたら、削除して構わない内容である事は別途確認して下さい。完全に消え去るので、重要な思い出の写真か何かが入っていたら目も当てられません。

完成したisoイメージファイルを、このUSBメモリに焼き付けます。

```console
# dd bs=4M if=$(ls out/*) of=/dev/sdb status=progress && sync
```

コマンドが完了したら、このUSBメモリでホストマシンを起動。ArchLinuxで起動できればひとまず完成です！

# isoイメージをホストマシンへ転送

今回はホストマシン(Windows10)にisoイメージをコピーします。

なぜかVirtualBoxの共有フォルダ機能がうまく働かないようです。仕方が無いのでSambaで接続します。

```console
# pacman -S smbclient --noconfirm --noprogressbar
（省略）
# mount -t cifs //ホストマシンNetBIOS名/共有フォルダ名 /mnt -o username=ホストマシンユーザ名,password=ホストマシンパスワード,uid=1000,gid=1000
```

isoファイルをコピー。

```console
# cp out/*.iso /mnt
```

これで ArchLinux をシャットダウン。

```console
# shutdown -h now
```

そうしたらストレージに新しい archlinux-*-x86_64.iso を設定して起動。そして起動画面からバージョンを確認。それから zfs を確認します。

```console

Arch Linux 5.4.52-1-lts (tty1)

archiso login: root (automatic login)

# modprobe zfs
```

画面1行目のバージョン表記が 5.4.52-1-lts で、```modprobe zfs```の実行結果に何も表示されなければOKです！やったね :thumbsup_tone1: