手当たり次第に書くんだ

飽きっぽいのは本能

Ubuntu 22.04 PXE と Autoinstall を使用したインストールの自動化

目次に戻る

Overview

PXE と Autoinstall を使用して Ubuntu のインストールを自動化します。本稿では UEFI のみを対象としています。PXE の仕組みはさまざまな要素が複合的に動作するため、ある程度の経験のあるエンジニアでないと構築そのものが難しい可能性もあります。

PXE

PXE (Preboot Execution Environment) は、コンピューターの起動時にネットワークを介して自動的に OS やその他のソフトウェアをインストールするための標準化されたプロセスです。RFC 2131, 4578 などで標準化されています。PXE を使用すると、コンピューターは特別な PXE ブート ROM を介してネットワークに接続し、DHCP サーバーから IP アドレスを取得し、PXE サーバーから起動イメージをダウンロードします。これにより、ハードディスクに OS がインストールされていない新しいコンピューターでも、ネットワーク経由で OS のインストールやシステムのセットアップを自動化することができます。PXE は、大規模なデプロイメントや管理で時間と手間を節約するために広く使用されています。

PXE サーバーは主に以下のコンポーネントから構成されます。

  • DHCP サーバー: PXE boot 対象のデバイスにネットワーク設定をするとともに、後続の参照先 TFTP サーバーとブートローダーのファイル名を対象デバイスに伝えます。
  • TFTP サーバー: Linux の boot に必要となる vmlinuz, initrd, grub.cfg, UEFI boot loader などを配置します。対象デバイスはこれらのファイルを参照して起動します。
  • Web サーバー: ISO ファイル、Autoinstall の設定ファイルなどを配置します。対象デバイスはこれらのファイルを参照して OS の自動インストールを開始します。

Autoinstall

Autoinstall は、Ubuntu のインストールプロセスを自動化するための仕組みで、内部的には cloud-init が使用されています。この機能を使用すると、ユーザーは手動で OS をインストールする必要なく、事前に定義された設定ファイルを使用して、インストール手順やシステム構成を定義することができます。この設定ファイルには、ネットワーク設定、パーティショニング、ソフトウェアの選択、ユーザーアカウントの設定などの情報が含まれています。これにより、大規模な環境での一貫したデプロイメントや、繰り返しの作業を自動化することが可能になります。

前提条件

  • こちらを参考に DHCP サーバーの構築が完了していること。「PXE boot 用の設定」を参照して下さい。
  • こちらを参考に TFTP サーバーの構築が完了していること。
  • こちらを参考に Web サーバーの構築が完了していること。
  • 本稿では同一ホスト内で DHCP, TFTP, Web サーバーが稼働していることを前提に説明しています。別ホストになる場合は適宜読み替えて下さい。

ISO イメージの配置

iso ディレクトリを作成し、ISO イメージを配置します。ISO イメージはこちらからダウンロードして下さい。

myadmin@ubuntu:~$ sudo mkdir /var/www/html/iso
myadmin@ubuntu:~$ ls -l /var/www/html/iso/ubuntu-22.04.3-live-server-amd64.iso

vmlinuz, initrd, grub.cfg の抽出と配置

ISO イメージをマウントします。

myadmin@ubuntu:~$ sudo mount /var/www/html/iso/ubuntu-22.04.3-live-server-amd64.iso /mnt

必要なディレクトリを作成します。

myadmin@ubuntu:~$ sudo mkdir -p /srv/tftp/{grub,casper}

必要なファイルをを TFTP のルートディレクトリにコピーします。grub.cfg は後で書き換える為、一旦、名前を変更してコピーしています。

myadmin@ubuntu:~$ sudo cp /mnt/boot/grub/grub.cfg /srv/tftp/grub/grub.cfg.sample
myadmin@ubuntu:~$ sudo cp /mnt/casper/{vmlinuz,initrd} /srv/tftp/casper

ISO イメージのマウントを解除します。

myadmin@ubuntu:~$ sudo umount /mnt

grub.cfg.sample をベースに grub.cfg を作成します。grub.cfg の書き方は、各々こだわりがあるかもしれませんが、以下の例では、GRUB のメニューから対象デバイスを選択することで、適用する Autoinstall ファイルを分けられる設定としています。特に Autoinstall ファイルを分ける必要性がない場合は、一つにまとめて良いでしょう。

