えんでぃの技術ブログ

えんでぃの技術ブログ

ネットワークエンジニアの視点で、IT系のお役立ち情報を提供する技術ブログです。

KickstartによるLinuxインストール自動化 (自動トリガー・PXEブート連携)

featured_image

Kickstartシリーズ

Kickstartとは、Linuxのインストールを自動化する機能です。
本シリーズではRHEL, Fedora, CentOS Streamをモデルに紹介します。

一連の記事でKickstartの構成を3パターン紹介します。
今回の記事では、3つ目の構成を紹介します。

  1. KickstartによるLinuxインストール自動化 (手動トリガー・HTTP連携)
  2. KickstartによるLinuxインストール自動化 (自動トリガー・ローカルディスク接続)
  3. KickstartによるLinuxインストール自動化 (自動トリガー・PXEブート連携) ← 今ココ

今回の記事については私が構成の内容を理解しきれておりません。
したがって、RHEL8のマニュアル通りの操作を抜粋して紹介するにとどめます。
詳しい原理や、使い勝手やセキュリティを踏まえた設計の吟味などはできませんが、ご了承ください。

今回の構成では、PXE BootやKickstartに必要なファイルをアップロードするサーバ (※) は、他にDHCPが動作していないネットワーク上で起動する必要があります。
(※) 本記事ではPXEサーバと呼びます

"他にDHCPが動作していないネットワーク" というのは、実はかなり大きな制約です。
VirtualBoxのようなローカル検証環境においてはDHCPを活用しているケースが多いと思うので、個人的にはローカル検証環境とPXE Bootはあまり相性が良くないと思います。

一方でPXE Boot用のネットワークが設計上分離されており、PXEサーバが常時起動しているようなインフラが整備されていればうまく活用できると思います。

構成概要

PXE (Preboot eXecution Environment) とは、ネットワークブートの一方式です。
ピクシー (/ˈpɪksiː/) と読まれることが多いようです1

ネットワーク越しにブートローダーやOSイメージ等の情報を取得して起動を開始します。
ブートローダーのパラメータにLinuxインストーラKickstartファイルのURLを指定することで、インストール作業の完全自動化まで可能となります。

kickstart3

環境構築は以下の手順で行います。
詳細は#環境構築にて説明します。

  1. DHCPサーバをインストールする
  2. DHCPサーバにTFTPサーバのIPアドレスなどを設定する
  3. TFTPサーバをインストールする
  4. ブートローダーの設定ファイルやバイナリファイルをTFTPサーバにアップロードする
  5. HTTP、FTP、またはNFSサーバを構築し、以下ファイルをアップロードする
    1. Kickstartファイル
    2. パッケージリポジトリ

Kickstartは以下の手順で開始します。
この構成では、イメージファイルの準備も不要です。
詳細は#Kickstartの実行にて説明します。

  1. インストール対象のマシンに空のディスクをセットする
  2. ネットワーク起動の優先順位を高くする
  3. マシンを起動する

環境構築

今回は、DHCPサーバ、TFTPサーバ、HTTPサーバを同じマシンに全て同居させた "PXEサーバ" を構築します。
今回の構成では、サーバは192.168.101.2/24というIPアドレスを持ちます。
デフォルトゲートウェイは、192.168.101.1であるとします。

手順はRHEL8 - Performing an advanced RHEL installationをベースとしています。
以降、各セクションに参照したセクションへのURLを記載します。

本記事の手順はCentOS Stream 9 (RHEL9相当) で動作を確認しました。

冒頭に記載しましたとおり、本記事では各設定内容の詳細までは吟味しません。
ただ、気になるポイントがあればSYSLINUX Wiki - PXELINUXが参考になると思います。

DHCPが動作していない仮想ネットワークを作成する

PXEサーバが動作するネットワークでは、他のDHCP機能が動作しないようにしてください。
VirtualBoxlibvirtなどの仮想ネットワークを使っている場合は、組み込みのDHCP機能がデフォルトで有効になっているので注意してください。

(参考) DHCPサーバが動作しない仮想ネットワークを作る理由

同じネットワーク内にDHCPサーバを複数台構築すると、DHCPサーバの動作が競合してしまいます。

