如何構建一台網路引導伺服器(三)

2019-01-01 17:18:00

在 中,我們提供了一個極簡的 iPXE 引導指令碼來引導你的網路引導映象。許多使用者除了使用網路引導映象外,可能在機器本地也有一個作業系統。但是使用常見的工作站的 BIOS 去切換引導載入器是很笨拙的。在本系列檔案的第三部分,我們將向你展示如何設定一個更複雜的 iPXE 設定。它將允許終端使用者以更容易的方式去選擇引導哪個作業系統。它也可以設定為讓系統管理員從一台中央伺服器來統一管理引導選單。

一個互動式 iPXE 引導選單

下面這些命令重定義了網路引導映象的 boot.cfg 來作為一個互動式的 iPXE 引導選單,並使用了一個 5 秒倒計時的定時器:

$ 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#!ipxeset timeout 5000:menumenu iPXE Boot Menuitem --key 1 lcl 1. Microsoft Windows 10item --key 2 f$MY_FVER 2. RedHat Fedora $MY_FVERchoose --timeout \${timeout} --default lcl selected || goto shellset timeout 0goto \${selected}:failedecho boot failed, dropping to shell...goto shell:shellecho type 'exit' to get the back to the menuset timeout 0shellgoto menu:lclexit:f$MY_FVERkernel --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 quietinitrd --name initrd.img \${prefix}/initramfs-$MY_KRNL.imgboot || goto failedEND

上述選單有五個節:

  • menu 定義了顯示在螢幕上的實際選單內容。
  • failed 提示使用者發生了錯誤,並將使用者帶到 shell 以錯誤錯誤。
  • shell 提供了互動式命令提示字元。你可以在引導選單出現時按下 Esc 鍵進入,或者是 boot 命令失敗時也會進入到命令提示字元。
  • lcl 包含一個提供給 iPXE 退出的簡單命令,以及返還控制權給 BIOS。在 iPXE 之後,無論你希望預設引導的裝置(即:工作站的本地硬體)是什麼,都必須在你的工作站的 BIOS 中正確地作為下一個引導裝置列出來。
  • f29 包含前面文章提到同一個網路引導程式碼,但使用最終的退出程式碼來替換掉 goto failed

從你的 $HOME/esp/linux 目錄中複製更新後的 boot.cfg 到所有用戶端系統的 ESP 中。如果一切順利,你應該會看到類似下面圖片的結果:

一個伺服器託管的引導選單

你可以新增到網路引導伺服器的另一個特性是,能夠從一台中央位置去管理所有用戶端的引導選單。這個特性尤其適用於批次安裝(升級)一個新版本的作業系統。在你將新核心和新的 initramfs 複製到所有用戶端的 ESP 之後,這個特性可以讓你執行一種 原子事務 去切換所有用戶端到新作業系統。

安裝 Mojolicious:

$ sudo -i# dnf install -y perl-Mojolicious

定義 “bootmenu” 應用程式:

# mkdir /opt/bootmenu# cat << END > /opt/bootmenu/bootmenu.pl#!/usr/bin/env perluse Mojolicious::Lite;use Mojolicious::Plugins;plugin 'Config';get '/menu';app->start;END# chmod 755 /opt/bootmenu/bootmenu.pl

為 “bootmenu” 應用程式定義組態檔:

# cat << END > /opt/bootmenu/bootmenu.conf{ 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 的模板:

# mkdir /opt/bootmenu/templates# mv $HOME/esp/linux/boot.cfg /opt/bootmenu/templates/menu.html.ep

定義一個 systemd 服務去管理引導選單應用程式:

# cat << END > /etc/systemd/system/bootmenu.service[Unit]Description=Serves iPXE Menus over HTTPAfter=network-online.target[Service]Type=forkingDynamicUser=trueRuntimeDirectory=bootmenuPIDFile=/run/bootmenu/bootmenu.pidExecStart=/usr/bin/hypnotoad /opt/bootmenu/bootmenu.plExecReload=/usr/bin/hypnotoad /opt/bootmenu/bootmenu.plAmbientCapabilities=CAP_NET_BIND_SERVICEKillMode=process[Install]WantedBy=multi-user.targetEND

在本地防火牆中為 HTTP 服務新增一個例外規則,並啟動 bootmenu 服務:

# firewall-cmd --add-service http# firewall-cmd --runtime-to-permanent# systemctl enable bootmenu.service# systemctl start bootmenu.service

wget 測試它:

$ sudo dnf install -y wget$ MY_BOOTMENU_SERVER=server-01.example.edu$ wget -q -O - http://$MY_BOOTMENU_SERVER/menu

以上的命令應該會輸出類似下面的內容:

#!ipxeset timeout 5000:menumenu iPXE Boot Menuitem --key 1 lcl 1. Microsoft Windows 10item --key 2 f29 2. RedHat Fedora 29choose --timeout ${timeout} --default lcl selected || goto shellset timeout 0goto ${selected}:failedecho boot failed, dropping to shell...goto shell:shellecho type 'exit' to get the back to the menuset timeout 0shellgoto menu:lclexit:f29kernel --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 quietinitrd --name initrd.img ${prefix}/initramfs-4.19.4-300.fc29.x86_64.imgboot || goto failed

現在,引導選單伺服器已經正常工作了,重新構建 ipxe.efi 引導載入器,使用一個初始化指令碼指向它。

第一步,先更新我們在本系列文章的第一部分中建立的 init.ipxe 指令碼:

$ MY_BOOTMENU_SERVER=server-01.example.edu$ cat << END > $HOME/ipxe/init.ipxe#!ipxedhcp || exitset prefix file:///linuxchain http://$MY_BOOTMENU_SERVER/menu || exitEND

現在,重新構建引導載入器:

$ cd $HOME/ipxe/src$ make clean$ make bin-x86_64-efi/ipxe.efi EMBED=../init.ipxe

將更新後的引導載入器複製到你的 ESP 中:

$ cp $HOME/ipxe/src/bin-x86_64-efi/ipxe.efi $HOME/esp/efi/boot/bootx64.efi

將更新後的引導載入器複製到所有的用戶端中之後,以後更新引導選單只需要簡單地編輯 /opt/bootmenu/templates/menu.html.ep 檔案,然後再執行如下命令:

$ sudo systemctl restart bootmenu.service

做一步的改變

如果引導選單伺服器工作正常,在你的用戶端系統上的 boot.cfg 檔案將更長。

比如,重新新增 Fedora 28 映象到引導選單中:

$ sudo -i# MY_FVER=28# 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=$(</etc/hostname)# 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 >> /opt/bootmenu/templates/menu.html.ep:f$MY_FVERkernel --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 quietinitrd --name initrd.img \${prefix}/initramfs-$MY_KRNL.imgboot || goto failedEND# sed -i "/item --key 2/a item --key 3 f$MY_FVER 3. RedHat Fedora $MY_FVER" /opt/bootmenu/templates/menu.html.ep# systemctl restart bootmenu.service

如果一切順利,你的用戶端下次引導時,應該看到如下圖所示的結果: