[覚書]PXE+PreseedでUbuntuインストールを自動化してみた

# はじめに

OSのインストール，めんどくさいですよね．
データセンターでは，ハードを準備してコンソール・LANケーブル・電源ケーブルを挿して電源入れるだけでネットワーク経由でOSインストール・ソフトウェアインストールが終了し，k8sとかのクラスタに自動に組み込まれる仕組みがあるらしいです（伝聞)
カッコいいので，試してみた．

# 環境

* UbuntuServer18.04
* VirtualBoxで検証

# PXEブート

Preboot eXecution Environmentの略．ネットワークブート．
DHCPサーバがPXEサーバの位置をアドバタイズし，TFTPを使ってイメージを配布する仕組み．

## IPアドレスを固定(netplan）

Ubuntu18からはymlでネットワークインターフェースを設定する．
IPアドレスを固定しておく． 

```yml:/etc/netplan/01-netcfg.yaml
# This file describes the network interfaces available on your system
# For more information, see netplan(5).
network:
  version: 2
  renderer: networkd
  ethernets:
    enp0s3:
      addresses: [192.168.56.101/24]
      dhcp4: no
      dhcp6: no
      nameservers:
        addresses: [192.168.56.1, 8.8.8.8]
      routes:
      - to: 192.168.56.0/24
        via: 192.168.56.254
      - to: 0.0.0.0/0
        via: 192.168.56.1
```

変更後は下のコマンドで反映させる．

```
$ sudo netplan apply
```

## tftp, dhcpの設定

インストールする．

```
$ sudo apt install -y isc-dhcp-server tftpd-hpa tftp-hpa
$ sudo systemctl enable tftpd-hpa
$ sudo systemctl enable isc-dhcp-server
```

dhcpサーバの設定.末尾に追加する．
指定したアドレス範囲にアドレスを分配する時に，PXEClientかどうかを識別．UEFIかどうかで配布するファイルを変更する．ファイルはtftpで配布．

```config:/etc/dhcp/dhcpd.conf
~~略~~
option space PXE;
option PXE.mtftp-ip    code 1 = ip-address;
option PXE.mtftp-cport code 2 = unsigned integer 16;
option PXE.mtftp-sport code 3 = unsigned integer 16;
option PXE.mtftp-tmout code 4 = unsigned integer 8;
option PXE.mtftp-delay code 5 = unsigned integer 8;
option arch code 93 = unsigned integer 16; # RFC4578

subnet 192.168.56.0 netmask 255.255.255.0 {
     range 192.168.56.50 192.168.56.100;
     option domain-name "cilab";
     option domain-name-servers 192.168.11.1;
     option routers 192.168.56.1;

     class "pxeclients" {
        match if substring (option vendor-class-identifier, 0, 9) = "PXEClie$
        next-server 192.168.56.101;

        if option arch = 00:07 {
           filename "BOOTx64.EFI";
        } else {
           filename "pxelinux.0";
        }
    }
}
```

## tftpサーバにリソースを設定する

tftpで配布するリソースは，デフォルトでは`/var/lib/tftpboot`に配置する．
Ubuntuのイメージを持ってくる．

