LinuxでPXE Bootサーバーを構築する:ネットワーク経由で複数サーバーにOSを自動インストール

Network tutorial - IT technology blog
Network tutorial - IT technology blog

PXE Bootが本当に必要になる場面

初めて12台の新しいサーバーに一度にUbuntuをインストールしなければならなかったとき、当時の唯一の方法はUSBブートを一台ずつ差し込んで、午後中ずっとNext → Next → Installをクリックし続けることだった。4時間近くかかり、その後さらに各マシンを手動で設定しなければならなかった。あの日からPXE Bootサーバーを構築することを決意した。

PXE(Preboot eXecution Environment)により、コンピューターはUSBやDVDの代わりにネットワークカードから起動し、社内サーバーから直接OSインストーラーをダウンロードできる。50人規模のオフィスと小規模データセンターでは、これまでで最も時間を節約できるツールだ。10台を同時にインストール。USBは不要。見守る必要もない——マシンを起動して席を離れるだけでいい。

PXE Bootのアーキテクチャと動作フロー

このフローを事前に把握しておくと、トラブル発生時のデバッグが格段に速くなる:

  1. クライアントマシンが起動し、BIOS/UEFIがPXEオプション付きのDHCP Discoverを送信する
  2. DHCPサーバーがIP + TFTPサーバーのアドレス + ブートローダーのファイル名を返す
  3. クライアントがTFTP経由でブートローダー(pxelinux.0またはgrubx64.efi)をダウンロードする
  4. ブートローダーがメニューを表示し、ユーザーがインストールするOSを選択する
  5. Kernel + initrdがTFTP経由でダウンロードされ、OSインストーラーが起動し、NFSまたはHTTP経由でインストールファイルを取得する

必須コンポーネントは3つ:DHCPサーバー(dnsmasqまたはisc-dhcp-server)、TFTPサーバー(tftpd-hpa)、そしてOSイメージを配信するNFS/HTTPサーバー

必要なコンポーネントのインストール

PXEサーバーにはUbuntu 22.04を使用する。一度にすべてインストールする:

sudo apt update
sudo apt install -y dnsmasq tftpd-hpa nfs-kernel-server syslinux-common pxelinux

systemd-resolvedが動いている場合は無効化する必要がある——ポート53を占有し、dnsmasqと直接競合するためだ:

sudo systemctl disable --now systemd-resolved
sudo rm /etc/resolv.conf
echo "nameserver 8.8.8.8" | sudo tee /etc/resolv.conf

PXEサーバーのネットワークインターフェースに静的IPを割り当てる——管理ネットワーク専用のインターフェースeth1192.168.10.1を使用する:

# /etc/netplan/99-pxe.yaml
network:
  version: 2
  ethernets:
    eth1:
      addresses: [192.168.10.1/24]
      dhcp4: false
sudo netplan apply

各コンポーネントの詳細設定

1. dnsmasqでDHCP + TFTPを設定する

isc-dhcp-serverではなくdnsmasqを選んだ理由は、設定がシンプルで読みやすく、TFTPプロキシが組み込まれており追加インストールが不要だからだ。設定ファイルを作成する:

sudo nano /etc/dnsmasq.d/pxe.conf
# 使用するインターフェース
interface=eth1
bind-interfaces

# 管理ネットワーク用DHCPレンジ
dhcp-range=192.168.10.100,192.168.10.200,12h

# TFTPサーバー
enable-tftp
tftp-root=/srv/tftp

# PXEブートファイル — BIOS用
dhcp-boot=pxelinux/pxelinux.0

# PXEブートファイル — UEFI用(UEFIサポートが必要な場合)
# dhcp-match=set:efi-x86_64,option:client-arch,7
# dhcp-boot=tag:efi-x86_64,grubx64.efi

# デバッグ用ログ
log-dhcp
log-facility=/var/log/dnsmasq.log
sudo systemctl restart dnsmasq
sudo systemctl enable dnsmasq

2. TFTPディレクトリ構造の作成

TFTPルートにブートローダーをコピーする:

sudo mkdir -p /srv/tftp/pxelinux

