自作PXE(DHCP/TFTP/HTTP)サーバでOS自動インストール Ubuntu 24.04編
この記事について
この記事ではPXE(DHCP/TFTP/HTTP)サーバを使ってOSの自動インストールを実施するために必要な作業や知識について解説します
学習のために執筆しているためAIは使用しません
環境
使用したPXE(DHCP/TFTP/HTTP)サーバ(自作)
使用したハードウェア(2台)- サーバ:intel NUC 12
- クライアント:intel NUC 12
インストールするOS:Ubuntu 24.04.2
PXEによるOSインストール概要
ブート方法にPXEを選択している場合、コンピュータの電源を入れると起動に必要な情報を取得するためにNICからDHCP通信が開始されます
起動に必要な情報がそろったらコンピュータはTFTPでブートローダをダウンロードし、ブートローダはカーネルと初期RAMイメージを起動してOSのインストールを実施します
本記事におけるOSインストール
前述のOSインストールを今回の条件で書き下すと上記のようになります
それぞれ見ていきます
UEFI->NIC->bootx64.efi->grubx64.efi
1. ブートローダの起動:1.1 UEFI Secure Boot
2025年現在のUEFIによる起動は主にUEFI Secure Bootと呼ばれる機能を使用します
詳細はUEFI仕様[1-1]を参照してください
近年のハードウェアは署名を持つ信頼できるブートローダを起動することが求められています
署名を検証するには信頼できる証明書が必要なため、ハードウェアは出荷時点で信頼できる証明書を内部に埋め込む必要があります
現実的には多くのハードウェアにはマイクロソフトの証明書が埋め込まれており、マイクロソフトがビルドしたバイナリが起動可能です
この方法にはデメリットがあり、ハードウェアに証明書を埋め込むことのできるマイクロソフト以外のベンダは実質的にブートローダを開発できなくなる可能性を含んでいます
これではRedHatもCanonicalも困ってしまうので対策として信頼できるベンダの証明書を含んだ軽量なブートローダであるshimが提供されています[1-3]
shimは各ベンダにより署名されたブートローダを取得し、grub${ARCH}.efiを起動します
1.2 PXE
PXEはintelによって策定されたネットワークブートの仕様です
詳細は仕様を参照してください[1-4]
PXEではDHCPサーバとBoot Serverが分離している環境を想定しています
クライアントはDHCPを使ってブート用設定を受け取りDHCPオプションに含まれる各種情報に従ってブートローダをダウンロードします
ただし、DHCPサーバの応答にPXE用のDHCPオプションが存在しない場合はRFCで定められたDHCP情報からブートします
今回はDHCPサーバとBoot Serverを同一の構成としてPXEのDHCPオプションは使用しません
そのため、今回は正確にはPXEではなくただのDHCPによるブートになります
DHCPに存在するfileという項目[1-5]を正しく渡せばブート可能です
1.3 設定方法
UEFI
コンピュータの起動時に適当なファンクションキーを押せばUEFIの設定変更プログラムが起動します
今回対象としたIntel NUCではF2キーです
Boot用の項目がどこかにあるはずなのでPXEで起動するように変更します
BMC(Baseboard Management Controller)などハードウェア管理用の制御機構がある場合はそちらを使用してください
DHCP
使用しているDHCPサーバの設定に合わせてfileを設定してください
今回の自作DHCPではソースコードにハードコーディングしています
TFTP
shim(bootx64.efi)とgrubはインストールしたいisoファイルから取得します
通常のgrubはPXE機能が入っていないのでPXE機能が入っているgrubnetを使用します
wget https://releases.ubuntu.com/noble/ubuntu-24.04.2-live-server-amd64.iso
mount -o loop,ro ubuntu-24.04.2-live-server-amd64.iso /mnt
ar vx /mnt/pool/main/g/grub2-signed/grub-efi-amd64-signed_1.202.2+2.12-1ubuntu7.1_amd64.deb
tar xvf data.tar.zst
mkdir -p /EFI/boot/
cp /mnt/EFI/boot/bootx64.efi /EFI/boot/bootx64.efi
cp ./usr/lib/grub/x86_64-efi-signed/grubnetx64.efi.signed /EFI/boot/grubx64.efi
umount /mnt
1.4 不明点
- shimでPXEブートをしようとすると一番最初にrevocations.efiというファイルのダウンロードを試みますが、このrevocations.efiの役割は不明です
これは予想になってしまいますが、失効した証明書を処理する機能だと思います - PXEのブートローダにはSyslinux系統のブートローダが多く使われています。それらのブートローダの名前は大体の場合pxelinux.0になるのですが、pxelinux.0のファイル名をgrub${ARCH}.efiにした場合に正常に起動できるのかは不明です
これは予想になってしまいますが、起動不可だと思います。署名済みのSyslinux系統のブートローダが必要なはずですが、見つかっていません
1.5 参考
[1-1] UEFI Specifications
[1-2] UEFI Secure Boot と MIRACLE LINUX をブートさせるまで
[1-3] shim
[1-4] PXE Specification Version 2.1
[1-5] RFC 2131
grub64.efi->vmlinuz->initrd/init
2. カーネルの起動:2.1 GRUB
GRUBはOSを起動するための非常に多機能なブートローダです
Linuxに限らずWindowsも起動可能ですが、ここでは大雑把に説明します
詳しく知りたい方はマニュアルを参照してください[2-1]
GRUBではコマンドと呼ばれる単位で機能を設定します
今回の用途ではlinuxとinitrdだけ把握しておけば十分です
- linux file params...
linuxカーネルのファイル名とコマンドラインパラメータを指定する - initrd file
初期RAMディスクのファイル名
上記以外にも*.lstという形式で設定を記述することができますが、今回は使用しません
GRUBを起動すると/grub/grub.cfgから設定を読み込んで指定されたファイルをメモリに配置し、OSを起動します
2.2 vmlinuz
linuxカーネルは歴史的にvmlinuzというファイルに保存されています
このvmlinuzはカーネルの実態[2-2]であるvmlinuxを圧縮したファイルとvmlinuxを展開するためのプログラム[2-3]から構成されます
ブートローダからvmlinuzに処理が移行すると展開プログラムが実行されlinuxカーネルが起動します
起動したカーネルはカーネルと関係ないコマンドラインパラメータを/proc/cmdlineに書き出してinitrdの/initを実行します[2-4]
2.3 設定方法
grub.cfg
grub.cfgにvmlinuzとinitrdを設定します
mkdir /grub
cat << EOF > /grub/grub.cfg
set timeout=0
menuentry "Ubuntu" {
linux /casper/vmlinuz ip=dhcp url=http://<HTTPサーバ>/images/ubuntu-24.04.2-live-server-amd64.iso ds=nocloud-net\;s=http://<HTTPサーバ>/autoinstall/ autoinstall
initrd /casper/initrd
}
EOF
説明 | |
---|---|
set timeout=0 | ブートを開始する時間。未設定の場合はユーザ入力を待ち続ける。0の場合は即座に開始する |
menuentry "Ubuntu" | ブートの選択肢 |
ip=dhcp | IPアドレス設定(/init用の設定) |
url=... | ISOイメージのURL(/init用の設定) |
ds=...;s=... | cloud-initのdatasourceと設定ファイルのURL(後述) |
autoinstall | Subiquit用の設定(後述) |
vmlinuzとinitrd
vmlinuzとinitrdはインストールしたいISOから取得します
wget https://releases.ubuntu.com/noble/ubuntu-24.04.2-live-server-amd64.iso
mount -o loop,ro ubuntu-24.04.2-live-server-amd64.iso /mnt
mkdir /casper
cp /mnt/casper/vmlinuz /casper/vmlinuz
cp /mnt/casper/initrd /casper/initrd
umount /mnt
2.4 参考
[2-1] GNU GRUB Manual 2.12
[2-2] linux
[2-3] misc.c
[2-4] init/main.c
initrd/init->systemd->cloud-init,Subiquity
Ubuntuの起動:3.1 initrd
initrdはOSの様々な機能を設定するために必要なファイルをまとめたcpioアーカイブです
詳細はドキュメントを参照してください[3-1]
カーネルはinitrdをメモリ上に展開して/initを実行します
具体的な中身が確認したい場合は以下で確認可能です
wget https://releases.ubuntu.com/noble/ubuntu-24.04.2-live-server-amd64.iso
sudo mount -o loop,ro ubuntu-24.04.2-live-server-amd64.iso /mnt
unmkinitramfs /mnt/casper/initrd initrd/
/initはシェルスクリプトになっています
Ubuntuのインストール用のinitrdはインストール済みのものとは異なり/confに設定ファイルを持っていて/scripts/casperを起動するようになっています
このcasperは/proc/cmdlineを参照してurl=...に記載されている場所からwgetコマンドでisoファイルをダウンロードします
そしてisoファイルからsquashfsファイルを探してマウントします
/initは必要な設定を一通り実行したらrun-initコマンド[3-2]でsystemdを起動します
3.2 systemd
systemdは様々なシステムを管理するためのソフトウェアです
systemdはユニットファイルを読み込んでそこに記載されている設定に従ってシステムを管理します
ユニットファイルには依存関係を設定可能でsystemdはそれらをうまく処理して各サービスを起動します
今回はSnapd、cloud-init、Subiuityにだけ注目します
3.3 Snapd
Snapdはディストリビューション非依存のパッケージ形式であるsnapパッケージの管理サービスです
ディストリビューション非依存なので古いUbuntuで新しいパッケージを利用することも可能です
この特性を利用してOSのインストーラであるSubiquityをインストールするためにSnapdが利用されています
今回のUbuntuのインストールでもsystemdが立ち上がると即座にSnapdが起動し、ubuntu-server-minimal.squashfsからSubiquityのインストールを実行しています[根拠不足]
3.4 cloud-init
cloud-initはOSの初期設定を自動化してくれるツールです
UbuntuのインストールにおいてはSubiquityに設定ファイルを渡すことだけに注目すれば十分です
cloud-initはカーネルのコマンドラインパラメータを読み取って必要な設定ファイルの場所(datasource)を把握します
このとき、datasourceにNoCloudを指定するとurlで直接設定ファイルの置き場所を指定できます[3-3]
cloud-initは設定ファイルから中身を取得すると/run/cloud-init/combined-cloud-config.jsonに中身を書き出します[3-4]
今回のUbuntuインストールで必要な機能はこれだけです
注意点として設定ファイルはcloud-initを使用して取得するためmeta-dataとuser-data(またはvendor-data)の形式で記載する必要がありますが、実際にインストール処理を行うのはSubiquityであってcloud-initはOSのインストールを行いません
更なる詳細はドキュメントを参照してください[3-5]
3.5 Subiquity
SubiquityはOSのインストーラです
Ubuntuをインストールしたことがある方であれば必ず見たことのあるインストール画面はSubiquityによるものです
Subiquityはコマンドラインパラメータにautoinstallの文字列が含まれている場合、設定された項目に従って自動でインストールを実行します
インストールが完了したらインストール先のストレージから起動するようにUEFIの設定を変更します
詳細な設定方法はドキュメントを参照してください[3-6]
3.6 設定方法
ISOイメージ
ISOイメージをコマンドラインパラメータで指定した場所に置きます
wget https://releases.ubuntu.com/noble/ubuntu-24.04.2-live-server-amd64.iso
mkdir /images
cp ubuntu-24.04.2-live-server-amd64.iso /images
cloud-init
ホスト名、ユーザ名、パスワードは全てubuntuにします
meta-dataは空ファイルで問題ありません
meta-data
touch /autoinstall/meta-data
user-data
cat << EOF > /autoinstall/meta-data
#cloud-config
autoinstall:
version: 1
identity:
hostname: ubuntu
username: ubuntu
password: $6$/X6MRgjz4jCIK8.G$FhJbD17m9qTcMA8FHMPcFvp7v2wvgmRBdvdEdTiZXZRwuZFUVsear9.vYY01QcwPuYAMRMvSJoJKfUlaBviU3/
ssh:
install-server: yes
EOF
説明 | |
---|---|
#cloud-config | 必須 |
autoinstall | Subiquityで実行する項目。cloud-initでは実行不可 |
3.7 不明点
- /initでどのファイルがどこにマウントされるかの正確な情報は不明です
- Snapd、cloud-init、Subiquityはsystemdによって起動されており*.serviceファイルがどこかに存在するはずですが、どこに存在しているかは不明です
3.8 参考
[3-1] initrd
[3-2] run-init
[3-3] NoCloud
[3-4] Storage locations
[3-5] Boot stages
[3-6] Autoinstall configuration reference manual
デモ
Discussion