myadmin@ubuntu:~$ sudo tee /srv/tftp/grub/grub.cfg <<EOF
set timeout=30
loadfont unicode
set menu_color_normal=white/black
set menu_color_highlight=black/light-gray
set web_server=10.1.0.80
set iso_url=http://${web_server}/iso/ubuntu-22.04.3-live-server-amd64.iso
set autoinstall_url=http://${web_server}/autoinstall
menuentry "PXE boot autoinstall ubuntu1" {
    set gfxpayload=keep
    linux /casper/vmlinuz ip=dhcp url=${iso_url} autoinstall cloud-config-url=${autoinstall_url}/ubuntu1.yaml
    initrd /casper/initrd
    }
menuentry "PXE boot autoinstall ubuntu2" {
    set gfxpayload=keep
    linux /casper/vmlinuz ip=dhcp url=${iso_url} autoinstall cloud-config-url=${autoinstall_url}/ubuntu2.yaml
    initrd /casper/initrd
    }
menuentry "PXE boot autoinstall ubuntu3" {
    set gfxpayload=keep
    linux /casper/vmlinuz ip=dhcp url=${iso_url} autoinstall cloud-config-url=${autoinstall_url}/ubuntu3.yaml
    initrd /casper/initrd
    }
grub_platform
if [ "$grub_platform" = "efi" ]; then
    menuentry 'Boot from next volume' {
        exit 1
    }
    menuentry 'UEFI Firmware Settings' {
        fwsetup
    }
else
    menuentry 'Test memory' {
        linux16 /boot/memtest86+.bin
    }
fi
EOF

ブートローダーの配置

UEFI ブートローダーを配置します。ここまでで TFTP サーバーの準備は完了です。この情報はこちらを参考にしました。

myadmin@ubuntu:~$ sudo wget -O /srv/tftp/grubnetx64.efi.signed http://archive.ubuntu.com/ubuntu/dists/jammy/main/uefi/grub2-amd64/current/grubnetx64.efi.signed

Autoinstall

Autoinstall ファイルの作成前に、対象デバイスに手動インストールを行い、必要な情報(ネットワークインターフェイス名、ストレージデバイス名など)を入手しておくことが重要です。インストール後は、Autoinstall ファイルのテンプレートとして /var/log/installer/autoinstall-user-data が作成されますので、それを参考にすると良いでしょう。

myadmin@ubuntu:~$ cat /var/log/installer/autoinstall-user-data

Autoinstall ファイルを配置するディレクトリを作成します。

myadmin@ubuntu:~$ sudo mkdir /var/www/html/autoinstall

Autoinstall ファイルに記載する管理者パスワードのハッシュを生成します。

myadmin@ubuntu:~$ openssl passwd -6 -salt $(openssl rand -hex 8) 'password'
  • -6: SHA-512 アルゴリズムを使用してパスワードのハッシュを生成します。
  • -salt $(openssl rand -hex 8): 8 バイトのランダムな 16 進数文字列 (solt) を生成します。
  • ‘password’ を実際のパスワードとして指定しています。

autoinstall-user-data をベースに Autoinstall ファイルを作成します。この例は前述の grub.cfg の ubuntu1 を想定しており、ubuntu1 は KVM を想定したパーティション構成となっています。