# pxelinuxブートローダーをコピー
sudo cp /usr/lib/PXELINUX/pxelinux.0 /srv/tftp/pxelinux/

# 必要なモジュールをコピー
sudo cp /usr/lib/syslinux/modules/bios/{ldlinux,menu,vesamenu,libutil,chain}.c32 /srv/tftp/pxelinux/

# メニュー設定用ディレクトリを作成
sudo mkdir -p /srv/tftp/pxelinux/pxelinux.cfg

3. PXEブートメニューの作成

デフォルトメニューファイルは、個別設定のないすべてのクライアントに適用される。タイムアウト100は最初のエントリを自動ブートするまでの10秒を意味する:

sudo nano /srv/tftp/pxelinux/pxelinux.cfg/default
UI vesamenu.c32
TIMEOUT 100
PROMPT 0
MENU TITLE PXE Boot Menu — IT From Zero

LABEL ubuntu2204
  MENU LABEL Ubuntu 22.04 LTS (x64)
  KERNEL ubuntu22.04/vmlinuz
  APPEND initrd=ubuntu22.04/initrd root=/dev/nfs nfsroot=192.168.10.1:/srv/nfs/ubuntu22.04 ip=dhcp quiet splash

LABEL ubuntu2404
  MENU LABEL Ubuntu 24.04 LTS (x64)
  KERNEL ubuntu24.04/vmlinuz
  APPEND initrd=ubuntu24.04/initrd root=/dev/nfs nfsroot=192.168.10.1:/srv/nfs/ubuntu24.04 ip=dhcp quiet splash

LABEL local
  MENU LABEL ローカルディスクから起動
  LOCALBOOT 0

4. ISOのマウントとNFSの準備

Ubuntu ISOをダウンロードし、マウントしてNFS経由でエクスポートする:

# ディレクトリを作成
sudo mkdir -p /srv/nfs/ubuntu22.04
sudo mkdir -p /mnt/ubuntu22.04

# ISOをダウンロード(またはUSBからコピー)
wget https://releases.ubuntu.com/22.04/ubuntu-22.04.3-live-server-amd64.iso -O /tmp/ubuntu22.04.iso

# ISOをマウント
sudo mount -o loop /tmp/ubuntu22.04.iso /mnt/ubuntu22.04

# ISOの全コンテンツをNFS共有にコピー
sudo rsync -av /mnt/ubuntu22.04/ /srv/nfs/ubuntu22.04/

# カーネルとinitrdをTFTPにコピー
sudo mkdir -p /srv/tftp/ubuntu22.04
sudo cp /srv/nfs/ubuntu22.04/casper/vmlinuz /srv/tftp/ubuntu22.04/
sudo cp /srv/nfs/ubuntu22.04/casper/initrd /srv/tftp/ubuntu22.04/

NFSエクスポートの設定:

sudo nano /etc/exports
/srv/nfs/ubuntu22.04 192.168.10.0/24(ro,sync,no_subtree_check,no_root_squash)
/srv/nfs/ubuntu24.04 192.168.10.0/24(ro,sync,no_subtree_check,no_root_squash)
sudo exportfs -ra
sudo systemctl restart nfs-kernel-server
sudo systemctl enable nfs-kernel-server

5. 便利なテクニック:MACアドレス別のPXE個別設定

マシンごとに異なるOSをインストールする必要があるときに最もよく使う機能だ。ファイル名はMACと完全に一致する必要があり、プレフィックス01-はEthernetの固定値だ:

# 形式: 01-aa-bb-cc-dd-ee-ff
sudo nano /srv/tftp/pxelinux/pxelinux.cfg/01-aa-bb-cc-dd-ee-ff
# このマシンはUbuntu 24.04を自動的にブートする
DEFAULT ubuntu2404
LABEL ubuntu2404
  KERNEL ubuntu24.04/vmlinuz
  APPEND initrd=ubuntu24.04/initrd root=/dev/nfs nfsroot=192.168.10.1:/srv/nfs/ubuntu24.04 ip=dhcp quiet splash

