在 如何构建一台网络引导服务器(一) 中,我们提供了一个极简的 iPXE 引导脚本来引导你的网络引导镜像。许多用户除了使用网络引导镜像外,可能在机器本地也有一个操作系统。但是使用常见的工作站的 BIOS 去切换引导加载器是很笨拙的。在本系列文件的第三部分,我们将向你展示如何设置一个更复杂的 iPXE 配置。它将允许终端用户以更容易的方式去选择引导哪个操作系统。它也可以配置为让系统管理员从一台中央服务器来统一管理引导菜单。
一个交互式 iPXE 引导菜单
下面这些命令重定义了网络引导镜像的 boot.cfg
来作为一个交互式的 iPXE 引导菜单,并使用了一个 5 秒倒计时的定时器:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
| $ MY_FVER=29 $ MY_KRNL=$(ls -c /fc$MY_FVER/lib/modules | head -n 1) $ MY_DNS1=192.0.2.91 $ MY_DNS2=192.0.2.92 $ MY_NAME=server-01.example.edu $ MY_EMAN=$(echo $MY_NAME | tr '.' "\n" | tac | tr "\n" '.' | cut -b -${#MY_NAME}) $ MY_ADDR=$(host -t A $MY_NAME | awk '{print $4}') $ cat << END > $HOME/esp/linux/boot.cfg
set timeout 5000
:menu menu iPXE Boot Menu item --key 1 lcl 1. Microsoft Windows 10 item --key 2 f$MY_FVER 2. RedHat Fedora $MY_FVER choose --timeout \${timeout} --default lcl selected || goto shell set timeout 0 goto \${selected}
:failed echo boot failed, dropping to shell... goto shell
:shell echo type 'exit' to get the back to the menu set timeout 0 shell goto menu
:lcl exit
:f$MY_FVER kernel --name kernel.efi \${prefix}/vmlinuz-$MY_KRNL initrd=initrd.img ro ip=dhcp rd.peerdns=0 nameserver=$MY_DNS1 nameserver=$MY_DNS2 root=/dev/disk/by-path/ip-$MY_ADDR:3260-iscsi-iqn.$MY_EMAN:fc$MY_FVER-lun-1 netroot=iscsi:$MY_ADDR::::iqn.$MY_EMAN:fc$MY_FVER console=tty0 console=ttyS0,115200n8 audit=0 selinux=0 quiet initrd --name initrd.img \${prefix}/initramfs-$MY_KRNL.img boot || goto failed END
|
上述菜单有五个节:
menu
定义了显示在屏幕上的实际菜单内容。
failed
提示用户发生了错误,并将用户带到 shell 以错误错误。
shell
提供了交互式命令提示符。你可以在引导菜单出现时按下 Esc
键进入,或者是 boot
命令失败时也会进入到命令提示符。
lcl
包含一个提供给 iPXE 退出的简单命令,以及返还控制权给 BIOS。在 iPXE 之后,无论你希望缺省引导的设备(即:工作站的本地硬件)是什么,都必须在你的工作站的 BIOS 中正确地作为下一个引导设备列出来。
f29
包含前面文章提到同一个网络引导代码,但使用最终的退出代码来替换掉 goto failed
。
从你的 $HOME/esp/linux
目录中复制更新后的 boot.cfg
到所有客户端系统的 ESP 中。如果一切顺利,你应该会看到类似下面图片的结果:
一个服务器托管的引导菜单
你可以添加到网络引导服务器的另一个特性是,能够从一台中央位置去管理所有客户端的引导菜单。这个特性尤其适用于批量安装(升级)一个新版本的操作系统。在你将新内核和新的 initramfs
复制到所有客户端的 ESP 之后,这个特性可以让你执行一种 原子事务 去切换所有客户端到新操作系统。
安装 Mojolicious:
1 2
| $ sudo -i # dnf install -y perl-Mojolicious
|
定义 “bootmenu” 应用程序:
1 2 3 4 5 6 7 8 9 10 11 12 13
|
use Mojolicious::Lite; use Mojolicious::Plugins;
plugin 'Config';
get '/menu';
app->start; END
|
为 “bootmenu” 应用程序定义配置文件:
1 2 3 4 5 6 7 8
| { hypnotoad => { listen => ['http://*:80'], pid_file => '/run/bootmenu/bootmenu.pid', } } END
|
这是一个非常简单的 Mojolicious 应用程序,它监听 80 端口,并且只回应对 /menu
的请求。如果你想快速了解 Mojolicious 能做什么,运行 man Mojolicious::Guides::Growing
去查看手册。按 Q
键退出手册。
将 boot.cfg
移到我们的网络引导应用程序中作为一个名为 menu.html.ep
的模板:
1 2
| # mkdir /opt/bootmenu/templates # mv $HOME/esp/linux/boot.cfg /opt/bootmenu/templates/menu.html.ep
|
定义一个 systemd 服务去管理引导菜单应用程序:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| [Unit] Description=Serves iPXE Menus over HTTP After=network-online.target
[Service] Type=forking DynamicUser=true RuntimeDirectory=bootmenu PIDFile=/run/bootmenu/bootmenu.pid ExecStart=/usr/bin/hypnotoad /opt/bootmenu/bootmenu.pl ExecReload=/usr/bin/hypnotoad /opt/bootmenu/bootmenu.pl AmbientCapabilities=CAP_NET_BIND_SERVICE KillMode=process
[Install] WantedBy=multi-user.target END
|
在本地防火墙中为 HTTP 服务添加一个例外规则,并启动 bootmenu 服务:
1 2 3 4
| # firewall-cmd --add-service http # firewall-cmd --runtime-to-permanent # systemctl enable bootmenu.service # systemctl start bootmenu.service
|
用 wget
测试它:
1 2 3
| $ sudo dnf install -y wget $ MY_BOOTMENU_SERVER=server-01.example.edu $ wget -q -O - http://$MY_BOOTMENU_SERVER/menu
|
以上的命令应该会输出类似下面的内容:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
|
set timeout 5000
:menu menu iPXE Boot Menu item --key 1 lcl 1. Microsoft Windows 10 item --key 2 f29 2. RedHat Fedora 29 choose --timeout ${timeout} --default lcl selected || goto shell set timeout 0 goto ${selected}
:failed echo boot failed, dropping to shell... goto shell
:shell echo type 'exit' to get the back to the menu set timeout 0 shell goto menu
:lcl exit
:f29 kernel --name kernel.efi ${prefix}/vmlinuz-4.19.4-300.fc29.x86_64 initrd=initrd.img ro ip=dhcp rd.peerdns=0 nameserver=192.0.2.91 nameserver=192.0.2.92 root=/dev/disk/by-path/ip-192.0.2.158:3260-iscsi-iqn.edu.example.server-01:fc29-lun-1 netroot=iscsi:192.0.2.158::::iqn.edu.example.server-01:fc29 console=tty0 console=ttyS0,115200n8 audit=0 selinux=0 quiet initrd --name initrd.img ${prefix}/initramfs-4.19.4-300.fc29.x86_64.img boot || goto failed
|
现在,引导菜单服务器已经正常工作了,重新构建 ipxe.efi
引导加载器,使用一个初始化脚本指向它。
第一步,先更新我们在本系列文章的第一部分中创建的 init.ipxe
脚本:
1 2 3 4 5 6 7 8
| $ MY_BOOTMENU_SERVER=server-01.example.edu $ cat << END > $HOME/ipxe/init.ipxe
dhcp || exit set prefix file:///linux chain http://$MY_BOOTMENU_SERVER/menu || exit END
|
现在,重新构建引导加载器:
1 2 3
| $ cd $HOME/ipxe/src $ make clean $ make bin-x86_64-efi/ipxe.efi EMBED=../init.ipxe
|
将更新后的引导加载器复制到你的 ESP 中:
1
| $ cp $HOME/ipxe/src/bin-x86_64-efi/ipxe.efi $HOME/esp/efi/boot/bootx64.efi
|
将更新后的引导加载器复制到所有的客户端中之后,以后更新引导菜单只需要简单地编辑 /opt/bootmenu/templates/menu.html.ep
文件,然后再运行如下命令:
1
| $ sudo systemctl restart bootmenu.service
|
做一步的改变
如果引导菜单服务器工作正常,在你的客户端系统上的 boot.cfg
文件将更长。
比如,重新添加 Fedora 28 镜像到引导菜单中:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| $ sudo -i
:f$MY_FVER kernel --name kernel.efi \${prefix}/vmlinuz-$MY_KRNL initrd=initrd.img ro ip=dhcp rd.peerdns=0 nameserver=$MY_DNS1 nameserver=$MY_DNS2 root=/dev/disk/by-path/ip-$MY_ADDR:3260-iscsi-iqn.$MY_EMAN:fc$MY_FVER-lun-1 netroot=iscsi:$MY_ADDR::::iqn.$MY_EMAN:fc$MY_FVER console=tty0 console=ttyS0,115200n8 audit=0 selinux=0 quiet initrd --name initrd.img \${prefix}/initramfs-$MY_KRNL.img boot || goto failed END
|
如果一切顺利,你的客户端下次引导时,应该看到如下图所示的结果:
via: https://fedoramagazine.org/how-to-build-a-netboot-server-part-3/
作者:Gregory Bartholomew 选题:lujun9972 译者:qhwdw 校对:wxy
本文由 LCTT 原创编译,Linux中国 荣誉推出