myadmin@ubuntu:~$ sudo tee /var/www/html/autoinstall/ubuntu1.yaml <<EOF
#cloud-config
autoinstall:
  apt:
    disable_components: []
    fallback: abort
    geoip: true
    mirror-selection:
      primary:
      - country-mirror
      - arches:
        - amd64
        - i386
        uri: http://archive.ubuntu.com/ubuntu
      - arches:
        - s390x
        - arm64
        - armhf
        - powerpc
        - ppc64el
        - riscv64
        uri: http://ports.ubuntu.com/ubuntu-ports
    preserve_sources_list: false
  codecs:
    install: false
  drivers:
    install: false
  identity:
    hostname: ubuntu1
    # plain text: password, openssl passwd -6 -salt $(openssl rand -hex 8) 'password'
    password: xxxxxxxx
    realname: myadmin
    username: myadmin
  kernel:
    package: linux-generic
  keyboard:
    layout: jp
    toggle: null
    variant: ''
  locale: en_US.UTF-8
  network:
    ethernets:
      eno1:
        dhcp4: true
    version: 2
  source:
    id: ubuntu-server
    search_drivers: false
  ssh:
    allow-pw: true
    authorized-keys: [ssh-ed25519 xxxxxxxx myadmin@ubuntu]
    install-server: true
  storage:
    config:
    # /dev/sda
    - ptable: gpt
      path: /dev/sda
      wipe: superblock-recursive
      preserve: false
      name: ''
      grub_device: false
      type: disk
      id: d-sda
    # sda1, /boot/efi
    - device: d-sda
      size: 1G
      wipe: superblock
      flag: boot
      number: 1
      preserve: false
      grub_device: true
      type: partition
      id: p-sda1
    - fstype: fat32
      volume: p-sda1
      preserve: false
      type: format
      id: f-sda1
    - path: /boot/efi
      device: f-sda1
      type: mount
      id: m-sda1
    # sda2, /boot
    - device: d-sda
      size: 2G
      wipe: superblock
      number: 2
      preserve: false
      grub_device: false
      type: partition
      id: p-sda2
    - fstype: ext4
      volume: p-sda2
      preserve: false
      type: format
      id: f-sda2
    - path: /boot
      device: f-sda2
      type: mount
      id: m-sda2
    # sda3, vg0
    - device: d-sda
      size: -1
      wipe: superblock
      number: 3
      preserve: false
      grub_device: false
      type: partition
      id: p-sda3
    - name: vg0
      devices:
      - p-sda3
      preserve: false
      type: lvm_volgroup
      id: vg0
    # vg0, root
    - name: root
      volgroup: vg0
      size: 20G
      wipe: superblock
      preserve: false
      type: lvm_partition
      id: p-root
    - fstype: ext4
      volume: p-root
      preserve: false
      type: format
      id: f-root
    - path: /
      device: f-root
      type: mount
      id: m-root
    # vg0, var
    - name: var
      volgroup: vg0
      size: 10G
      wipe: superblock
      preserve: false
      type: lvm_partition
      id: p-var
    - fstype: ext4
      volume: p-var
      preserve: false
      type: format
      id: f-var
    - path: /var
      device: f-var
      type: mount
      id: m-var
    # vg0, home
    - name: home
      volgroup: vg0
      size: 40G
      wipe: superblock
      preserve: false
      type: lvm_partition
      id: p-home
    - fstype: ext4
      volume: p-home
      preserve: false
      type: format
      id: f-home
    - path: /home
      device: f-home
      type: mount
      id: m-home
    # vg0, /var/lib/libvirt/images
    - name: var_lib_libvirt_images
      volgroup: vg0
      size: -1
      wipe: superblock
      preserve: false
      type: lvm_partition
      id: p-var_lib_libvirt_images
    - fstype: ext4
      volume: p-var_lib_libvirt_images
      preserve: false
      type: format
      id: f-var_lib_libvirt_images
    - path: /var/lib/libvirt/images
      device: f-var_lib_libvirt_images
      type: mount
      id: m-var_lib_libvirt_images
  updates: security
  version: 1
EOF

主な変数を以下に示します。

  • hostname: ホスト名を設定します。
  • password: ハッシュした管理者パスワードを設定します。
  • realname, username: 管理者のユーザー名を設定します。
  • network: 対象デバイスのインターフェイス名を設定します。この時点で固定 IP アドレスを設定することも可能ですが、本稿の例では DHCP としています。インターフェイス名が異なると Autoinstall は失敗します。完全一致ではない書き方も可能ではあります。
  • authorized-keys: SSH の公開鍵を設定しています。
  • storage: パーティション、LVM の設定です。Autoinstall の設定で一番面等なのがこの設定でしょう。この例は筆者が見やすく書きやすい状態としていますが、見る人によっては見づらいかもしれません。とにかく、どのような構造で書かれているかをまずは理解することが重要です。YAML をフロー形式で記載することも見やすくする選択肢になるかもしれません。この設定もデバイス名が異なると Autoinstall は失敗します。

自動インストールの確認

ここまでで PXE を使用した自動インストールが可能な状態となっています。PXE ブート可能なデバイスを起動して確認しましょう。UEFI での PXE ブート設定は、各デバイスの BIOS に依存しますので、それぞれのマニュアルなどを参考にして下さい。

補足

  • KVM の virt-install では、Autoinstall ファイルを指定して読み込ませることができるため、PXE 環境は不要となります。
  • 22.04.2 あたりから Autoinstall の指定方法がおそらく変わっています。それ以前は metadata, userdata として指定が必要でしたが、その方式ではうまくいかなくなりました。本稿の例は 22.04.3 で確認しています。

最後に

冒頭にも述べましたが、PXE の仕組みは複合的で複雑であるため、デバッグを含めた検証にもかなり時間を使いました。もし参考になりましたら、コメントを頂けますと励みになります。

目次に戻る

Ubuntu 22.04 PXE と Autoinstall を使用したインストールの自動化

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です

日本語が含まれない投稿は無視されますのでご注意ください。(スパム対策)

トップへ戻る