新しいマシンを大量導入するときに非常に便利だ——各MACの設定をあらかじめ作成しておけば、マシンの電源を入れるだけで正しいOSインストーラーが自動的に起動する。一台ずつ見守る必要はない。

動作確認とモニタリング

TFTPの動作確認

# テスト用TFTPクライアントをインストール
sudo apt install tftp-hpa

# TFTPサーバーからファイルをダウンロードしてテスト
tftp 192.168.10.1
tftp> get pxelinux/pxelinux.0
tftp> quit

# ファイルがダウンロードされているか確認
ls -lh pxelinux.0

DHCPログのリアルタイム監視

# PXEをリクエストしているクライアントを監視
sudo tail -f /var/log/dnsmasq.log | grep -E "DHCP|PXE|TFTP"

# またはjournalctlを使用
sudo journalctl -u dnsmasq -f

クライアントがPXEブートに成功すると、このようなログが出力される——sent pxelinux.0という行が見えれば正常だ:

dnsmasq-dhcp: DHCPDISCOVER(eth1) aa:bb:cc:dd:ee:ff
dnsmasq-dhcp: DHCPOFFER(eth1) 192.168.10.105 aa:bb:cc:dd:ee:ff
dnsmasq-tftp: sent /srv/tftp/pxelinux/pxelinux.0 to 192.168.10.105

NFSエクスポートの確認

# 現在のエクスポート一覧を表示
showmount -e 192.168.10.1

# クライアントからテストマウント
sudo mount -t nfs 192.168.10.1:/srv/nfs/ubuntu22.04 /mnt/test
ls /mnt/test

スタック全体のクイックチェックスクリプト

#!/bin/bash
# check-pxe.sh — PXEサーバーのクイックヘルスチェック

echo "=== PXE Server Health Check ==="

echo -n "[dnsmasq]  "
systemctl is-active dnsmasq

echo -n "[tftpd]    "
systemctl is-active tftpd-hpa

echo -n "[nfs]      "
systemctl is-active nfs-kernel-server

echo -n "[TFTP dir] "
ls /srv/tftp/pxelinux/pxelinux.0 &>/dev/null && echo "OK" || echo "MISSING"

echo -n "[NFS exp]  "
showmount -e localhost 2>/dev/null | grep -q srv && echo "OK" || echo "NO EXPORTS"

echo "===="
chmod +x check-pxe.sh
./check-pxe.sh

実運用から学んだこと

  • まずファイアウォールを確認:UDP 67/68(DHCP)、UDP 69(TFTP)、TCP 2049(NFS)を開放すること。これを忘れると延々とデバッグするはめになる——実際に経験済みだ。
  • UEFIとBIOSの違い:2020年以降の新しいマシンはほぼUEFIだ。EFI用に別途dhcp-bootを追加し、pxelinux.0の代わりにgrubx64.efiを使う必要がある。上記の設定ファイルにコメントアウト済みなので、アンコメントするだけでいい。
  • ネットワークスイッチとクライアントBIOS:各クライアントマシンのBIOSでPXE Bootを有効にし、VLANが正しいか確認すること。マネージドスイッチでこのオプションを有効にし忘れただけで、ちょうど1時間無駄にしたことがある——クライアントがブロードキャストし続けているのにDHCPサーバーが無反応な状態でただ眺めていた。
  • 大きなファイルにはTFTPではなくNFS:Ubuntu ServerのISOは1.4GB以上ある。TFTPは大きなファイルに対して遅く不安定だ。TFTPはブートローダーとカーネルのみに使い、残りはNFSに任せること。
  • preseed/kickstartで次のレベルへpreseed(Ubuntu)またはkickstartRHEL/Rocky)と組み合わせれば、完全に無人でインストールできる——マシンを起動してコーヒーを淹れに行き、戻ってきたらインストールが完了してログイン待ちになっている。

PXEサーバーを構築した後、データセンターの15台のマシンにRocky Linuxを約45分でインストールした——コーヒーを飲む時間も含めて。USBを一台ずつ差し込んでいた以前のやり方とは比べ物にならない。

Share: