PXE实现Windows和Linux的双系统引导

天锦 发表于 码农也得有格调 分类,标签:

先前协会为了修电脑方便,部署了WDS服务器实现PXE网启,引导终端设备加载PE系统或是Window安装进程以进行系统的维护和安装。但是作为一个计算机社团,光有Windows是不行的,Linux对我们也很重要,所以有了这次双系统引导的折腾。

在网上看了很多pxe引导的例子,觉得中国科技大学的PXE服务就是我想要的那种,既能引导Linux也能引导Windows,参考 PXE是什么中国科技大学网络启动服务、和 中国科技大学PXE服务FAQ,最终选择跳坑科大的simple-pxe。simple-pxe是科大崔灏学长写的一个用于生成GRUB启动菜单的脚本,并不是一键安装的全套服务,所以还有很多要自己折腾的。

在运行simple-pxe脚本前,要先准备好HTTP、NFS和TFTP服务环境。simple-pxe脚本使用到了bsdtar、curl、svn、和fatcat命令,fatcat在CentOS中没有包可用需要手动编译、Ubuntu下有现成的包可用,所以建议在Ubuntu下折腾。

TFTP和DHCP

PXE启动实现方案有很多种如pxelinux、ipxe和grub等都支持pxe引导。所有的PXE启动第一阶段都是客户端通过DHCP获取到IP地址、网关、子网掩码这些联网基础信息和额外的用于PXE启动的Option 66(启动服务器主机名)和Option 67(启动文件名)。PXEClient在获取到这些信息后便会使用TFTP协议从启动服务器上面下载启动文件到内存上并执行启动文件。该文件就是pxelinux.0或者是core.0等这些可执行文件。用于显示系统选择菜单和从网络上下载系统文件,加载到内存和启动系统这系列的操作。simple-pxe生成的是grub的引导菜单,也支持grub2,我由于不清楚这几个之间的关系,下了syslinux,整pxelinux.0报错,启动不起来,是一头雾水浪费了些时间。

建立/srv/pxe作为服务目录

[root@pxe ~]# mkdir -p /srv/pxe

生成支持网络启动的grub

[root@pxe ~]# grub-mknetdir --net-directory=/srv/pxe --subdir=/grub -d /usr/lib/grub/i386-pc

到DHCP中设置Option66 为TFTP服务器地址,你可以在pxe这台服务器上装TFTP服务器,但是我在部署的时候不知道什么原因,终端总是TimeOut拿不到文件,防火墙也关了该有的权限也都有,就是无法get文件,最后是用我的OpenWRT路由器做了TFTP服务器,在OpenWRT上建立/srv/pxe/grub目录,把在pxe服务器上生成的grub文件都复制到OpenWRT上实现的,需要用TFTP传输的只是grub的可执行文件和部分mod,体积不大所有可以交给OpenWRT去代劳,后续的系统镜像这些大文件用的是HTTP协议和NFS协议,就跟TFTP没关系了。和Option67设置为/grub/i386-pc/core.0

这个时候可以看一下PXE第一步能不能正常工作了,正常情况下是可以从TFTP上下载到Grub的,并且能执行起来,不过因为没有grub.cfg这个配置文件,启动起来的Grub会报错,接下来就运行simple-pxe准备系统文件和生成grub菜单了。

simple-pxe

git clone项目:

[root@pxe ~]# git clone https://github.com/ustclug/simple-pxe.git
[root@pxe ~]# cd simple-pxe
[root@pxe  simple-pxe]# cp config.local.example config.local
[root@pxe  simple-pxe]# vim config.local

编辑config.local去设置你的NFS服务地址,HTTP服务地址以及服务运行目录等信息,选择你需要的Linux发行版,不需要的就从PXE_PREPARE和PXE_MENUS中删掉。修改好后prepare以准备文件,menu以生成菜单。

[root@pxe simple-pxe]# ./simple-pxe prepare
[root@pxe simple-pxe]# ./simple-pxe menu

生成的菜单配置文件在config.local中设置的PXE_LOCAL_ROOT目录下的menu目录中,我这里是默认的/srv/pxe,

[root@pxe  simple-pxe]# ls /srv/pxe/menu
archlinux.menu  clonezilla.menu  fedora.menu   gparted.menu  netbsd.menu  root.menu     tool.menu
centos.menu     debian.menu      freebsd.menu  linux.menu    reboot.menu   ubuntu.menu

其中root.menu是入口,simple-pxe只支持Linux,我们还有弄Windows的,所以把这个root.menu改名为linux.menu做二级菜单,在重新手写一个root.menu做入口菜单。

[root@pxe ~]# cd /srv/pxe/menu
[root@pxe menu]# mv root.menu linux.menu

以下是重写的root.menu