同じネットワークにDHCPサーバが複数台存在すると、以下のような動きになってしまいます。
(※) DHCPサーバに冗長化機能があり、Active-Standby構成で動作しているようなケースは例外です

  • クライアントがブロードキャストでDHCPDISCOVERを出す
  • 複数台のDHCPサーバがDHCPDISCOVERを受け取り、DHCPOFFERを返す
  • クライアントは複数のDHCPサーバからDHCPOFFERを受け取るが、最初に届いたDHCPOFFERで後続の処理を進める

つまり、DHCPOFFERを先に届けたもの勝ちという動きになり、意図しないDHCPサーバがクライアントにIPアドレスを渡してしまいます。

今回の構成では、確実にPXEサーバが起動しているDHCPサーバからIPアドレスを受け取る必要があります。
PXEサーバ上で動作するDHCPサーバは、後続処理のためにTFTPサーバのIPやファイルパスを伝える特殊な役割を持つためです。

したがって、VirtualBoxKVM (libvirt) が起動している仮想ネットワークのDHCP機能と、PXEサーバのDHCP機能が競合しないように構成を組む必要があります。

(参考) KVMの場合の手順

KVM環境において、DHCP機能を無効化したネットワークを作る手順を紹介します。
操作方法はKVMの基本操作集 - #仮想ネットワークの作成が参考になります。

Cockpitの場合は以下のようなパラメータを指定します。

cockpit_add_nodhcp_network1

仮想ネットワーク作成後、ネットワーク起動し、自動起動も有効化しておきましょう。

cockpit_add_nodhcp_network2

コマンドで実行する場合は、やや煩雑な手順になります。
今回は少々手抜きですが、上記Cockpitで作成したXML形式の定義情報を貼っておきます。
ただし、MACアドレス、UUID情報、ブリッジ名は自動生成に任せたいので削除しておきました。

<network>
  <name>nodhcp</name>
  <forward mode='nat'>
    <nat>
      <port start='1024' end='65535'/>
    </nat>
  </forward>
  <domain name='nodhcp' localOnly='yes'/>
  <dns>
    <host ip='192.168.101.1'>
      <hostname>gateway</hostname>
    </host>
  </dns>
  <ip address='192.168.101.1' netmask='255.255.255.0' localPtr='yes'>
  </ip>
</network>

以下のコマンドにより、作成したtmp.xmlを読み込んで新しい仮想ネットワークを作成します。

virsh net-define tmp.xml

ネットワークを起動し、自動起動を有効化します。

virsh net-start nodhcp
virsh net-autostart nodhcp

VMのネットワーク設定

KVMの構成におけるネットワーク設定を参考までに残しておきます。
以下の構成です。

sudo nmcli connection add ifname enp1s0 con-name enp1s0 type ethernet ipv4.method manual ipv4.addresses 192.168.101.2/24 ipv4.gateway 192.168.101.1 ipv4.dns 192.168.101.1 autoconnect yes

sudo nmcli connection up enp1s0

Linuxイメージファイルのマウント

今回のPXEサーバの構築にはLinuxインストール用のイメージファイルを使用します。

Linuxインストール用のISOファイルを接続した上でサーバを起動します。
Cockpitから仮想マシンに対してISOファイルを追加する際、BusをSCSIではなくSATAを指定しないとLinux上で/dev/cdromが生成しませんでした。

サーバ起動後、以下のコマンドでISOファイルをマウントします2

sudo mkdir /media/cdrom
sudo mount -t iso9660 -o ro,loop /dev/cdrom /media/cdrom

DHCPサーバの構築

参考元: 14. Preparing to install from the network using PXE
(14.2と14.3にそれぞれBIOSUEFI向けの設定方法が説明されていますが、DHCPの設定に関してはどちらも共通です)

DHCPサーバのインストール

以下のコマンドでDHCPサーバをインストールします。

sudo dnf install dhcp-server

DHCPサーバの設定

続いてDHCPサーバの設定を書き換えます。

sudo vi /etc/dhcp/dhcpd.conf

dhcpd.confの中身を以下のように編集します。
IPアドレスの値は環境によって調整してください。

option space pxelinux;
option pxelinux.magic code 208 = string;
option pxelinux.configfile code 209 = text;
option pxelinux.pathprefix code 210 = text;
option pxelinux.reboottime code 211 = unsigned integer 32;
option architecture-type code 93 = unsigned integer 16;