[Ubuntu 18.04.4 LTS (Bionic Beaver)](http://cdimage.ubuntu.com/releases/18.04.4/release/?_ga=2.251244230.1941979109.1584174279-2021336477.1584174279)

↑のページの「ubuntu-18.04.4-server-amd64.iso」をダウンロード

```
$ sudo mkdir -p /mnt/ubuntu
$ mount -o loop,ro ubuntu-18.04-server-amd64.iso /mnt/ubuntu
$ cd /mnt/ubuntu/
$ sudo cp -r /mnt/ubuntu/install/netboot/* /var/lib/tftpboot/
```

apache web serverで配布する場合は以下も実行しておく
```
sudo ln -s /mnt/ubunu /var/www/html/
```

とりあえずここまででPXEブートができる(多分)

# Pressed

RHEL/CentOSでいうKickstart．OSの自動インストールをする仕組み．
ネットワークインターフェース設定やlocale設定，ユーザ設定などの入力，，インストールするパッケージを選択など，OSインストール時にユーザインターフェースが必要だった部分を自動化する．また，設定ファイル内でコマンド・スクリプト実行が可能である．
動的なパーティション設定やIPアドレス設定が可能になる（多分）

＃＃ Preseedファイルの設定

ｃｆｇファイルを作っていく

```
$ sudo mkdir /var/lib/tftpboot/presseed
$ sudo nano /var/lib/tftpboot/preseed/ubuntu-18.04-preseed.cfg
```

Pressedファイルは[[WIP]Preseed による Ubuntu Server の自動インストール入門（18.04 LTS対応版）](https://qiita.com/wnoguchi/items/9a9092dd23eea88d435f)を参考

```conf:ubuntu-18.04-preseed.cfg
#===========================================================================================
# BOOT SEQUENCE CONFIGURATIONS START
# ENDの設定のところまではDVDメディア、USBメディアに同梱している場合にのみ有効になる設定。
# PXEブートの場合はこのセクションは無視される。
# この場合はpxelinuxのconfigのappendに直接記述する必要がある。
#===========================================================================================
d-i debian-installer/language string en
d-i debian-installer/country string US
d-i debian-installer/locale string en_US.UTF-8
d-i localechooser/supported-locales en_US.UTF-8
d-i console-setup/ask_detect boolean false
d-i console-setup/layoutcode string us
d-i console-setup/charmap select UTF-8

# キーボードレイアウトの特性の設定（日本語キーボード）
d-i keyboard-configuration/layoutcode string jp
d-i keyboard-configuration/modelcode jp106

#===========================================================================================
# ネットワークまわりの設定
#-------------------------------------------------------------------------------------------
# 静的IP
#-------------------------------------------------------------------------------------------
# preseed.cfgを外から持ってこようとするとどうしてもいったんDHCP解決しないといけない。
# そして以下の netcfg 項目は一回目は無視されるので d-i preseed/run のところで
# ネットワーク設定をリセットするハックが必要になる。
# そうすると静的IPとして設定を直してくれるようになる。
#
# 詳しくは以下:
# - https://help.ubuntu.com/lts/installation-guide/i386/preseed-contents.html
# - http://debian.2.n7.nabble.com/Bug-688273-Preseed-netcfg-use-autoconfig-and-netcfg-disable-dhcp-doesn-t-work-td1910023.html
#
# 以下の2項目を設定しないと静的IPとして処理されないので重要
#d-i netcfg/use_autoconfig boolean false 
#d-i netcfg/disable_autoconfig boolean true 

#d-i netcfg/choose_interface select auto
#d-i netcfg/disable_dhcp boolean true
#d-i netcfg/get_nameservers string 8.8.8.8 8.8.4.4 1.1.1.1 
#d-i netcfg/get_ipaddress string 192.168.56.102 
#d-i netcfg/get_netmask string 255.255.255.0 
#d-i netcfg/get_gateway string 192.168.56.1 
#d-i netcfg/confirm_static boolean true 
#d-i netcfg/get_hostname string pxe-client 
#d-i netcfg/get_domain string cilab 
#d-i netcfg/wireless_wep string

#-------------------------------------------------------------------------------------------
# DHCPのとき
#-------------------------------------------------------------------------------------------
d-i netcfg/choose_interface select auto
d-i netcfg/disable_autoconfig boolean false
d-i netcfg/get_hostname string pxe-client
d-i netcfg/get_domain string client 
d-i netcfg/wireless_wep string 

#------
# User
#------
d-i passwd/root-login boolean false
d-i passwd/user-fullname string hogehoge
d-i passwd/username string hogehoge
d-i passwd/user-password password password
d-i passwd/user-password-again password password

#----
# TimeZone
#----
d-i clock-setup/utc boolean true
d-i time/zone string Asia/Tokyo
d-i clock-setup/ntp boolean true

#===========================================================================================
# BOOT SEQUENCE CONFIGURATIONS END
#===========================================================================================

# インストーラパッケージをダウンロードするミラーを選択する
#d-i mirror/protocol http
d-i mirror/country string manual
d-i mirror/http/hostname string jp.archive.ubuntu.com
d-i mirror/http/directory string /ubuntu/
d-i mirror/http/proxy string

# インストールするスイートを選択
#d-i mirror/suite xenial
d-i mirror/suite bionic

d-i clock-setup/utc boolean false 
d-i time/zone string Japan 
d-i clock-setup/ntp boolean false

#===========================================================================================
# PARTMAN PARTITIONING SECTION START
#===========================================================================================
# すべてのRAIDデバイス構成を破棄する
d-i partman-md/device_remove_md boolean true
# すべてのLVMデバイス構成を破棄する
d-i partman-lvm/device_remove_lvm boolean true

d-i partman/confirm_nooverwrite boolean true

d-i partman-auto/disk string /dev/sda
d-i partman-auto/method string regular
d-i partman-auto/choose_recipe select atomic
# Set the default filesystem
d-i partman/default_filesystem string ext4

# Install without swap space
d-i partman-basicfilesystems/no_swap boolean false

d-i partman-auto/expert_recipe string \
vm :: \
1024 1024 -1 $default_filesystem \
$primary{ } \
$bootable{ } \
method{ format } \
format{ } \
use_filesystem{ } \
$default_filesystem{ } \
mountpoint{ / } \
.
d-i partman-md/confirm boolean true
d-i partman-partitioning/confirm_write_new_label boolean true
d-i partman/choose_partition select Finish partitioning and write changes to disk
d-i partman/confirm boolean true 
d-i partman/confirm_nooverwrite boolean true

### Base system installation
# Verbose output and no boot splash screen.
d-i debian-installer/quiet boolean false
d-i debian-installer/splash boolean false

# Always install the server kernel.
# d-i base-installer/kernel/override-image string linux-server

d-i apt-setup/main boolean true
d-i apt-setup/services-select multiselect
tasksel tasksel/first multiselect
d-i pkgsel/language-pack-patterns string
d-i pkgsel/install-language-support boolean false
d-i pkgsel/include string openssh-server curl dnsutils build-essential tasksel s-nail sudo lv

postfix postfix/mailname string your-preferred-mailname
d-i pkgsel/upgrade select full-upgrade
d-i pkgsel/update-policy select none

popularity-contest popularity-contest/participate boolean false
d-i pkgsel/updatedb boolean false


# GRUBインストーラー
d-i grub-installer/grub2_instead_of_grub_legacy boolean true 
d-i grub-installer/only_debian boolean true 
d-i grub-installer/bootdev string /dev/sda

# インストールが終了したらサーバー再起動
d-i finish-install/keep-consoles boolean true
d-i finish-install/reboot_in_progress note
d-i cdrom-detect/eject boolean false
```


## menuの設定

自動インストールを行うため，timeoutを300(30秒)に設定

```conf:/var/lib/tftpboot/pxelinux.cfg/default
# D-I config version 2.0
# search path for the c32 support libraries (libcom32, libutil etc.)
path ubuntu-installer/amd64/boot-screens/
include ubuntu-installer/amd64/boot-screens/menu.cfg
default ubuntu-installer/amd64/boot-screens/vesamenu.c32
prompt 0
timeout 300
```

インストールメニューは```/var/lib/tftpboot/ubuntu-installer/amd64/boot-screens```で設定されている．
ontimeoutを設定し，タイムアウトが発生した場合の選択肢を決定する．

```conf:menu.cfg
menu hshift 13
menu width 49
menu margin 8

menu title Installer boot menu^G
ontimeout auto-ubuntu-18.04
include ubuntu-installer/amd64/boot-screens/stdmenu.cfg
include ubuntu-installer/amd64/boot-screens/txt.cfg
include ubuntu-installer/amd64/boot-screens/gtk.cfg
menu begin advanced
	menu title Advanced options
	include ubuntu-installer/amd64/boot-screens/stdmenu.cfg
	label mainmenu
		menu label ^Back..
		menu exit
	include ubuntu-installer/amd64/boot-screens/adtxt.cfg
	include ubuntu-installer/amd64/boot-screens/adgtk.cfg
menu end
label help
	menu label ^Help
	text help
   Display help screens; type 'menu' at boot prompt to return to this menu
	endtext
	config ubuntu-installer/amd64/boot-screens/prompt.cfg
```

「auto-ubuntu-18.04」を追加する．
appendにガリガリと書かないとうまく動かない．ガンバレ．

```conf:txt.cfg
default install
label auto-ubuntu-18.04
        menu label ^Ubuntu 18.04 automated install
        kernel ubuntu-installer/amd64/linux
        default true
        append DEBCONF_DEBUG=5 auto=true debian-installer/language=en debian$
label install
        menu label ^Install
        kernel ubuntu-installer/amd64/linux
        append vga=788 initrd=ubuntu-installer/amd64/initrd.gz --- quiet
label cli
        menu label ^Command-line install
        kernel ubuntu-installer/amd64/linux
        append tasks=standard pkgsel/language-pack-patterns= pkgsel/install-$
```

とりあえずここまででPressedが動いてるはず．多分．

## UEFI対応

まだ検証中．
virtualboxがUEFIのネットブートに対応していないらしくて辛い．


# 参考文献

[[WIP]Preseed による Ubuntu Server の自動インストール入門（18.04 LTS対応版）](https://qiita.com/wnoguchi/items/9a9092dd23eea88d435f)
[初めてのPXEブート](http://lab.astamuse.co.jp/entry/2018/10/24/160000)
[Ubuntu 16.04上にUbuntu 18.04のPXEブートサーバをセットアップ](https://hnakamur.github.io/blog/2018/04/24/ubuntu18.04-pxe-boot-server-on-ubuntu16.04/)
[Ubuntu 16.04 LTS でPXE Bootサーバ環境構築 - Webを汚すWeblog](https://blog.dshimizu.jp/article/901)
[サーバ大量構築時のキモ ～PreseedでのLinux自動インストールディスク作成～](https://orebibou.com/2014/06/%E3%82%B5%E3%83%BC%E3%83%90%E5%A4%A7%E9%87%8F%E6%A7%8B%E7%AF%89%E6%99%82%E3%81%AE%E3%82%AD%E3%83%A2-%EF%BD%9Epreseed%E3%81%A7%E3%81%AElinux%E8%87%AA%E5%8B%95%E3%82%A4%E3%83%B3%E3%82%B9%E3%83%88/)
[PreseedでUbuntu 18.04をProvisioningした作業メモ (UEFI対応版)](https://qiita.com/YasuhiroABE/items/135a5507b6d47363ab31)
[PXEネットワークブート用サーバを構築するには](https://www.atmarkit.co.jp/flinux/rensai/linuxtips/710pxeserver.html#:~:text=PXE%EF%BC%88Preboot%20eXecution%20Environment%EF%BC%89%E3%81%AF,PXE%E3%82%B5%E3%83%BC%E3%83%90%E3%81%8C%E5%BF%85%E8%A6%81%E3%81%A0%E3%80%82)
[UEFI環境でのPXEブート](http://denkas.hatenadiary.jp/entry/2015/03/19/004534)