Ubuntu Server 20.04の自動インストール機能でネットワークインストールする。

# はじめに
この記事は以下記事の続きとなります。
PXEサーバの構築は前回の記事をご確認下さい。

- [OS自動インストールを行うためのPXEブート環境を作る](https://qiita.com/sakai00kou/items/bc6ae4d6b4cacc4b8af9)

CentOS8をKickstartでネットワークインストールする場合は以下の記事をご確認下さい。

- [CentOS8をKickstartでネットワークインストールする。](https://qiita.com/sakai00kou/items/16b22a64e239170e774a)

Ubuntu Server 20.10版も書きました。

- [Ubuntu Server 20.10の自動インストール機能でネットワークインストールする。](https://qiita.com/sakai00kou/items/47811ac1d86818258d4b)

---
`Ubuntu Server 20.04`でサポートされた新機能として[自動インストール機能](https://ubuntu.com/server/docs/install/autoinstall)があります。

今までも`Preseed`による自動インストールが可能だったと思いますが、`Ubuntu Server 20.04`の自動インストールは`cloud-init`形式でOS設定ができるため、内容が読みやすく設定しやすいのが特徴です。

公式の自動インストール手順は以下かと思いますが、私の環境ではどうしてもうまくいかなかったため、公式手順とは異なりますが何とか成功した手順を公開します。

- [Netbooting the live server installer](https://discourse.ubuntu.com/t/netbooting-the-live-server-installer/14510)

# 注意点
- Ubuntu Desktop版は今回の方法では自動インストールできません。

# 構成
VirtualBoxに以下構成の仮想マシンを作成しました。

PXEサーバは以前の記事で作成したPXEサーバを使用しているため、以下PXEサーバ側の操作はVirtualBox上CentOS8での操作となります。

なお、メモリは**3GB以上、できれば4GB以上のメモリ**を割り当てて下さい。
※最初2GBで作成した際、`Out of Memory`が発生して結構ハマりました。

**・自動インストール対象マシン構成**

|構成|種別|
|:--|:--|
|CPU|1 vCPU|
|メモリサイズ|4096 MB|
|ストレージ|20.00 GB|
|ネットワーク1|ホストオンリーアダプター|
|ネットワーク2|NAT|

**・PXEサーバディレクトリ構成**

|ディレクトリ|パス|
|:--|:--|
|TFTPディレクトリ|/tftpboot|
|HTTPディレクトリ|/pxeboot|

**・アドレス構成**

|対象|アドレス|
|:--|:--|
|PXEサーバ|192.168.56.105|
|自動インストール対象マシン|192.168.56.130|

※自動インストール対象マシンのアドレスは自動インストール後のアドレスです。

# 構築の流れ
PXEサーバは構築済みの前提となります。

**・PXEサーバ側手順**
1. Ubuntu Server 20.04のISOファイル転送
2. Ubuntu Server 20.04のカーネルイメージのコピー
3. TFTPブート構成ファイルの作成
4. Cloud-init用ファイルの作成
5. 自動インストール用ディレクトリ作成
6. meta-dataファイル作成
7. user-dataファイル作成
8. Netplanファイルの作成

**・自動インストール対象マシン側手順**
1. 自動インストール対象マシンの設定
2. 自動インストール

# Ubuntu Server 20.04の自動インストール機能について
`Ubuntu Server 20.04`の自動インストールでは、前述の通り`cloud-init`を使用するため、`user-data`ファイルと`meta-data`ファイルが必要となります。

## Ubuntu Server 20.04のISOファイル転送
[CANONICALのサイト](https://jp.ubuntu.com/download)より`Ubuntu Server 20.04 LTS`をダウンロードし、ダウンロードしたISOファイル（ubuntu-20.04-live-server-amd64.iso）をPXEサーバ以下のディレクトリに転送します。

|ファイル|パス|
|:--|:--|
|ISOファイル|/pxeboot/ubuntu-20.04-live-server-amd64.iso|

## Ubuntu Server 20.04のカーネルイメージのコピー
先ほど転送したISOファイルをマウントして`Ubuntu Server 20.04`のカーネルイメージを取得します。

```shell:カーネルイメージ格納ディレクトリ作成
sudo mkdir /tftpboot/Ubuntu
```

```shell:ISOイメージマウント
sudo mount -t iso9660 -o loop ubuntu-20.04-live-server-amd64.iso /mnt
```

```shell:カーネルイメージコピー
sudo cp /mnt/casper/{vmlinuz,initrd} /tftpboot/Ubuntu
```

```shell:ISOイメージアンマウント
sudo umount /mnt
```

# TFTPブート構成ファイルについて
PXEブートする際に取得するブート構成ファイルの名前は決められており、以下の様な規則になります。
※参考：[BIOSベースのPXEクライアントのブート・ローダー構成](https://docs.oracle.com/cd/E77565_01/install/ol7-install-pxe-boot-bios.html)

- **UUID** (例: a8943708-c6f6-51b9-611e-74e6ac80b93d)
- **01-MAC_address** (例: 01-80-00-27-c6-a1-16)
- **IPアドレスの完全32ビット** (例: 0A0000FD)
- **IPアドレスの最上位28ビット** (例: 0A0000F)
- **IPアドレスの最上位24ビット** (例: 0A0000)
- **IPアドレスの最上位20ビット** (例: 0A000)
- **IPアドレスの最上位16ビット** (例: 0A00)
- **IPアドレスの最上位12ビット** (例: 0A0)
- **IPアドレスの最上位8ビット** (例: 0A)
- **IPアドレスの最上位4ビット** (例: 0)
- **default** (デフォルト構成ファイル)

例えばMACアドレスのファイルを格納した場合、ホストごとにブート構成ファイルを固定できるため、それぞれのホスト専用の定義を指定することができます。

また、ブート構成ファイルの設定の書き方によっては、起動時に読み込むOSファイルやOSイメージをユーザに選択させることもできるので、`default`に複数の起動定義を記載して選択することも可能です。

## TFTPブート構成ファイルの作成
今回は`default`に自動インストール用定義を記載します。

```shell:/tftpboot/pxelinux.cfg/default
sudo cat << _EOF_ | sudo tee /tftpboot/pxelinux.cfg/default
default autoinstall
label autoinstall
  kernel Ubuntu/vmlinuz
  initrd Ubuntu/initrd
  append autoinstall ip=dhcp url=http://192.168.56.105/pxeboot/ubuntu-20.04-live-server-amd64.iso ds=nocloud-net;s=http://192.168.56.105/pxeboot/autoinstall/
_EOF_
```

## Cloud-init用ファイルの作成
`cloud-init`で自動インストールするために必要となる、`user-data`ファイルと`meta-data`ファイルを作成します。

`meta-data`ファイルはAWS等で使用する場合は`meta-data`からインスタンスID等を取得するために利用しますが、今回は空ファイルを作成しておくだけで問題ありません。

`user-data`、`meta-data`ファイルはPXEサーバから取得するようにしますので、PXEサーバの以下に作成します。

|ファイル|パス|
|:--|:--|
|user-dataファイル|/pxeboot/autoinstall/user-data|
|meta-dataファイル|/pxeboot/autoinstall/meta-data||


### 自動インストール用ディレクトリ作成
[前回のPXEサーバ構築](https://qiita.com/sakai00kou/items/bc6ae4d6b4cacc4b8af9)で作成したPXEブート用ディレクトリの下に**自動インストール用ディレクトリ**を作成します。

```shell:自動インストール用ディレクトリ作成
sudo mkdir /pxeboot/autoinstall
```

### meta-dataファイル作成
前述の通り空ファイルを自動インストール用ディレクトリの下に作成します。

```shell:meta-dataファイル作成
sudo touch /pxeboot/autoinstall/meta-data
```

### user-dataファイル作成前準備
`user-data`ファイルは`cloud-init`の書式で作成しますが、自動インストール時に使えるコマンドは限られているため、以下公式ドキュメント等を参照し、`user-data`ファイルを作成して下さい。

- [Automated Server Installs Config File Reference](https://ubuntu.com/server/docs/install/autoinstall-reference)

上記ドキュメントには[networkの設定](https://ubuntu.com/server/docs/install/autoinstall-reference#network)も記載されていますが、私の環境ではどうやっても**ネットワークの設定が反映できなかった**ので、ネットワークの設定は別ファイルで取得するようにしています。

また、`user-data`ファイル内に記載されているパスワードは以下の様な方法でハッシュ値を生成しておきます。
※今回はパスワード`ubuntu`で生成します。

```shell:パスワードハッシュ化
sudo openssl passwd -6 ubuntu
```

### user-dataファイル作成
OSの設定はインストール完了後、`Ansible`等で設定する前提で、`user-data`ファイルは作りすぎず、`Ansible`実行に必要となる設定の追加程度に止めておきます。

ネットワークの設定は前述の通り、私の環境では`cloud-init`ではできなかったので、`late-commands`で、予め作成しておいた`netplan`ファイルを取得するようにします。

但し、ネットワークインストール中は、**実際のディスク領域を`/target`でマウントしている**ようなので、`/target`を頭に指定して保存する必要があります。

もし他のファイルも一緒に送りたいという方は参考にして下さい。

```yaml:user-dataファイル作成
sudo cat << _EOF_ | sudo tee /pxeboot/autoinstall/user-data
#cloud-config
autoinstall:
  version: 1
  locale: ja_JP.UTF-8
  keyboard:
    layout: "jp"
  storage:
    layout:
      name: lvm
  identity:
    hostname: ubuntu-server
    username: ubuntu
    password: "$6$nFV7aBiOVRpPF8Qq$l0KnHQehyWsyGRzXvQnnriXxSUbrhPrWtkhOm4lZh1wSdzz4Ga9QN3eBcf9POKo8YFF0pztU9oIwx8oyNrNsf."
  ssh:
    install-server: yes
  user-data:
    timezone: Asia/Tokyo
  late-commands:
    - "wget -P /target/etc/netplan http://192.168.56.105/pxeboot/autoinstall/90-network.yaml"
_EOF_
```

## Netplanファイルの作成
`netplan`ファイルはOSインストール時に自動的に作成されますが、自動生成されたファイルは基本的に**手動で触るべきではない**です。

`/etc/netplan`配下のファイルはファイル名順に読み込まれて、前に読み込まれた設定を**上書き**します。

- [Netplan reference](https://netplan.io/reference/#general-structure)

そのため、後に読み込まれるようにファイル名を指定することで、デフォルトでどのような設定がされているとしても、任意の設定に変更することができます。

デフォルトだと`00-installer-config.yaml`などの名前で生成されるため、今回は`90-network.yaml`という名前にします。

```yaml:netplanファイル
sudo cat << _EOF_ | sudo tee /pxeboot/autoinstall/90-network.yaml
network:
  version: 2
  ethernets:
    enp0s3:
      dhcp4: no
      dhcp6: no
      addresses:
      - 192.168.56.130/24
    enp0s8:
      dhcp4: yes
      dhcp6: no
      nameservers:
        addresses:
        - 8.8.8.8
        - 8.8.4.4
_EOF_
```

# 自動インストール対象マシンの設定
自動インストール対象マシンは`PXEブート`できるようにしておけば基本的には設定は必要ありません。

但し、インストールディスクに既にOSがインストールされているような場合は各種BIOSの起動デバイス選択から`PXEブート`が先になるように変更します。

`VirtualBox`の場合、仮想ストレージが空の状態であれば、以下のように`起動順序`で`ネットワーク`にチェックされていることを確認すれば問題ありません。

![01_boot.jpg](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/569912/132ce3fd-f000-5fb4-a2de-b1ba3ba9556d.jpeg)

# 自動インストール
自動インストール対象マシンの電源を入れることで`ネットワークインストール`が始まります。

あとは待つだけなので気長に待ちましょう。

# まとめ
`Ubuntu Server 20.04`で実装された機能であるため、情報が少なく苦労しましたが、何とか自動インストールできるところまでできてホッとしました。

これで`Ubuntu Server`構築の自動化が捗りそうです。

# 参考
https://ubuntu.com/server/docs/install/autoinstall
https://gihyo.jp/admin/serial/01/ubuntu-recipe/0615
https://discourse.ubuntu.com/t/automated-server-installs/16612?_ga=2.77481941.1164907437.1596334333-228679426.1592779869
https://docs.oracle.com/cd/E77565_01/install/ol7-install-pxe-boot-bios.html