set menu_color_highlight=white/red
set menu_color_normal=white/blue
export menu_color_highlight
export menu_color_normal
if [ "$feature_all_video_module" = "y" ]; then
  insmod all_video
else
  for mod in efi_gop efi_uga ieee1275_fb vbe vga video_bochs video_cirrus; do
    insmod $mod
  done
fi
menuentry '--- Computer Association Network Boot Service ---' {
  if [ 1 = 1 ]; then
    set pager=1
    cat (http,10.60.60.45)/pxe/intro.txt
    echo "Press any key to continue"
    read
  fi
}
menuentry '> Windows Series'{
  configfile "(http,10.60.60.45)/pxe/menu/windows.menu" 
}
menuentry '> Linux Series'{
  configfile "(http,10.60.60.45)/pxe/menu/linux.menu"  
}
menuentry '> Tools' {
  configfile "(http,10.60.60.45)/pxe/menu/tool.menu"
}
menuentry '> Reboot' {
  configfile "(http,10.60.60.45)/pxe/menu/reboot.menu"
}

关于引导Windows,我选了用加载iso虚拟光盘的方式实现引导Windows的,比较方便。以下是windows.menu

menuentry '..' {
  configfile "(http,10.60.60.45)/pxe/menu/root.menu"
}
menuentry 'Windows PE With Network'{
  insmod memdisk
  echo 'Loading Memdisk...'
  linux16 /memdisk iso raw
  echo 'Loading PE Image File...'
  initrd16 (http,10.60.60.45)/pxe/windows/networkpe.iso
  echo 'Loading Done,Booting Windows PE...'
}
menuentry 'Windows Server 2019 Installer'{
  insmod memdisk
  echo 'Loading Memdisk...'
  linux16 /memdisk iso raw
  echo 'Loading Windows Image File...'
  initrd16 (http,10.60.60.45)/pxe/windows/server2019.iso
  echo 'Loading Done,Booting Windows...'
}

这里要注意一下linux16 /memdisk中的memdisk是从syslinux中复制出来的文件,要放到/srv/pxe目录下的。roou.menu也作为grub.cfg上传到tftp服务器:

[root@pxe ~]# scp /usr/lib/syslinux/memdisk root@openwrt:/srv/pxe
[root@pxe ~]# scp /srv/pxe/menu/root.menu root@openwrt:/srv/pxe/grub/grub.cfg

我是因为TFTP在openwrt上跑的,才上传到openwrt主机上,如果你的TFTP就在pxe服务器上跑的,那就是:

[root@pxe ~]# scp /usr/lib/syslinux/memdisk /srv/pxe
[root@pxe ~]# scp /srv/pxe/menu/root.menu /srv/pxe/grub/grub.cfg

BIOS&UEFI

BIOS和UEFI双支持可以在DHCP中判断DHCPClient厂商vendorclass下发不同的Option67来实现。

dnsmasq配置参考如下(仅参考):

enable-tftp
tftp-lowercase
dhcp-no-override
tftp-root=/mnt/sda1/pxeboot
dhcp-match=set:iPXE,175
dhcp-vendorclass=set:flag,PXEClient:Arch:00000
dhcp-vendorclass=set:flag,PXEClient:Arch:00006
dhcp-vendorclass=set:flag,PXEClient:Arch:00007
dhcp-vendorclass=set:flag,PXEClient:Arch:00009
tag-if=set:load,tag:!iPXE,tag:flag
pxe-prompt="Press F8 or Enter key for PXE menu.", 5
#BIOS MENU
pxe-service=tag:load,X86PC, "BIOS ipxe undionly", undionly.kpxe
pxe-service=tag:load,X86PC, "BIOS ipxe.pxe", ipxe.pxe
pxe-service=tag:load,X86PC, "BIOS Microsoft PXE", pxeboot.n12
pxe-service=tag:load,X86PC, "boot from local", 0
#UEFI MENU
pxe-service=tag:load,IA32_EFI, "Microsoft UEFI (IA32_EFI)", bootia32.efi
pxe-service=tag:load,X86-64_EFI, "Microsoft UEFI (X86-64_EFI)", bootx64.efi
pxe-service=tag:load,BC_EFI, "Microsoft UEFI(BC-EFI)", bootx64.efi
pxe-service=tag:load,6, "iPXE snponly UEFI32(6)", snponly32.efi
pxe-service=tag:load,7, "iPXE snponly UEFI(7)", snponly.efi
pxe-service=tag:load,9, "iPXE snponly UEFI(9)", snponly.efi
pxe-service=tag:load,06,  "iPXE UEFI32(06)", ipxe32.efi
pxe-service=tag:load,07,  "iPXE UEFI(07)", ipxe.efi
pxe-service=tag:load,09,  "iPXE UEFI(09)", ipxe.efi
dhcp-boot=tag:iPXE,ipxemenu.txt

至此,基本上就OK了。