PreseedでUbuntu 18.04をProvisioningした作業メモ (UEFI対応版)

# はじめに
以前、Ubuntu 16.04用にISOイメージを作成した顛末を残しました。([Preseedで自動インストールするカスタムISOイメージを作成する](https://qiita.com/YasuhiroABE/items/ff233459035d8187263d))

Ubuntu 18.04をオフラインでPC Engines社製のAPUにインストールするネットワークを構築した顛末を、[iPXE経由でAPUにUbuntu 18.04をインストールする](https://qiita.com/YasuhiroABE/items/cb8dd5141281a24613b6)に掲載しています。

今回は、合わせ技でUbuntu 18.04用のISOイメージを作成し、DVDブート+Preseedで自動インストールすることと、Raid1は使わずにUEFIに対応した比較的ノーマルな構成のハードウェアにUbuntuを導入することにしました。

> 【2021年5月10日追記】Ubuntu 18.04の次のLTS版、20.04ではPreseedの仕組みが廃止され、AutoInstallを利用する必要があります。AutoInstallでは構成がまだ難しい場合(RAIDを利用するなど)には、18.04+Preseedを利用し、20.04にバージョンアップする方法も有効だと思いますが、まずはAutoInstallの利用を検討してください。AutoInstallについては、[Ubuntu 20.04をAutoInstallで自動インストールしてみた](https://qiita.com/YasuhiroABE/items/637f1046a15938f9d3e9)に記載しています。

# 基本的な作業方針

基本的にはこれまでの方法を踏襲し、Preseedでparmanでパーティションを作成する辺りでGPTに対応すること、UEFIに対応するためにgrubの設定を新たに加えるぐらいで落ち着くはずです。

# 環境

* Hardware: IBOX-N10A (UEFI enabled)
* Disk: mSATA Samsung SSD 850 EVO 250GB

# 参考資料

Ubuntu 16.04の頃からISOイメージを作成するために参照しているドキュメント類です。

* http://sig9.hatenablog.com/entry/2016/09/10/120000
* https://www.u-aizu.ac.jp/~yasu-abe/ja/memo/20160603.1/
* https://gist.github.com/wnoguchi/6577937
* (New!) https://github.com/nuada/ubuntu-preseed
* (New!) https://help.ubuntu.com/lts/installation-guide/s390x/apbs04.html
* (New!) https://wiki.archlinux.jp/index.php/インストール_ISO_のリマスタリング

# 今回の作業で、難しいと感じたところ

## sources.list の内容

```mirror/http/mirror select jp.archive.ubuntu.com```を指定したので、```mirror/http/hostname```の指定は不要かなと思っていると、インストールされたシステムの/etc/apt/sources.listのホスト名が*us.archive.ubuntu.com*になっていたりします。

Ubuntuのガイド中のコメントでは、マニュアル設定またはselectによるCC.archive.ubuntu.comの指定のどちらかで良いのかなと思われるのですが、実際には両方の設定が必要になります。個々のパラメータが各所で関連していると思われます。

```text:該当する記述
# If you select ftp, the mirror/country string does not need to be set.
#d-i mirror/protocol string ftp
d-i mirror/country string manual
d-i mirror/http/hostname string ports.ubuntu.com
d-i mirror/http/directory string /ubuntu
d-i mirror/http/proxy string

# Alternatively: by default, the installer uses CC.archive.ubuntu.com where
# CC is the ISO-3166-2 code for the selected country. You can preseed this
# so that it does so without asking.
#d-i mirror/http/mirror select CC.archive.ubuntu.com
```

## mirror/http/proxy を空にする設定

mirror/httpつながりで、設定しない場合でもこの項目を入れておかないとCUIが止まり、対話的に設定を求められます。

```
d-i mirror/http/proxy string
```

## UEFIに対応したpartman設定

partmanについては、参考資料に載せた https://github.com/nuada/ubuntu-preseed にある partitions-uefi-boot-root-swap.template の設定を全面的に採用しています。

partman-autoの設定だけではインストール後に起動しないので、ラベル名に*gpt*を指定している部分も含めて必要になります。

## UEFIに対応するため、txt.cfgではなく、grub.cfgを設定する

DVDドライブからインストーラーを起動する際には、通常のMBRからsyslinuxを起動する場合と、GPT対応ディスクとして起動する場合の2通りがあります。

今回はGPT対応ディスクとして起動される事を前提としてるため、以前は不要だったgrub.cfgのmenuentryを編集しています。→ [※詳細](#bootgrubgrubcfg)

## /swapfile の利用を止める

18.04からはスワップパーティションを削除しても、/swapfileが作成されます。

Kubernetesを導入する際にはswapoffが必須の設定です。
このために新しく導入された項目を利用し、サイズをゼロにする設定を行なう必要が生じました。

```
d-i partman-swapfile/percentage string 0
d-i partman-swapfile/size string 0
```

## ターゲット・ディスクが/mediaにマウントされている

既に/dev/sdaが構成されていると、/mediaにマウントされる場合があるため、early_commandで/mediaをunmountすることができます。

```
d-i preseed/early_command string umount /media
```

ただし、ディスクの状況によってこの命令で止まったりするため、実用的には```|| true```を後ろにつけるなどしている他の例に倣うべきだと思います。

# 全体の設定

今回も preseedディレクトリにsudoers、authorized_keysファイルを配置しています。

## preseed/preseed.cfg

```
d-i debian-installer/locale string en_US
d-i debian-installer/keymap string us
d-i keyboard-configuration/xkb-keymap select us
d-i keyboard-configuration/toggle select No toggling
d-i netcfg/choose_interface select auto
d-i netcfg/get_hostname string unassigned-hostname
d-i netcfg/get_domain string localdomain
d-i mirror/http/mirror select jp.archive.ubuntu.com
d-i apt-setup/restricted boolean true
d-i apt-setup/universe boolean true
d-i apt-setup/backports boolean true
d-i apt-setup/services-select multiselect security
d-i apt-setup/security_host string security.ubuntu.com
d-i apt-setup/security_path string /ubuntu
d-i mirror/suite string bionic
d-i passwd/user-fullname string Admin User01
d-i passwd/username string ubuntu
d-i passwd/user-password password temppwd
d-i passwd/user-password-again password temppwd
d-i user-setup/allow-password-weak boolean true
d-i user-setup/encrypt-home boolean false
d-i clock-setup/utc boolean false
d-i time/zone string Asia/Tokyo
d-i clock-setup/ntp boolean true
d-i clock-setup/ntp-server string ntp.nict.jp
d-i partman-auto/disk string /dev/sda
d-i partman/alignment string cylinder
d-i partman/confirm_write_new_label boolean true
d-i partman-basicfilesystems/choose_label string gpt
d-i partman-basicfilesystems/default_label string gpt
d-i partman-partitioning/choose_label string gpt
d-i partman-partitioning/default_label string gpt
d-i partman/choose_label string gpt
d-i partman/default_label string gpt
d-i partman-auto/method string regular
d-i partman-auto/choose_recipe select gpt-boot-root-swap
d-i partman-auto/expert_recipe string         \
   gpt-boot-root-swap ::                      \
      1 1 1 free                              \
         $bios_boot{ }                        \
         method{ biosgrub } .                 \
      200 200 200 fat32                       \
         $primary{ }                          \
         method{ efi } format{ } .            \
      512 512 512 ext2                        \
         $primary{ } $bootable{ }             \
         method{ format } format{ }           \
         use_filesystem{ } filesystem{ ext2 } \
         mountpoint{ /boot } .                \
      1000 20000 -1 ext4                      \
         $primary{ }                          \
         method{ format } format{ }           \
         use_filesystem{ } filesystem{ ext4 } \
         mountpoint{ / } .                    
d-i partman-partitioning/confirm_write_new_label boolean true
d-i partman/choose_partition select finish
d-i partman/confirm boolean true
d-i partman/confirm_nooverwrite boolean true
d-i partman-basicfilesystems/no_swap boolean false
d-i partman-md/device_remove_md boolean true
d-i partman-lvm/device_remove_lvm boolean true
d-i partman-swapfile/percentage string 0
d-i partman-swapfile/size string 0
d-i preseed/early_command string umount /media
d-i base-installer/install-recommends boolean true
d-i base-installer/kernel/image string linux-server
d-i apt-setup/use_mirror boolean false
d-i apt-setup/restricted boolean true
d-i apt-setup/universe boolean true
d-i apt-setup/backports boolean true
d-i apt-setup/services-select multiselect security
d-i apt-setup/security_host string security.ubuntu.com
d-i apt-setup/security_path string /ubuntu
d-i debian-installer/allow_unauthenticated boolean true
tasksel tasksel/first multiselect none
d-i pkgsel/include string openssh-server python2.7-minimal
d-i pkgsel/upgrade select full-upgrade
popularity-contest popularity-contest/participate boolean false
d-i pkgsel/update-policy select none
d-i pkgsel/install-language-support boolean true
d-i grub-installer/only_debian boolean true
d-i grub-installer/with_other_os boolean true
d-i grub-installer/bootdev  string /dev/sda
d-i finish-install/reboot_in_progress note
d-i preseed/late_command string \
 in-target mkdir -p /home/ubuntu/.ssh ; \
 in-target cp /media/cdrom/preseed/authorized_keys /home/ubuntu/.ssh/authorized_keys ; \
 in-target chmod 750 /home/ubuntu/.ssh ; \
 in-target chown -R ubuntu:ubuntu /home/ubuntu/.ssh ; \
 in-target cp /media/cdrom/preseed/sudoers /etc/sudoers ; \
 in-target chmod 440 /etc/sudoers ; \
 in-target chown root:root /etc/sudoers ; \
 in-target sed -i -e 's/#PasswordAuthentication yes/PasswordAuthentication no/' /etc/ssh/sshd_config
```

## boot/grub/grub.cfg

menuentryはisolinux/txt.cfgと基本的に同じです。initrdだけ別の行に移動している構成です。

```
if loadfont /boot/grub/font.pf2 ; then
        set gfxmode=auto
        insmod efi_gop
        insmod efi_uga
        insmod gfxterm
        terminal_output gfxterm
fi

set menu_color_normal=white/black
set menu_color_highlight=black/light-gray

set timeout=0
menuentry "Install Ubuntu Server with Preseed" {
        set gfxpayload=keep
        linux   /install/vmlinuz file=/cdrom/preseed/preseed.cfg vga=normal auto=true locale=en_US.UTF-8 console-setup/charmap=UTF-8 console-setup/layoutcode=us console-setup/ask_detect=false pkgsel/language-pack-patterns=pkgsel/install-language-support=false quiet --
        initrd  /install/initrd.gz
}
```

# DVDイメージの作成

以前はgenisoimageコマンドを使っていましたが、GPTブートに対応させるためxorrisoコマンドを使うように変更しました。

```bash:16.04バージョン
#!/bin/bash

sudo genisoimage -N -J -R -D -V "CUSTOM" -o ubuntu-16.04.4-server-amd64-preseed."$(date +%Y%m%d.%H%M%S)".iso -b isolinux/isolinux.bin -c isolinux/boot.cat -no-emul-boot -boot-load-size 4 -boot-info-table iso_root/
```

```bash:18.04バージョン
#!/bin/bash

sudo xorriso -as mkisofs -volid "CUSTOM" -output ubuntu-18.04.1-server-amd64-preseed."$(date +%Y%m%d.%H%M%S)".iso -eltorito-boot isolinux/isolinux.bin -eltorito-catalog isolinux/boot.cat -no-emul-boot -boot-load-size 4 -boot-info-table -eltorito-alt-boot -e boot/grub/efi.img -no-emul-boot -isohybrid-gpt-basdat -isohybrid-mbr iso_root/isolinux/isohdpfx.bin iso_root/
```

# isohdpfx.binファイルの準備

MBRブートするためのエントリで、512バイト1セクタ分のデータをDVDイメージからコピーして使用しています。

```bash
$ dd if=ubuntu-18.04.1-server-amd64.iso of=isohdpfx.bin bs=512 count=1
```

この他にsyslinux.cfgとtxt.cfgの設定も一応しています。

# さいごに

今回利用したIBOX-N10Aは4ポート NICとJ1900 CPUを備えた、そこそこのパフォーマンスのあるルーター向けベアボーンです。

UEFIブートするDVDイメージはコマンドラインをみても、GRUBのefi.imgを指定しているため、syslinuxは関係ありませんが、16.04からの流れで一応設定しています。

自動インストールを利用してキッティングするようなシチューエションはあまりないかもしれませんが、構成された個体の設定にばらつきがあるといろいろ困るので作業の品質を一定にするためには便利な方法です。

これは将来の自分のためのメモですが、何かの参考になれば幸いです。