subnet 192.168.101.0 netmask 255.255.255.0 {
    option routers 192.168.101.1;
    range 192.168.101.101 192.168.101.254;

    class "pxeclients" {
      match if substring (option vendor-class-identifier, 0, 9) = "PXEClient";
      next-server 192.168.101.2;

      if option architecture-type = 00:07 {
        filename "BOOTX64.efi";
        } else {
        filename "pxelinux/pxelinux.0";
      }
    }
}

中身について補足します。

DHCPサーバの起動

DHCPサーバを起動します。

# sudo systemctl enable dhcpd.service; sudo systemctl start dhcpd.service と同じ
sudo systemctl enable dhcpd.service --now

TFTPサーバの構築

参考元: 14. Preparing to install from the network using PXE

TFTPサーバのインストール

以下のコマンドでTFTPサーバをインストールします。

sudo dnf install tftp-server

firewalldによるTFTP通信許可

firewalldが有効な場合は、以下のコマンドでTFTP通信を許可しておきます。
重要なコマンドは「変更」と「設定反映」です。

# 事前確認。serviceにtftpがないこと
sudo firewall-cmd --list-all

# 変更
sudo firewall-cmd --add-service tftp --permanent

# 差分比較
diff -u <(sudo firewall-cmd --list-all) <(sudo firewall-cmd --list-all --permanent)
# -public (active)
# +public
#    target: default
#    icmp-block-inversion: no
# -  interfaces: enp1s0
# +  interfaces: 
#    sources: 
# -  services: cockpit dhcpv6-client ssh
# +  services: cockpit dhcpv6-client ssh tftp
#    ports: 
#    protocols: 
#    forward: yes

# 設定反映
sudo firewall-cmd --reload

# 事後確認。serviceにtftpがあること
sudo firewall-cmd --list-all

BIOS利用クライアント向けのブートローダー格納

参考元: 14.2. Configuring a TFTP server for BIOS-based clients

PXEBOOT用のブートローダーや設定ファイルをTFTPサーバに格納します。
本セクションで紹介するのは、BIOSベースのクライアント向けの手順です。
UEFIベースのクライアント向けの手順は、#UEFI利用クライアント向けのブートローダー格納にて別途紹介します。
理由がなければ、両方のセクションを対応しましょう。

作業ディレクトリに移動し、ブートローダRPMをISOイメージファイルから取り出します。
RPMファイルを展開し、中にあるブートローダーファイル群を/var/lib/tftpboot/pxelinux/ディレクトリに格納します。

mkdir ~/tmp/
cd ~/tmp/

# RHEL8の公式手順ではISOファイルから取り出している
  # RHEL8の場合: cp -p /media/cdrom/BaseOS/Packages/syslinux-tftpboot*.rpm .
  # CentOS Stream9場合: cp -p /media/cdrom/AppStream/Packages/syslinux-tftpboot-*.rpm .
dnf download syslinux-tftpboot

rpm2cpio syslinux-tftpboot*.rpm | cpio -dimv

sudo mkdir /var/lib/tftpboot/pxelinux
sudo cp -p tftpboot/* /var/lib/tftpboot/pxelinux/

作業用ディレクトリは不要になったので、このタイミングで消しておきます。

cd
rm -rf ~/tmp/

PXELINUXの設定ファイルを格納するディレクトリを作成します。

sudo mkdir /var/lib/tftpboot/pxelinux/pxelinux.cfg

PXELINUXの設定ファイルを作成します。

sudo vi /var/lib/tftpboot/pxelinux/pxelinux.cfg/default

defaultファイルには以下の内容を記述します。
IPアドレスや文言は環境に合わせてアレンジしてください。

default vesamenu.c32
timeout 50

display boot.msg

label linux_cs9
  menu label ^Install system
  menu default
  kernel images/centos_stream9/vmlinuz
  append initrd=images/centos_stream9/initrd.img ip=dhcp inst.repo=http://192.168.101.2/repositories/centos_stream9 inst.ks=http://192.168.101.2/kickstarts/centos_stream9
label vesa_cs9
  menu label Install system with ^basic video driver
  kernel images/centos_stream9/vmlinuz
  append initrd=images/centos_stream9/initrd.img ip=dhcp inst.xdriver=vesa nomodeset inst.repo=http://192.168.101.2/repositories/centos_stream9 inst.ks=http://192.168.101.2/kickstarts/centos_stream9
label rescue_cs9
  menu label ^Rescue installed system
  kernel images/centos_stream9/vmlinuz
  append initrd=images/centos_stream9/initrd.img rescue
label local
  menu label Boot from ^local drive
  localboot 0xffff

BIOS画面からPXE Bootを試みるとき、このdefaultファイルを参照してBoot Entryを選択します。
ファイル名は他にもUUIDやMACアドレスIPアドレスを元にした文字列も指定可能です。
上記のファイル名の条件に一致するようなクライアントから接続があった場合、defaultファイルよりも優先してそれらのファイルが読み込まれます。
詳細はSYSLINUX Wiki - PXELINUX - #Configuration filenameを参照してください。

設定ファイルの文法については、SYSLINUX Wiki - Configを参照してください。

今回はシンプルにdefaultファイルのみ作成しました。
MACアドレスIPアドレスごとのファイルを作成するかは設計思想に依存すると思いますが、手間がかかるので基本defaultのみで良いのではないかと思います。

defaultファイルは、RHEL8のマニュアルから以下の部分をアレンジしました。

変更前 変更後 詳細
prompt 1 行削除
  • prompt 1の場合、常にboot:プロンプトを表示する
  • prompt 0の場合、boot:プロンプトを表示しない
    (デフォルト)
  • boot:の表示によって起動が遅くなるので省いた
  • prompt
timeout 600 timeout 50
label linux label linux_cs9
  • 今後別OSの選択肢が増えたときのために名称変更
  • label
label vesa label vesa_cs9 同上
label rescue label rescue_cs9 同上

vesa_cs9, rescue_cs9, local_cs9については、不要であれば#コメントアウトしても問題ないと思います。

上表以外にも、各labelの配下に指定しているkernelinitrdinst.repoIPアドレスとファイルパスを適切な値に変更しました。

kernelinitrdについては、/var/lib/tftpboot/をrootとしたときの相対パスを指定します。
後続の#kernel, initrdファイルの格納において、ここで指定したパスにkernelinitrdを格納する必要があります。

inst.repoは、RPMパッケージリポジトリのURLです。
IPアドレスはHTTPサーバのものを指定します。
今回はDHCP/TFTP/HTTPサーバがすべて同じマシンに同居する構成のため、共通のIPアドレスである192.168.101.2を指定します。
後続の#RPMパッケージリポジトリの格納において、RPMパッケージリポジトリをここで指定したファイルパスに格納する必要があります。
inst.repoと同等のオプションはKickstartファイルのuriオプションでも指定しますが、これらはどちらも指定する必要があります。

inst.repoと同じ行にinst.ksを追記し、KickstartファイルのURLを指定しました。
後続の#Kickstartファイルの格納において、Kickstartファイルをここで指定したファイルパスに格納する必要があります。

UEFI利用クライアント向けのブートローダー格納

参考元: 14.3. Configuring a TFTP server for UEFI-based clients

前セクションではBIOSベースのクライアント用のブートローダーをTFTPサーバに格納しました。
本セクションでは、UEFIベースのクライアント用のブートローダーを格納します。

異なるバイナリファイルや設定ファイルを用意する必要がありますが、設定のポイントは基本的にBIOS向けの対応手順と変わりません。

まず、作業用ディレクトリを作成して移動します。

mkdir ~/tmp
cd ~/tmp

shim、grub2-efi RPMパッケージをISOファイルから取り出します。
これらのRPMはオンラインリポジトリには存在しなかったので、ISOファイルから取り出す必要がありました。

cp -p /media/cdrom/BaseOS/Packages/shim-x64-[0-9]*.rpm .
cp -p /media/cdrom/BaseOS/Packages/grub2-efi-x64-[0-9]*.rpm .

RPMファイルを展開して中身のファイルを取り出します。

rpm2cpio shim-x64-[0-9]*.rpm | cpio -dimv
rpm2cpio grub2-efi-x64-[0-9]*.rpm | cpio -dimv

EFIブートイメージファイルを取り出し、TFTPからアクセス可能な領域に格納します。

mkdir /var/lib/tftpboot/uefi

# RHELの場合は...
# sudo cp -p boot/efi/EFI/redhat/grubx64.efi
# sudo cp -p boot/efi/EFI/redhat/shimx64.efi
sudo cp -p boot/efi/EFI/centos/grubx64.efi
sudo cp -p boot/efi/EFI/centos/shimx64.efi

EFI用のBoot Entryを追記します。

sudo vi /var/lib/tftpboot/grub.cfg

以下のように記載します。

set timeout=5
menuentry 'CentOS Stream 9' {
  linuxefi images/centos_stream9/vmlinuz ip=dhcp inst.repo=http://192.168.101.2/repositories/centos_stream9/ inst.ks=http://192.168.101.2/kickstarts/centos_stream9
  initrdefi images/centos_stream9/initrd.img
}

grub.cfg環境変数やコマンドについては、GNU GRUB Manual - #16 The list of available commandsを参照してください。

grub.cfgファイルは、RHEL8のマニュアルから以下の部分をアレンジしました。

変更前 変更後 詳細
set timeout=60 set timeout=5
menuentry 'RHEL 8' menuentry 'CentOS Stream 9'

上表の他にも各種ファイルのパスやURLを環境に合わせて変更しました。

vmlinuzinitrd.imgについては、/var/lib/tftpboot/をrootとしたときの相対パスを指定します。
後続の#kernel, initrdファイルの格納において、ここで指定したパスにkernelinitrdを格納する必要があります。

inst.repoは、RPMパッケージリポジトリのURLです。
IPアドレスはHTTPサーバのものを指定します。
今回はDHCP/TFTP/HTTPサーバがすべて同じマシンに同居する構成のため、共通のIPアドレスである192.168.101.2を指定します。
後続の#RPMパッケージリポジトリの格納において、RPMパッケージリポジトリをここで指定したファイルパスに格納する必要があります。
inst.repoと同等のオプションはKickstartファイルのuriオプションでも指定しますが、これらはどちらも指定する必要があります。

inst.repoと同じ行にinst.ksを追記し、KickstartファイルのURLを指定しました。
後続の#Kickstartファイルの格納において、Kickstartファイルをここで指定したファイルパスに格納する必要があります。

kernel, initrdファイルの格納

PXE Bootで起動する際に必要なkernelイメージファイル、及びInit RAM DiskをISOファイルからコピーして格納します。
以下のコマンドを実行します。

mkdir -p /var/lib/tftpboot/pxelinux/images/centos_stream9
sudo cp -p /media/cdrom/images/pxeboot/{vmlinuz,initrd.img} /var/lib/tftpboot/pxelinux/images/centos_stream9/

TFTPサーバの起動

# sudo systemctl enable tftp.socket; sudo systemctl start tftp.socket と同じ
sudo systemctl enable tftp.socket --now

HTTPサーバの構築

参考元: RHEL8 - Performing an advanced RHEL installation - 6.4. Creating an installation source using HTTP or HTTPS

HTTPサーバにはKickstartファイルと、RPMパッケージリポジトリをアップロードします。

HTTPサーバのインストール

以下のコマンドでApache httpdをインストールします。

sudo dnf install httpd

firewalldによるHTTP通信許可

firewalldが有効な場合は、以下のコマンドでHTTP通信を許可しておきます。
重要なコマンドは「変更」と「設定反映」です。

# 事前確認。serviceにhttpがないこと
sudo firewall-cmd --list-all

# 変更
sudo firewall-cmd --add-service http --permanent

# 差分比較
diff -u <(sudo firewall-cmd --list-all) <(sudo firewall-cmd --list-all --permanent)
# -public (active)
# +public
#    target: default
#    icmp-block-inversion: no
# -  interfaces: enp1s0
# +  interfaces: 
#    sources: 
# -  services: cockpit dhcpv6-client ssh tftp
# +  services: cockpit dhcpv6-client http ssh tftp
#    ports: 
#    protocols: 
#    forward: yes

# 設定反映
sudo firewall-cmd --reload

# 事後確認。serviceにhttpがあること
sudo firewall-cmd --list-all

Kickstartファイルの格納

参考元: 5.3. Making a Kickstart file available on an HTTP or HTTPS server

KickstartファイルをHTTPサーバにアップロードします。
使用するファイルは、KickstartによるLinuxインストール自動化 (手動トリガー・HTTP連携) - #書き換え後のKickstartファイルとほぼ同じです。

ただし、cdromrepoの行のみ以下のように書き換えます。
RPMパッケージリポジトリをCDROMではなく、HTTPサーバ上のリポジトリに変更します。

# cdrom
url --url=http://192.168.101.2/repositories/centos_stream9

# repo --name="AppStream" --baseurl=file:///run/install/sources/mount-0000-cdrom/AppStream
repo --name="AppStream" --baseurl=http://192.168.101.2/repositories/centos_stream9/AppStream

cdromRPMパッケージリポジトリとしてISOイメージファイルを指定するコマンドです。
今回はRPMパッケージリポジトリとしてHTTPサーバを指定するので、これをurlコマンドに置き換えます。

repoは、baseなどデフォルトのRPMリポジトリに追加のリポジトリを指定するオプションです。
RHEL8以降は、インストール時にAppStreamというリポジトリを追加で指定する必要があります3

用意したKickstartファイルをHTTPサーバにアップロードします。

sudo mkdir /var/www/html/kickstarts
sudo vi /var/www/html/kickstarts/centos_stream9

今回使用するKickstartファイルは以下のとおりです。

# Generated by Anaconda 34.25.0.25
# Generated by pykickstart v3.32
#version=RHEL9
# Use graphical install
graphical
repo --name="AppStream" --baseurl=file:///run/install/sources/mount-0000-cdrom/AppStream

%addon com_redhat_kdump --enable --reserve-mb='auto'

%end

# Keyboard layouts
keyboard --vckeymap=jp --xlayouts='jp'
# System language
lang en_US.UTF-8

# Network information
network  --bootproto=dhcp --device=enp1s0 --ipv6=auto --activate
network  --hostname=cs

url --url=http://192.168.101.2/repositories/centos_stream9

%packages
@^minimal-environment

%end

# Run the Setup Agent on first boot
firstboot --enable

# Generated using Blivet version 3.4.0
ignoredisk --only-use=vda
# Partition clearing information
clearpart --none --initlabel
# Disk partitioning information
part pv.111 --fstype="lvmpv" --ondisk=vda --grow
part /boot --fstype="ext4" --ondisk=vda --size=1024
volgroup cs --pesize=4096 pv.111
logvol / --fstype="ext4" --percent=100 --name=root --vgname=cs
logvol swap --fstype="swap" --size=1024 --name=swap --vgname=cs

# System timezone
timezone Asia/Tokyo --utc

# Root password
rootpw --iscrypted $6$GMEsgHeNZwjJWb.d$BuP/sn9FX6xKEFGYo8KzNmLB5jPl7RhFQyHnklgrK2CkQntcsT2aOCz4Ozzcefc5J7gXO7IXVvj7KdQOddpv81
user --groups=wheel --name=endy --password=$6$qtY89ARpZJNqk8ap$1u6e3CplnSGpqBppAyd/.f9fheOt74TA.fqMdPsROa3kmSSlHuOyXurBWSr5EHksAemR.3HjDjkI1n6JIeJIk1 --iscrypted --gecos="endy"

過去記事と同様に、お好みでシンボリックリンクを作っておくとCentOS Streamのバージョン差異を抽象化できて便利になります。
よろしければ、以下のコマンドでcentos_streamというファイル名のシンボリックリンクを作成しておきましょう。

ln -s centos_stream9 centos_stream

RPMパッケージリポジトリの格納

参考元: 6.4. Creating an installation source using HTTP or HTTPS

ISOファイルからRPMパッケージリポジトリ情報をコピーします。
この部分の手順は、いわゆるリポジトリサーバの構築手順に近い内容かなと思います。

今回はLinuxの初期インストール用のパッケージを調達したいので、オンラインリポジトリではなくISOファイルからリポジトリデータをコピーします。

以下のコマンドでコピーします。
コピー元ディレクトリにある.treeinfoという隠しファイルが重要です。
*のようなワイルドカードを使うと隠しファイルのコピーが漏れてしまうので、以下の例のようにフォルダごとコピーしましょう。

sudo mkdir /var/www/html/repositories/
sudo cp -pr /media/cdrom/ /var/www/html/repositories/
sudo mv /var/www/html/repositories/cdrom /var/www/html/repositories/centos_stream9

HTTPサーバの起動

以下のコマンドでHTTPサーバを起動します。

# sudo systemctl enable httpd.service; sudo systemctl start httpd.service と同じ
sudo systemctl enable httpd.service --now

Kickstartの実行

ここまでの操作により、Kickstartに必要なPXEサーバの構築は完了しました。

では、いよいよ空のVMPXE Bootし、KickstartによってLinuxを自動インストールします。

(参考) 仮想マシンの作成

KVM配下に仮想マシンを作成する場合を例に、パラメータの例を示します。

詳細はKVMの基本操作集 - #VMの作成をご覧ください。

CockpitからVMを作成する際は、下図のようにパラメータを指定します。
今回はPXE Bootをするため、通常のCDROMからの起動ではなく、ネットワークからの起動を選択します。
また、PXEサーバと同じネットワークに接続するようにします。
今回の場合は、#DHCPが動作していない仮想ネットワークを作成するで作成したnodhcpというネットワークに接続します。

cockpit_vm_creation_with_network_boot_enabled

virt-installコマンドで仮想マシンを作成する場合は、例えば以下のようなコマンドを実行します。

Network bootを優先するため、普段指定している--cdromの代わりに--pxeを指定します。
また、今回は仮想ネットワークにdefault以外のものを指定するので、明示的に--network network=nodhcpによって指定します。

コンソール画面の自動起動を無効化したい場合は、--no-autoconsoleオプションも付けましょう。
--no-autoconsoleを指定する場合は、末尾の&は削除します。

virt-install \
--name test \
--memory 2048 \
--vcpus 2 \
--disk size=10 \
--graphics vnc \
--graphics spice \
--os-variant centos-stream9 \
--network network=nodhcp \
--pxe &

インストール手順を何度か試したいとも思いますので、作成したVMを停止して削除するコマンドも添えておきます。
--os-variantの指定を省いた場合は、--storage vdaの部分が--storage hdaになることもあります。
詳細はKVMの基本操作集 - #VMの削除を参照してください。

virsh destroy test ; virsh undefine test --storage vda --snapshots-metadata --managed-save

Kickstartによる自動インストール

VMを起動すると、以下の処理が自動的に走ります。

正しく動作すれば、以下のブートローダーの画面が表示されます。
無操作のまま5秒待つか、一番上のInstall systemを選択するとこの先のインストールに進みます。

pxe_bootloader

正しく処理が進めば、このままインストールが完了します。

(参考) トラブルのパターン

全てではありませんが、過去に踏んだことのあるトラブルを紹介します。

inst.repoの指定ミス

参考: 23.1. Configuring the Installation System at the Boot Menu - #Specifying the Installation Source

inst.repoに指定したパス配下の.treeinfoにHTTPアクセスできなかった場合、ブートローダーのグレーの画面を通過後、以下のようなエラー画面に遷移します。

.treeinfoの読み取りに失敗し、inst.repoinst.ksのパスに/images/install.imgを付与したパスから読み取る処理にフォールバックします。そのパスにもファイルが存在しないため、HTTP通信で404エラー応答が返り、処理に失敗します。

error_repository1

↓しばらく待つと、以下のようなエラーメッセージがしばらくループし続けた後、完全に処理を停止します。

error_repository2

このエラーが出た場合、inst.repoに指定したパスを中心に、HTTP通信がエラーになった原因を探って修正する必要があります。
確認するファイルは以下の2つです。

  • /var/lib/tftpboot/pxelinux/pxelinux.cfg/default
  • /var/lib/tftpboot/grub.cfg

(参考) Kickstartでエラーが発生したときの対処法

1つ目の記事で紹介した(参考) Kickstartでエラーが発生したときの対処法を参照してください。

まとめ

PXE bootとKickstartを組み合わせて、ネットワーク越しに各種リソースにアクセスしてLinuxインストールを完全自動化する構成を紹介しました。

構成がなかなか複雑ですが、ネットワークに繋いでマシンの電源を入れるだけでLinuxのインストールが完了するというのは面白いと思います。

しかし、ローカル検証環境において活用するにはDHCPサーバの競合を回避する必要があります。
本番用途で活用するには、構築したサーバに何らかの方法で固定IPアドレスを割り振る工程も自動化するところで頭を使うと思います。

実際のユースケースと結びつけて正しく設計しようと考えると、今回紹介した構成は難易度が高いと思います。
他のKickstart構成やVMクローン、AnsibleなどのDevOpsツールなどの代替手段があるだけに、PXE bootの構成は中々採用されないかもしれません。

私も今のところ良いユースケースを思いつかない状況ですが、せっかく構築できたので本記事で紹介した次第です。
うまい使い方をご存知の方がいれば、ぜひコメントいただけますと幸いです。

関連記事