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

前置きは[俺様サーバー構築記 - 基本方針](https://qiita.com/katz_engineer/items/dbabcff4e14e9db2b10f)を参照。

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

# 参考文献

- [インストールガイド - ArchWiki](https://wiki.archlinux.jp/index.php/インストールガイド)
- [Arch LinuxをUEFI + GPT環境にインストールする - クロの思考ノート](http://note.kurodigi.com/archlinux-uefi-install/)

# download

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

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

# VirtualBox

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

仮想マシンはごく普通の設定です。強いて言えば、メモリが若干多めですかね。今時はこの程度でも普通だと思いますが。サーバにするならむしろ少ないくらいですか。
タイプ: Linux
バージョン: Arch Linux (64-bit)
メモリーサイズ: 4096MB
仮想ハードディスクを作成する
　ファイルサイズ: 100.00GB
　ハードディスクのタイプ: VDI (VirtualBox Disk Image)
　物理ハードディスクにあるストレージ: 可変サイズ

以上で作成した後、設定によって少々いじります。
システム:
　拡張機能: EFIを有効化(一部のOSのみ)
　プロセッサー数: 2
ストレージ:
　コントローラー: （ダウンロードした archlinux-2017.12.01-x86_64.iso を選択）
オーディオ: オーディオを無効にする
ネットワーク: ネットワークアダプターを有効化、割り当て=NAT （ホストマシンはノートパソコンで無線LANを使用しているので、ブリッジではゲストのネットワークがうまくつながらない）

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

# 待つ

画面真っ黒のまま、しばらく待たされるんですよね～… これ、慣れないと心臓に悪い。何とかなりませんかねぇ。

# インストールの準備

基本は[続々・ArchLinux インストール覚書](https://qiita.com/katz_engineer/items/88250ee4ea51edb327f0#_reference-fe4d793ffcc42cb14c7e)と同じです。違いはBIOSに関する箇所のみ。

## キーボード

```
# loadkeys jp106
```

## コンソールフォント

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

## 起動モードの確認

VirtualBox仮想マシンの設定で UEFI にしましたが、念の為。

```
# ls /sys/firmware/efi/efivars
（表示省略）
```

## パーティション

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

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

UEFIなので、EFIシステムパーティションが必要です。それとルートディレクトリのパーティション。

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

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

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

```
# gdisk /dev/sda
GPT fdisk (gdisk) version 1.0.3

Partitoin table scan:
 MGR: not present
 BSD: not present
 APM: not present
 GPT: not present

Creating new GPT entries.

Command (? for help): o
This option deletes all partitions and creates a new protective MBR.
Proceed? (Y/N): y

Command (? for help): n
Partition number (1-128, default 1):
First sector (34-209715166, default = 2048) or {+-}size{KMGTP}:
First sector (2048-209715166, default = 209715166) or {+-}size{KMGTP}: +512M
Current type is 'Linux filesystem'
Hex code or GUID (L to show codes, Enter = 8300): ef00
Changed type of partition to 'EFI System'

command (? for help): n
Partition number (2-128, default 2):
First sector (34-209715166, default = 1050624) or {+-}size{KMGTP}:
Last sector (1050624-209715166, default = 209715166) or {+-}size{KMGTP}:
Current type is 'Linux filesystem'
Hex code or GUID (L to show codes, Enter = 8300):
Changed type of partition to 'Linux filesystem'

Command (? for help): w

Final checks complete. About to write GPT data. THIS WILL OVERWRITE EXISTING
PARTITIONS!!

Do you want to proceed? (Y/N): y
OK; writing new GUID partition table (GPT) to /dev/sda.
The operation has completed successfully.
# ls -l /dev/sd*
brw-rw---- 1 root disk8, 0 Jan  3 10:10 /dev/sda
brw-rw---- 1 root disk8, 1 Jan  3 10:10 /dev/sda1
brw-rw---- 1 root disk8, 2 Jan  3 10:10 /dev/sda2
```

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

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

```
# mkfs.fat -F32 /dev/sda1
mkfs.fat 4.1 (2017-01-24)
# mkfs.ext4 /dev/sda2
mke2fs 1.43.7 (16-Oct-2017)
Creating filesystem with 26083067 4k blocks and 6520832 inodes
Filesystem UUID: 8b0bfd24-e148-4977-923a-49f728154e9a
Superblock backups stored on blocks:
        32768, 98304, 163840, 229376, 294912, 819200, 884736, 1605632, 2654208,
        4096000, 7962624, 11239424, 20480000, 23887872

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

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

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

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

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

```
# ping archlinux.jp | head -n3
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=7.14 ms
64 bytes from tk2-235-27344.vs.sakura.ne.jp (160.16.119.98): icmp_seq=2 ttl=51 time=10.3 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: Mon 2018-01-01 12:33:15 UTC
                  Universal time: Mon 2018-01-01 12:33:15 UTC
                        RTC time: Mon 2018-01-01 12:33:14
                       Time zone: UTC (UTC, +0000)
       System clock synchronized: yes
systemd-timesyncd.service active: yes
                 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: enable
   Active: active (running) since Mon 2018-01-01 12:33:02 UTC; 1min 3s ago
     Docs: man:systemd-timesyncd.service(8)
 Main PID: 784 (systemd-timesyn)
   Status: "Synchronized to time server 133.243.238.163:123 (ntp.nict.jp)."
    Tasks: 2 (limit: 4915)
   CGroup: /system.slice/systemd-timesyncd.service
           └─784 /usr/lib/systemd/systemd-timesyncd

Jan 01 12:33:02 archiso systemd[1]: Starting Network Time Synchronization...
Jan 01 12:33:02 archiso systemd[1]: Started Network Time Synchronization.
Jan 01 12:33:02 archiso systemd-timesyncd[784]: Synchronized to time server 133.243.238.163:123 (ntp
```

# インストール

## ミラーの選択

日本ならJapanをリスト先頭に持ってきましょう。

```
# cd /etc/pacman.d
# mv mirrorlist{,.org}
# cp mirrorlist{.org,}
# vi mirrorlist
〈編集内容省略〉
# diff -U0 mirrorlist{.org,}
--- mirrorlist.org      2017-12-01 15:58:50.000000000 +0000
+++ mirrorlist  2018-01-01 12:42:16.959986832 +0000
@@ -6,0 +7,4 @@
+## Japan
+Server = http://ftp.jaist.ac.jp/pub/Linux/ArchLinux/$repo/os/$arch
+## Japan
+Server = http://ftp.tsukuba.wide.ad.jp/pub/Linux/ArchLinux/$repo/os/$arch
@@ -335,2 +338,0 @@
-## Japan
-Server = http://ftp.jaist.ac.jp/pub/Linux/ArchLinux/$repo/os/$arch
@@ -463,2 +464,0 @@
-## Japan
-Server = http://ftp.tsukuba.wide.ad.jp/pub/Linux/ArchLinux/$repo/os/$arch
# rm mirrorlist.org
```

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

UEFIブートに必要なパッケージも同時に落としてきます。

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

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

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

# システムの設定

## fstab

```
# genfstab -U /mnt >>/mnt/etc/fstab
# cat /mnt/etc/fstab
#
# /etc/fstab: static file system information
#

# <file system> <dir>   <type>  <options>      <dump>  <pass>
# /dev/sda2
UUID=8b0bfd24-e148-4977-923a-49f728154e9a      /               ext4           rw,relatime,data=orderd    0 1

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

## chroot、タイムゾーン

```
# arch-chroot /mnt
# rm /etc/localtime
# ln -s /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
```

## ブートローダー

UEFI起動の場合、systemdがブートローダを持っているらしい。

参考文献:

* https://wiki.archlinux.jp/index.php/Systemd-boot

```
# bootctl --path=/boot install
Created "/boot/EFI"
Created "/boot/EFI/systemd"
Created "/boot/loader"
Created "/boot/loader/entries"
Copied "/usr/lib/systemd/boot/efi/systemd-bootx64.efi" to "/boot/EFI/systemd/systemd-bootx64.efi"
Copied "/usr/lib/systemd/boot/efi/systemd-bootx64.efi" to "/boot/EFI/BOOT/BOOTX64.EFI".
Created EFI boot entry "Linux Boot Manager".
```

更にIntelのマイクロコードのアップデートを有効にします。

参考文献:

* [systemd-boot - サンプル - マイクロコードのアップデート - ArchWiki](https://wiki.archlinux.jp/index.php/マイクロコード#systemd-boot)
* [標準的な root インストール - systemd-boot - ArchWiki](https://wiki.archlinux.jp/index.php/Systemd-boot#.E6.A8.99.E6.BA.96.E7.9A.84.E3.81.AA_root_.E3.82.A4.E3.83.B3.E3.82.B9.E3.83.88.E3.83.BC.E3.83.AB)

```
# cat >/boot/loader/entries/entry.conf <<___
> title   Arch Linux
> linux   /vmlinuz-linux
> initrd  /intel-ucode.img
> initrd  /initramfs-linux.img
> options root=PARTUUID=$(blkid --match-tag PARTUUID -o value /dev/sda2)
> ___
```

## ネットワーク

デバイス名の固定は、今回はやりません。すぐにzfsで再インストールしますので。

```
# cat >/etc/systemd/network/all.network
[Match]
Name=*

[Network]
DHCP=ipv4
〈Ctrl-d〉
# 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  12.62s user 2.81s system 2% cpu 12:04.39 total
# cp {,/mnt}/etc/resolv.conf
# vi /mnt/etc/resolv.conf
〈必要に応じて修正〉
```

## 再起動

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

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

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

# rootログイン

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

```

Arch Linux 4.14.9-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 ファイルに追記。ファイルサイズは0で中身無しだから、追記と言うよりも…って感じになりますが。ここではダイナミックカーネルモジュールをサポートしているバージョンを選択します。いえ zfs-linux-git で何度かやったんですがね、結構頻繁にダメになるんですよ、zfsのバージョンとカーネルバージョンの不一致で。あまりにも面倒なので zfs-dkms を使う事にしました。

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

```
# cd /root/media
# cat >>packages.x86_64 <<___
> linux-headers
> spl-dkms
> zfs-dkms
> ___
```
（2018.02.25.追記修正、ここまで）

pacman.conf ファイルに追記。追記になります。リダイレクト記号 >> を間違えないように。不等号を2文字重ねます。

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

```
# cat >>pacman.conf
[archzfs]
SigLevel = Never
Server = http://archzfs.com/$repo/x86_64
〈Ctrl-d〉
```
（2018.02.25.修正、ここまで）

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

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

今回はVirtualBoxにインストールしているので、完成したisoイメージをホストマシンに転送したい。一番簡単なのはVirtualBoxの共有フォルダ機能の利用かな、と思ってやってみました。

```
# pacman -S linux-headers virtualbox-guest-utils-nox
resolving dependencies...
:: There are 2 providers availale for VIRTUALBOX-GUEST-MODULES:
:: Repository community
   1) virtualbox-guest-dkms  2) virtualbox-guest-modules-arch

Enter a number (default=1): 1
〈以下略〉
```

VirtualBoxのデバイスメニューから共有フォルダーを設定。その名前をmountします。

```
# mount -t vboxsf 〈共有フォルダーの名前〉 /mnt
```

完成したisoイメージファイルを共有フォルダーにコピーします。

```
# cp /root/media/out/archlinux-*.iso /mnt
```

ホストマシン側にコピーしたisoイメージファイルを確認。ファイルが存在していればOK。やったね :thumbsup_tone1: