俺様サーバー構築記 - ZFSをarchisoに埋め込む@デスクトップパソコン(BIOS)

マシンスペックは[ArchLinux インストール覚書](https://qiita.com/katz_engineer/items/f032a24cb273c4eb6669)で書いた通り [DELL Inspiron 530s](https://www.dell.com/support/home/jp/ja/jpbsd1/product-support/product/inspiron-530s/manuals) です。古い古い化石のようなマシンです。会社で廃棄処分になる奴をロハで貰ってきたものなので。会社で数年間、何かのサーバとして動かし続けた実績があるとの事でした。

サーバー構築方針などの能書きについては「[俺様サーバー構築記 - 基本方針](https://qiita.com/katz_engineer/items/dbabcff4e14e9db2b10f)」を参照。

2019/12/25
手順が若干変わったので記事を新しく起こしました。[俺様サーバー構築記 - ZFSをarchisoに埋め込む; やり直し@VirtualBox(UEFI)](https://qiita.com/katz_engineer/items/4b15e3b83d43d152ae7a)

# 参考文献

- [俺様サーバー構築記 - ZFSをarchisoに埋め込む@VirtualBox(UEFI)](https://qiita.com/katz_engineer/items/2da99197c37a6125ea81#_reference-56da66fb32e3194d7c4d)
- [続々・ArchLinux インストール覚書](https://qiita.com/katz_engineer/items/88250ee4ea51edb327f0#_reference-fe4d793ffcc42cb14c7e)

後者で示した通り、インストール対象の物理マシンには既にArchLinuxがインストールされています。これを使って、対象のインストーラをダウンロードして、今回はUSBメモリにisoを焼き付けて使用します。

# 最初のインストーラをUSBメモリに焼き付ける

「[俺様サーバー構築記 - ZFSをarchisoに埋め込む@VirtualBox(UEFI)](https://qiita.com/katz_engineer/items/2da99197c37a6125ea81#_reference-56da66fb32e3194d7c4d)」で、ZFSを埋め込んだisoを既に作成済なので、これをUSBメモリに焼き付ければそれで終わり。以下の手順もすべて不要なんですけどね。普通の方はそれで作業完了だと思います。

私の場合、この時に使ったVirtualBoxはWindowsマシンで動かしていたんです。その為isoをUSBメモリに焼き付けるには、その為のツールをインストールしなければならない訳でして。こんな作業は初めてだったので、ツールなんか入っていません。今からWindowsマシンに余分なツールを入れるのは気に入りませんし（それも今回1回しか使わないし）、それで今回の手間を掛けました。

今日の時点でのArchLinuxインストーラー最新版をダウンロードしました。 archlinux-2019.01.01-x86_64.iso です。別のマシンで適当なブラウザを使い、[Arch Linux をダウンロード](https://www.archlinux.jp/download/)のページから適当なミラーを選択しましょう。私は何も考えずにリストの最上位 jaist.ac.jp を選択しました。

そしてURLを確認し、それでダウンロードします。

```
# curl -O http://ftp.jaist.ac.jp/pub/Linux/ArchLinux/iso/2019.01.01/archlinux-2019.01.01-x86_64.iso
```

これをUSBメモリに焼き付けます。このマシンはHDDを2台搭載しているので、USBメモリは ```/dev/sdc``` になります。```/dev/disk/by-id``` を見ると usb- の接頭辞の付いた名前が見えるので、その辺で確認すれば良いでしょう。あるいはUSBメモリを挿入する前後でのデバイスの差を調べます。

参考文献: [1.1.1 GNU/Linux - 1.1 dd を使う - 1 BIOS・UEFI ブータブル USB - USB インストールメディア - ArchWiki](https://wiki.archlinux.jp/index.php/USB_インストールメディア#GNU.2FLinux)

```
# dd bs=4M if=archlinux-2019.01.01-x86_64.iso of=/dev/sdc status=progress && sync
```

USBメモリを挿したまま再起動します。そしてUSBメモリから起動させますが、正直、これが非常に面倒でした。BIOS画面を表示してBOOTメディアを調整するんですが、このマシンのBIOSはその設定がわかりにくい。

0. 一度電源を切ってから、電源を入れ直す（コマンド reboot で再起動はダメ）
0. F2キーを押してBIOS画面を表示
0. Boot Device Configuration
0. Hard Disk Boot Priority に HSB-HDD0 が表示されているので、これを順番の1.に移動
0. Boot Other Device を Enabled にする
0. F10キーを押してセーブして起動

この辺は機種に依存して変わる筈ですので、それぞれ確認して下さい。

# インストールの準備

## キーボード

```
# loadkeys jp106
```

## コンソールフォント

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

## 起動モードの確認

BIOSだという事はわかっていますが念の為。

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

## パーティション

このマシンのHDDは ```/dev/sda``` と ```/dev/sdb``` です。archisoを作るだけなので、今回は ```/dev/sda``` のみ使用します。

```
# ls /dev/sd*
/dev/sda  /dev/sdb  /dev/sdc  /dev/sdc1  /dev/sdc2
```

ここで見える ```/dev/sdc``` とその眷属（```/dev/sdc1``` ```/dev/sdc2```）は、起動する時に使用したUSBメモリです。mountコマンドの結果にそれが表れます。

```
# mount | grep /dev/sd
/dev/sdc1 on /run/archiso/bootmnt type iso9660 (ro,relatime,nojoliet,check=s,map=n,blocksize=2048)
```

ストレージデバイスを確認した所で、HDDにパーティションを切ります。今回の用途の場合、最低でもbootパーティションを分ける必要があります。

…なのですが、デバイス丸ごと1個をbtrfsにしていた過去がありまして、これの扱いがなかなか難しい。何が難しいかと言うと…

```
# lsblk -f /dev/sda
NAME FSTYPE LABEL       UUID                                 FSAVAIL FSUSE% MOUNTPOINT
sda  btrfs  btrfs_raid1 1a7327e5-95f3-4913-8f04-0fcc3c109d3a
```

これが、消えません。パーティションテーブルを削除しても、なぜか消えません。

```
# fdisk /dev/sda

Welcome to fdisk (util-linux 2.33).
Changes will remain in memory only, util you decide to write them.
Be careful before using the write command.


Command (m for help): o
Created a new DOS disklabel with disk identifier 0x6c93c192.

Command (m for help): w
The partition table has been alterd.
Calling ioctl() to re-read partition table.
Syncing disks.

# lsblk -f /dev/sda
NAME FSTYPE LABEL       UUID                                 FSAVAIL FSUSE% MOUNTPOINT
sda  btrfs  btrfs_raid1 1a7327e5-95f3-4913-8f04-0fcc3c109d3a
```

以上のような具合。

試行錯誤の末、```wipefs -a``` というコマンドでクリアされる（ように見える）事がわかりました。それが正しい対処なのかどうか不明ですが、とりあえずそれで行きます。HDDというデバイスに関する深い知識があれば理解できるのだと思いますが、今の私の知識ではこれが限界です。

正直、この問題には今の時点で対応する必要はありませんが。次のステップで対応すればいい話ではあります。

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

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

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

コマンドは sfdisk というものを見つけたので、これを利用してみます。

なお作業対象は、2台あるHDDの内の片方のみ。archiso作成作業の場所を作るだけですので。

```
# wipefs -a /dev/sda
/dev/sda: 8 bytes were erased at offset 0x00010040 (btrfs): 5f 42 48 52 66 53 5f 4d
# sfdisk /dev/sda <<___
\`heredoc> ,512M
\`heredoc> ,
\`heredoc>___
Checking that no-one is using this disk right now ... OK
〈以下、長いので省略〉
```

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

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

```
# mkfs.fat -F32 /dev/sda1
mkfs.fat 4.1 (2017-01-24)
# mkfs.ext4 /dev/sda2
mke2fs 1.44.5 (15-Dec-2018)
〈以下略〉
```

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

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

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

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

```
# 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=54 time=8.16 ms
64 bytes from tk2-235-27344.vs.sakura.ne.jp (160.16.119.98): icmp_seq=2 ttl=54 time=8.72 ms

--- archlinux.jp ping statistics ---
2 packets transmitted, 2 received, 0% packet loss, time 2ms
rtt min/avg/max/mdev = 8.155/8.435/8.715/0.280 ms
```

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

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

```
# cd /etc/systemd
# sed -i -e"s/^#NTP=.*$/NTP=ntp.nict.jp/" timesyncd.conf
# timedatectl set-ntp true
# timedatectl status
                      Local time: Sun 2019-01-13 01:48:41 UTC
                  Universal time: Sun 2019-01-13 01:48:41 UTC
                        RTC time: Sun 2019-01-13 01:48:41
                       Time zone: UTC (UTC, +0000)
       System clock synchronized: yes
                     NTP service: 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: enabled)
   Active: active (running) since Sun 2019-01-13 01:48:35 UTC; 1min 20s ago
     Docs: man:systemd-timesyncd.service(8)
 Main PID: 938 (systemd-timesyn)
   Status: "Synchronized to time server 133.243.238.163:123 (ntp.nict.jp)."
    Tasks: 2 (limit: 4915)
   Memory: 1.3M
   CGroup: /system.slice/systemd-timesyncd.service
           └─844 /usr/lib/systemd/systemd-timesyncd

Jan 13 01:48:35 archiso systemd[1]: Starting Network Time Synchronization...
Jan 13 01:48:35 archiso systemd[1]: Started Network Time Synchronization.
Jan 13 01:48:35 archiso systemd-timesyncd[938]: Synchronized to time server 133.243.238.163:123 (ntp.nict.jp).
```

# インストール

## ミラーの選択

日本ならJapanをリスト先頭に持ってきましょう。っていうか、Japanだけ抜き出しました。コマンドが簡単になるので。

```
# cd /etc/pacman.d
# sed -i -ne"/^#.*Japan$/,+1 p" mirrorlist
# cat mirrorlist
## Japan
Server = http://ftp.jaist.ac.jp/pub/Linux/ArchLinux/$repo/os/$arch
## Japan
Server = http://mirrors.cat.net/archlinux/$repo/os/$arch
## Japan
Server = http://ftp.tsukuba.wide.ad.jp/Linux/archlinux/$repo/os/$arch
```

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

BIOSブートに必要なパッケージも同時に落としてきます。ブートローダは、今回は syslinux を使ってみます。詳細は後述。

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

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

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

# システムの設定

## fstab

```
# genfstab -U -p /mnt >>/mnt/etc/fstab
# cat /mnt/etc/fstab
# Static information about the filesystems.
# See fstab(5) for details.

# <file system> <dir> <type> <options> <dump> <pass>
# /dev/sda2
UUID=f3f6c234-d876-4dc1-bc5d-37987f0e64db       /               ext4           rw,relatime    0 1

# /dev/sda1
UUID=42D3-5C98          /boot           vfat           rw,relatime,fmask=0022,dmask=0022,codepage=437,iocharset=iso8859-1,shortname=mixed,utf8,errors=remount-ro        0 2
```

## chroot、タイムゾーン

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

## ロケール

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

日本語フォントが入っていない場合は LANG=C にしておきましょう。文字化けが非常に鬱陶しい事になります。

## ホストネーム

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

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

## Initramfs

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

##　Rootパスワード

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

## ブートローダー

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

参考文献：
- [1.2.1 自動インストール - 1.2 インストール - 1 BIOS 環境 - Syslinux - ArchWiki](https://wiki.archlinux.jp/index.php/Syslinux)

```
# 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
# sfdisk -l /dev/sda
Disk /dev/sda: 298.1 GiB, 320072933376 bytes, 625142448 sectors
Disk model: ST3320620AS
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: 0x5298794e

Device     Boot    Start       End   Sectors   Size Id Type
/dev/sda1  *        2048   1050623   1048576   512M 83 Linux
/dev/sda2        1050624 625142447 624091824 297.6G 83 Linux
```

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

```
# cd /boot/syslinux
# cp syslinux.cfg syslinux.cfg.org
# vi syslinux.cfg
# diff -U3 syslinux.cfg{.org,}
--- syslinux.cfg.org    2019-01-13 17:51:30.000000000 +0900
+++ syslinux.cfg        2019-01-13 18:02:12.000000000 +0900
@@ -51,13 +51,15 @@
 LABEL arch
     MENU LABEL Arch Linux
     LINUX ../vmlinuz-linux
-    APPEND root=/dev/sda3 rw
+    APPEND root=UUID=f3f6c234-d876-4dc1-bc5d-37987f0e64db 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=f3f6c234-d876-4dc1-bc5d-37987f0e64db rw
+    INITRD ../intel-ucode.img
     INITRD ../initramfs-linux-fallback.img

 #LABEL windows
```

ちなみにUUIDは、下記コマンドを使えば一撃で取得できます。

```
# blkid --match-tag UUID -o value /dev/sda2
f3f6c234-d876-4dc1-bc5d-37987f0e64db
```

## ネットワーク

systemdを使用するとデバイス名を固定してくれるようですので、DHCPクライアントだけ設定します。

```
# 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.
```

なお /mnt/etc/resolv.conf は arch-chroot によって /etc/resolv.conf に置き換えられているようです。そのため exit してから設定しないと、設定前の何も無い状態に書き戻されてしまいます。インストール手順としてちょっと歪な気がしますが、arch-chrootをexitした後にresolv.confを修正します。

```
# exit
exit
arch-chroot /mnt  17.05s user 4.79s system 0% cpu 42:00.56 total
# cp --parents /etc/resolv.conf /mnt
# vi /mnt/etc/resolv.conf
〈必要に応じて修正〉
```

## 再起動

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

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

そして、インストールメディアであるUSBメモリを外した後に電源を入れます。

# rootログイン

再起動するとsyslinuxのメニュー画面が表示されますが、デフォルトの設定ですと5秒で自動的に先へ進みます。

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

```

Arch Linux 4.20.0-arch1-1-ARCH (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パッケージをダウンロード。

```
# pacman -Syy
〈省略〉
# pacman -S archiso
```

次に、[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)には「プロセスを開始」って書いてあるんだけど…意味がよくわかりません。とりあえず書いてあるコピーコマンドを実行。

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

packages.x86_64 ファイルに追記。

ここではダイナミックカーネルモジュールをサポートしているバージョンを選択します。zfs-linux-git で何度かやったんですが、結構頻繁にダメになるんです、zfsのバージョンとカーネルバージョンの不一致で。あまりにも面倒なので zfs-dkms を使う事にしました。

そしてzfsを使う時にはspl (Solaris Porting Layer) も入れる必要があります。またdkmsを使う時には linux-headers をインストールしておく必要があります。

```
# cd /root/media
# cat >>packages.x86_64 <<___
> linux-headers
> spl-dkms
> zfs-dkms
> ___
```

pacman.conf ファイルに追記。

ヒアドキュメントを使ってもいいんですが、その場合は ```$repo``` のドル記号をバックスラッシュでエスケープして ```\$repo``` とする必要があります。どっちでもいいんですけど、ちょっと面倒臭いんで、標準入力からキーボード入力します。こんな細っかい使い分けなんかどうでもいいですが。

```
# cat >>pacman.conf
[archzfs]
SigLevel = Never
Server = http://archzfs.com/$repo/x86_64
〈Ctrl-d〉
```

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

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

USBメモリを挿した後に下記コマンドを実行して、焼き付けるべきデバイスが ```/dev/sdc``` である事を確認します。

```
# lsblk -dpo NAME,FSTYPE,LABEL,UUID /dev/sdc
NAME     FSTYPE  LABEL       UUID
/dev/sdc iso9660 ARCH_201901 2019-01-01-15-22-42-00
```

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

```
# dd bs=4M if=out/archlinux-2019.01.13-x86_64.iso of=/dev/sdc status=progress && sync
```

焼き付ける事に成功したら、一度電源を切ります。このマシンは電源を切って入れ直さないと、稼働中に差したUSBメモリをブートデバイスとして認識してくれないので。

```
# shutdown -h now
```

電源を入れ直したら F2 キーを押し、BIOS画面でUSBメモリから起動するように変更。

起動すればOKです。やったね :thumbsup_tone1: