Ubuntu Weekly Recipe

第787回PXEでサーバーの完全自動インストールを行う

今回は、Ubuntu Serverの完全自動インストール方法を紹介します。

PXEブートを利用した完全自動インストール

サーバーの自動インストール自体は第615回で紹介済みですが、ごく僅かではあるものの、対話での入力が必要な箇所が存在していたり、イメージファイルを書き込んだUSBスティックをインストール先のマシンに挿しておく必要があるため、完全な自動化には至っていませんでした。複数台のマシンに対するインストールや、サーバールームなどの日常作業を行っている場所とは離れた場所に設置されたマシンに対するインストールでは対話作業の手間が大きくなるため、せっかく自動インストールを導入した恩恵が得られなくなってしまいます。そのため、このような環境下で自動化の恩恵を十分に受けるためには、インストール作業を完全自動で行わせる必要が出てきます。

完全自動インストールは、自動インストールサーバーと、インストール対象のマシンのPXEブートを使用します。

自動インストール作業は以下の順番で行われます。

  1. インストール対象のマシンがPXEブートし、DHCPリクエストを送信する。
  2. 自動インストールサーバーのDHCPサーバーが一時的なIPアドレスを割り当て、ブートローダーの位置を教える。
  3. マシンが、自動インストールサーバーのTFTPサーバーに置かれたブートローダーやブート設定ファイル、カーネル、初期RAMディスクなどをダウンロードし、自動インストール(用OS)を起動する。
  4. マシンが、自動インストールサーバーのwebサーバーに置かれた自動インストール設定ファイルや、インストールメディアをダウンロードして、自動インストールを実施する。

自動インストールサーバーの構築

つまり、自動インストールサーバーには以下の機能が必要です。

  • インストール対象マシンの自動インストール中に一時的なIPアドレスを割り当てるDHCPサーバー
  • マシンにブートローダーやカーネルをダウンロードさせるためのTFTPサーバー
  • マシンに自動インストール設定ファイルやインストールメディアをダウンロードさせるためのwebサーバー

この項では、これらの機能を持ったサーバーを構築します。

dnsmasq(DHCPサーバー兼TFTPサーバー)のインストール

DHCPサーバーとTFTPサーバーとしてdnsmasqを自動インストールサーバーにインストールします。また、TFTPサーバーのルートディレクトリとして/tftpbootディレクトリを作成します。

$ sudo apt install dnsmasq
$ sudo mkdir /tftpboot

続いてdnsmasqにDHCPサーバー兼TFTPサーバーの設定を行います。

$ sudo tee /etc/dnsmasq.conf <<'EOF'
interface=eno1 # dnsmasqをlistenさせるインターフェイス名
bind-interfaces

# DNSサーバー機能を無効化
port=0

# TFTPサーバー機能を有効化
enable-tftp
tftp-root=/tftpboot

# DHCPサーバーの設定
dhcp-leasefile=/var/lib/misc/dnsmasq.leases
dhcp-option=option:domain-name,"example.com"  # ドメイン名
dhcp-option=option:router,192.168.10.1 # ルータのIPアドレス
dhcp-option=option:netmask,255.255.255.0 # サブネットマスク
dhcp-option=option:dns-server,192.168.10.11,192.168.10.12 # DNSサーバーのIPアドレス
dhcp-match=set:efi-x86_64,option:client-arch,7 # EFI bytecode
dhcp-match=set:efi-x86_64,option:client-arch,9 # EFI x86-64
dhcp-boot=tag:efi-x86_64,"/grubnetx64.efi"
dhcp-match=set:bios,option:client-arch,0 # Intel x86PC
dhcp-boot=tag:bios,"pxelinux.0"

dhcp-range=192.168.10.0,static # ネットワークアドレス
EOF

各設定のポイントです。

# UEFI PXEブート用設定
dhcp-match=set:efi-x86_64,option:client-arch,7 # EFI bytecode
dhcp-match=set:efi-x86_64,option:client-arch,9 # EFI x86-64
# UEFI boot時のブートローダー設定
dhcp-boot=tag:efi-x86_64,"/grubnetx64.efi"
# BIOS PXEブート用設定
dhcp-match=set:bios,option:client-arch,0 # Intel x86PC
# grub boot時のブートローダー設定
dhcp-boot=tag:bios,"pxelinux.0"

自動インストールサーバーは、インストール対象マシンのアーキテクチャーによって適切なブートローダーを提供する必要があります。PXEブート時、マシンはRFC4578に従ってアーキテクチャーのタイプをヘッダーに設定してDHCPリクエストを送信するため、それを提供するブートローダーの条件分岐に使用します[1]

dhcp-range=192.168.10.0,static # ネットワークアドレス

今回、各マシンのIPアドレス割当設定は個別に設定します。しかし、dhcp-rangeを定義しないとDHCPサーバー機能が動かないため、⁠dnsmasqが存在しているネットワークに関してはすべて静的にIPアドレスを設定する」エントリを定義する必要があります。

dnsmasqの設定が完了したら、一度再起動を行います。

$ sudo systemctl restart dnsmasq.service

ブートローダーの設置

まず、BIOSブート用のMBRブートローダー(syslinux)と、コアモジュールをTFTPサーバーに設置します。

$ sudo apt install pxelinux syslinux
$ sudo cp /usr/lib/syslinux/modules/bios/ldlinux.c32 /tftpboot/
$ sudo cp /usr/lib/PXELINUX/pxelinux.0 /tftpboot/

続いて、UEFIブート用のブートローダー(grub)をTFTPサーバーに設置します[2]

$ sudo wget -O /tftpboot/grubnetx64.efi http://archive.ubuntu.com/ubuntu/dists/jammy/main/uefi/grub2-amd64/current/grubnetx64.efi

最後に各インストール対象マシンごとのブート設定ファイル置き場を作成し、UEFIブート時のメインのブート設定ファイルを設置します(この設定ファイルが必要な理由は後述します⁠⁠。

$ sudo mkdir -p /tftpboot/grub/system
$ sudo mkdir -p /tftpboot/pxelinux.cfg
$ sudo tee /tftpboot/grub/grub.cfg <<'EOF'
set timeout=2

loadfont unicode

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

if [ -s "${prefix}/system/${net_default_mac}" ]; then
  source "${prefix}/system/${net_default_mac}"
  echo "Machine specific grub config file ${prefix}/system/${net_default_mac} loaded"
else
  echo "Could not find machine specific grub config file ${prefix}/system/${net_default_mac}"
  sleep 30
fi
EOF

Nginx(Webサーバー)のインストール

WebサーバーとしてNginxを自動インストールサーバーにインストールします。

$ sudo apt install nginx

インストール対象マシンから、http://自動インストールサーバー/autoinstallで自動インストール設定ファイル、http://自動インストールサーバー/isoでインストールメディアが取得できるように設定します。

まず、置き場となるディレクトリを作成します。

$ sudo mkdir /var/www/autoinstall /var/www/iso

続いて、/etc/nginx/sites-available/default のserver句にlocation設定を追加します。

server {

...

        location / {
                # First attempt to serve request as file, then
                # as directory, then fall back to displaying a 404.
                try_files $uri $uri/ =404;
        }

        location /autoinstall {
                root /var/www/;
                autoindex on;
        }

        location /iso {
                root /var/www/;
                autoindex on;
        }

...

}

設定を追加したら、反映のためにNginxをreloadします。

$ sudo systemctl reload nginx.service

インストール用ディストリビューションの用意

今回は、Ubuntu 22.04.3 LTSを自動インストールさせます。

まず、インストール用ISOファイルをダウンロードします。

$ wget https://releases.ubuntu.com/jammy/ubuntu-22.04.3-live-server-amd64.iso

ISOファイルをマウントして、その中にあるカーネルと初期RAMディスクを抽出してTFTPサーバーに設置します。

抽出が完了したら、ISOファイルをアンマウントして、Webサーバーのインストールメディア置き場に設置します。

$ sudo mkdir -p /tftpboot/images/jammy
$ sudo cp /mnt/casper/initrd /mnt/casper/vmlinuz /tftpboot/images/jammy/
$ sudo umount /mnt
$ sudo mv ubuntu-22.04.3-live-server-amd64.iso /var/www/iso/

これで、自動インストールサーバーとしての最低限の設定は完了で、インストール対象マシン個別の設定を行っていくことになります。

自動インストールの設定

自動インストールの設定ですが、BIOSブートと、UEFIブートで必要な設定ファイルのパスや様式が若干異なります。以下ではそれぞれに対して個別に説明します。

なお、以下の説明ではインストール対象マシンを08:00:27:84:bd:feのMACアドレスを持つNICからPXEブートさせることを前提とします。

BIOSブートの場合

TFTPサーバーへ自動インストールを行わせるためのブート設定ファイルを設置します。

設定ファイルの名前は、ブートローダーによって固定化されていて、01-MACアドレスの様式である必要があります。そして、MACアドレスの表記は、オクテットごとに-で分け、a-fは小文字である必要があります。今回のケースでは、01-08-00-27-84-bd-feである必要があり、01:08:00:27:84:bd:fe01-08-00-27-84-BD-FEではダウンロードに失敗します。

sudo tee /tftpboot/pxelinux.cfg/01-08-00-27-84-bd-fe <<'EOF'
default linux
prompt 0
timeout 30
label linux
        kernel /images/jammy/vmlinuz
        ipappend 2
        append initrd=/images/jammy/initrd autoinstall ip=dhcp url=http://自動インストールサーバーのIPアドレス/iso/ubuntu-22.04.3-live-server-amd64.iso ds=nocloud-net;s=http://自動インストールサーバーのIPアドレス/autoinstall/08:00:27:84:bd:fe/ ---
EOF

appendに設定されていることの意味は第615回で説明されていることと一部重複しますが、ここでも改めて説明します。

  • 「autoinstall⁠」⁠:cloud-configファイルの中にautoinstallキーが存在しているとき、ユーザーの操作なしに自動インストールを開始するためのオプション。
  • 「ip=dhcp」⁠:DHCPで一時的なIPアドレスを割り当てるオプション。
  • 「url=…」⁠:インストールメディアの場所を指定するためのオプション。ここでは、先程Webサーバーに設置したUbuntu22.04.3のISOファイルのパスを指定しています。
  • 「ds=nocloud-net;s=…⁠」⁠:cloud-configファイルの場所(データストア)を指定するためのオプション。これから、この場所に設定ファイルを設置します。

続いて、自動インストールのための設定ファイルをWebサーバーに設置します。

ファイル置き場として、/var/www/autoinstall/MACアドレスディレクトリを作成します。ここでのMACアドレスの表記は、オクテットごとに:で分け、a-fは小文字である必要があります。

$ sudo mkdir /var/www/autoinstall/08:00:27:84:bd:fe

MACアドレスの名前のディレクトリを作成しているのは、複数マシンの設定ファイルを設置するための便宜です。すべてのマシンで同一の設定ファイルで良いのであれば/var/www/autoinstall/以下にファイルを設置で問題ないのですが、IPアドレスの静的設定など、各マシンで設定ファイルの内容に個性を出す必要がある場合はマシンごとに別な設定ファイルを用意する必要があります。しかし、user-datameta-dataというファイル名自体は任意のものに変更できないため、各マシンごとの設定を識別できるものとしてMACアドレスのディレクトリを作成して、その下に設定ファイルを設置する形式を採っています[3]

ファイル置き場にcloud-configフォーマットのファイルuser-dataとuser-dataの情報を記述するmeta-dataファイルを設置します。meta-dataファイルは空ファイルで問題ありませんが、存在しないと自動インストールに失敗します。

$ sudo tee /var/www/autoinstall/08:00:27:84:bd:fe/user-data <<'EOF'
#cloud-config
autoinstall:
  version: 1
  identity:
    hostname: ubuntu-server
    username: ubuntu
    password: "$6$/X6MRgjz4jCIK8.G$FhJbD17m9qTcMA8FHMPcFvp7v2wvgmRBdvdEdTiZXZRwuZFUVsear9.vYY01QcwPuYAMRMvSJoJKfUlaBviU3/"
  ssh:
    install-server: yes
EOF
$ sudo touch /var/www/autoinstall/08:00:27:84:bd:fe/meta-data

設定ファイルはYAML形式です。ただし、ファイルの先頭に#cloud-configを必ず付ける必要があります。個別の設定値の説明は公式のAutomated Server installer config file referenceを参照してください。

今回は次のような設定を行っています。

  • ホスト名を「ubuntu-server」にする
  • ユーザー名を「ubuntu」にする
  • パスワードを「ubuntu」にする[4]
  • sshサーバーをインストールする

最後にdnsmasqへ、インストール対象マシンのDHCPエントリを追加します。

$ sudo tee -a /etc/dnsmasq.conf <<'EOF'
dhcp-host=08:00:27:84:bd:fe,192.168.118.161,ubuntu-server
EOF
$ sudo systemctl restart dnsmasq.service

この設定で、インストール対象マシンから(手動操作が入ってしまいますが)電源投入直後のブート画面でPXEブートを指定するか、サーバーマシンの場合はIPMIからSSH、HTTPRedfishなどを使用してPXEブートを実行させれば自動インストールが開始されます。

自動インストール完了後、自動でrebootし、インストールされたOSが起動します。

UEFIブートの場合

BIOSブートの場合と同じに、TFTPサーバーへ自動インストール設定行わせるためのブート設定ファイルを設置します。

ただし、ファイルのパスやファイル名がBIOSブートとは異なります。

PXEブート時に/tftpboot/grub/grub.cfgをロードすることが、ブートローダーによって固定化されています。

このままではインストール対象マシンごとのカーネルコマンドラインや、初期ramディスクの設定ができません。そこで、grub.cfg(メインのブート設定ファイル)はTFTPサーバーのインストール時、各マシン用の設定ファイルを/tftpboot/grub/system/${net_default_mac}からロードするように設定を施します。

${net_default_mac}はPXEブートしたマシンのMACアドレスです。

すなわち、マシンごとの設定ファイルの名前は、/tftpboot/grub/system/MACアドレスである必要があります[5]

MACアドレスの表記は、オクテットごとに:で分け、a-fは小文字である必要があります。

$ sudo tee /tftpboot/grub/system/08:00:27:84:bd:fe <<'EOF'
menuentry "AutoInstall Ubuntu Server (jammy)" {
        set gfxpayload=keep
        linux   /images/jammy/vmlinuz autoinstall ip=dhcp url=http://自動インストールサーバーのIPアドレス/iso/ubuntu-22.04.3-live-server-amd64.iso ds=nocloud-net\;s=http://自動インストールサーバーのIPアドレス/autoinstall/${net_default_mac}/ ---
        initrd  /images/jammy/initrd
}
EOF

続いて、自動インストールのための設定ファイルをWebサーバーに設置します。ファイルの置き場所や様式、内容はBIOSブートの場合と基本的に同一なのですが、追加の設定が必要になります。

UEFIブートの場合、デフォルトでは自動インストール中にBIOS設定を更新して、最初のブートデバイスをNIC(からのPXEブート)に変更する振る舞いをします。

この振る舞いは、MAASの自動インストール機能との兼ね合いに依るものなのですが、今回のケースではPXEブートと自動インストールが永遠に繰り返されてしまうことになるため、無効化する必要があります。

具体的にはuser-dataautoinstall.storage中にあるgrub.uefi_reorder設定をfalseに設定します。ただし、uefi_reorderは、storageで暗黙に定義されているlayoutキー(値としてはlvmが指定されている)には反応せず、任意のパーティショニング設定を行うconfigキーにのみ反応する振る舞いをします

まとめると、自動インストールに最初のブートデバイスをNICにさせないためには以下の設定が必要になります。

  • autoinstall.storate.grub.uefi_reorderfalseにする。
  • autoinstall.storage.configに明示的なパーティショニング設定をする。

autoinstall.storage.configは、CurtinのStorage設定を直接記載します。

以下が、先頭にEFIシステムパーティション(ESP⁠⁠、次にスワップ領域32GiB[6]、最後に余った全領域をルートファイルシステムに割り当てる場合のパーティショニング設定です。

#cloud-config
autoinstall:
  version: 1
  ...
  storage:
    version: 2
    grub:
      # ブートオーダーを更新させない
      reorder_uefi: false
    # パーティショニング設定。config句で設定しないとreorder_uefiの設定が反映されない
    config:
      # パーティションテーブルの作成
      - type: disk
        id: sda
        ptable: gpt
        path: /dev/sda
        wipe: superblock
        preserve: false
        name: ''
        grub_device: false

      # パーティションの作成
      # ESP
      - type: partition
        id: sda1
        device: sda
        number: 1
        flag: boot
        wipe: superblock
        preserve: false
        offset: 1073741824 # 1GiB
        size: 1073741824   # 1GiB; 末尾は先頭から2GiB
        grub_device: true
      # スワップ
      - type: partition
        id: sda2
        device: sda
        number: 2
        flag: swap
        wipe: superblock
        preserve: false
        offset: 2147484160 # 前のパーティションの末尾+512バイト => 2GiB+512
        size: 34359738368  # 32GiB; 末尾は先頭から34GiB+512
        grub_device: false
      # ルートファイルシステム
      - type: partition
        id: sda3
        device: sda
        number: 3
        wipe: superblock
        preserve: false
        offset: 36507223040 # 前のパーティションの末尾+512バイト => 34GiB+512+512
        size: -1            # -1で100%指定
        grub_device: false

      # ファイルシステムの作成
      # ESP
      - type: format
        id: fs-sda1
        volume: sda1  # パーティションの作成で設定したidを指定する
        fstype: fat32 # ESPはfat32でフォーマットする
        preserve: false
      # スワップ
      - type: format
        id: fs-sda2
        volume: sda2
        fstype: swap # スワップ領域はswapを指定する
        label: swap
        preserve: false
      # ルートファイルシステム
      - type: format
        id: fs-sda3
        volume: sda3
        fstype: ext4
        preserve: false

      # マウントポイント
      # ESP
      - type: mount
        id: mount-efi
        device: fs-sda1 # ファイルシステムの作成で設定したidを指定する
        path: /boot/efi
      # スワップ
      - type: mount
        id: mount-swap
        device: fs-sda2
        path: none      # スワップ領域はnoneを指定する
      # ルートファイルシステム
      - type: mount
        id: mount-root
        device: fs-sda3
        path: /

必要な設定項目は多いですが、⁠空ディスクにファイルシステムを作成する際に必要な作業をYAML形式で書き下している」と考えると理解しやすいのではないでしょうか。

上記の設定を含んだuser-dataと、空ファイルmeta-data/var/www/autoinstall/MACアドレス/へ設置し、dnsmasqへのDHCPエントリを追加すれば、UEFIブートマシンでも自動インストールが可能になります。

$ sudo mkdir /var/www/autoinstall/08:00:27:84:bd:fe
$ sudo tee /var/www/autoinstall/08:00:27:84:bd:fe/user-data <<'EOF'
#cloud-config
autoinstall:
  version: 1
  identity:
    hostname: ubuntu-server
    username: ubuntu
    password: "$6$/X6MRgjz4jCIK8.G$FhJbD17m9qTcMA8FHMPcFvp7v2wvgmRBdvdEdTiZXZRwuZFUVsear9.vYY01QcwPuYAMRMvSJoJKfUlaBviU3/"
  ssh:
    install-server: yes
  storage:
    version: 2
    grub:
      reorder_uefi: false
    config:
      ...
EOF
$ sudo touch /var/www/autoinstall/08:00:27:84:bd:fe/meta-data
$ sudo tee -a /etc/dnsmasq.conf <<'EOF'
dhcp-host=08:00:27:84:bd:fe,192.168.118.161,ubuntu-server
EOF
$ sudo systemctl restart dnsmasq.service

おすすめ記事

記事・ニュース一覧