ubuntu netboot test - hanyong/note GitHub Wiki
时间: 2017-11-05 11:33:25 宿主机环境: ubuntu 16.04
参考官方文档: https://help.ubuntu.com/16.04/installation-guide/amd64/ch04s05.html
先使用虚拟机测试网络启动。
首先为虚拟机网络创建一个 bridge, 这有许多种办法, 这里我们使用 libvirt 创建一个 NAT 网络。
libvirt 也支持配置 TFTP 和 DHCP, 但为了模拟物理机安装, 这里我们不配置。
写一个 libvirt 网络配置文件 nat.xml
如下,参考文档: https://libvirt.org/formatnetwork.html#examplesNAT 。
<!-- vim: set ts=2 sw=2 et: -->
<network>
<name>nat</name>
<bridge name="nat0"/>
<forward mode="nat"/>
<ip address="192.168.128.1" mask="255.255.255.0">
</ip>
</network>
创建网络,检查创建结果:
$ virsh net-create nat.xml
从nat创建网络nat.xml
$ ip addr
# ... ...
5: nat0: <NO-CARRIER,BROADCAST,MULTICAST,UP> mtu 1500 qdisc noqueue state DOWN group default qlen 1000
link/ether 00:00:00:00:00:00 brd ff:ff:ff:ff:ff:ff
inet 192.168.128.1/24 brd 192.168.128.255 scope global nat0
valid_lft forever preferred_lft forever
6: nat0-nic: <BROADCAST,MULTICAST> mtu 1500 qdisc pfifo_fast state DOWN group default qlen 1000
link/ether 52:54:00:c3:1c:f7 brd ff:ff:ff:ff:ff:ff
虚拟机我们也使用 libvirt 创建,写一个配置文件 test1.xml
如下, 参考文档: https://libvirt.org/formatdomain.html 。
这里有两个关键配置,一是使用网络启动,二是连接到我们刚才创建的 NAT 网络。
<!-- vim: set sw=2 ts=2 et: -->
<domain type='kvm'>
<name>node1</name>
<os>
<type>hvm</type>
<boot dev="network"/>
</os>
<features>
<acpi/>
<apic/>
</features>
<cpu mode='host-passthrough'/>
<vcpu>2</vcpu>
<memory unit='GiB'>3</memory>
<devices>
<console type='pty'>
<target type='virtio'/>
</console>
<graphics type='vnc'/>
<interface type='network'>
<source network='nat'/>
<model type='virtio'/>
</interface>
</devices>
</domain>
定义虚拟机,之后可以通过 virt-manager 反复启动测试。
$ virsh define node1.xml
定义域 node1(从 node1.xml)
这时启动虚拟机可看到启动失败,因为我们还没配置网络启动服务器。
安装 isc-dhcp-server
,因为是临时使用,设置其不要自动启动。
$ sudo systemctl disable isc-dhcp-server
Synchronizing state of isc-dhcp-server.service with SysV init with /lib/systemd/systemd-sysv-install...
Executing /lib/systemd/systemd-sysv-install disable isc-dhcp-server
insserv: warning: current start runlevel(s) (empty) of script `isc-dhcp-server' overrides LSB defaults (2 3 4 5).
insserv: warning: current stop runlevel(s) (0 1 2 3 4 5 6) of script `isc-dhcp-server' overrides LSB defaults (0 1 6).
查看默认配置 /etc/dhcp/dhcpd.conf
,其中说如果 /etc/ltsp/dhcpd.conf
存在会替代这文件,而后者现在不存在。
为了不影响默认配置文件,我们把这个文件拷贝过去修改。
$ sudo rsync -rtpvi /etc/dhcp/dhcpd.conf /etc/ltsp/
sending incremental file list
created directory /etc/ltsp
>f+++++++++ dhcpd.conf
sent 3,729 bytes received 67 bytes 7,592.00 bytes/sec
total size is 3,641 speedup is 0.96
看了下默认配置,主要是设置域名,DNS 服务器等,似乎暂时可以不修改。 默认配置报错,没有绑定网卡:
$ systemctl status isc-dhcp-server
● isc-dhcp-server.service - ISC DHCP IPv4 server
Loaded: loaded (/lib/systemd/system/isc-dhcp-server.service; enabled; vendor preset: enabled)
Active: failed (Result: exit-code) since 日 2017-11-05 13:22:38 CST; 1min 35s ago
Docs: man:dhcpd(8)
Main PID: 22304 (code=exited, status=1/FAILURE)
11月 05 13:22:38 han2015 sh[22304]: Not configured to listen on any interfaces!
11月 05 13:22:38 han2015 systemd[1]: isc-dhcp-server.service: Main process exited, code=exited, status=1/FAILURE
这是因为默认没有配置子网,而 dhcpd 默认是自动根据子网 IP 段确定绑定网卡的。
添加子网配置:
subnet 192.168.128.0 netmask 255.255.255.0 {
range 192.168.128.64 192.168.128.127;
option routers 192.168.128.1;
}
这回可以启动成功了,但打印了一段警告文字因为它发现没有绑定物理网卡,忽略。
$ sudo systemctl status isc-dhcp-server
● isc-dhcp-server.service - ISC DHCP IPv4 server
Loaded: loaded (/lib/systemd/system/isc-dhcp-server.service; disabled; vendor preset: enabled)
Active: active (running) since 日 2017-11-05 13:47:46 CST; 6s ago
Docs: man:dhcpd(8)
Main PID: 23106 (dhcpd)
CGroup: /system.slice/isc-dhcp-server.service
└─23106 dhcpd -user dhcpd -group dhcpd -f -4 -pf /run/dhcp-server/dhcpd.pid -cf /etc/ltsp/dhcpd.conf
11月 05 13:47:46 han2015 dhcpd[23106]:
11月 05 13:47:46 han2015 dhcpd[23106]:
11月 05 13:47:46 han2015 dhcpd[23106]: No subnet declaration for enp5s0 (no IPv4 addresses).
11月 05 13:47:46 han2015 dhcpd[23106]: ** Ignoring requests on enp5s0. If this is not what
11月 05 13:47:46 han2015 dhcpd[23106]: you want, please write a subnet declaration
11月 05 13:47:46 han2015 dhcpd[23106]: in your dhcpd.conf file for the network segment
11月 05 13:47:46 han2015 dhcpd[23106]: to which interface enp5s0 is attached. **
11月 05 13:47:46 han2015 dhcpd[23106]:
11月 05 13:47:46 han2015 dhcpd[23106]: Sending on Socket/fallback/fallback-net
11月 05 13:47:46 han2015 dhcpd[23106]: Server starting service.
再启动虚拟机,这回获取 IP 地址成功了,但启动失败,因为还没配置好网络启动。
看了一下文档 man dhcpd.conf
,filename
指定启动文件名(路径),next-server
指定获取启动文件的服务器。
同时看文档说明,allow bootp
和 allow booting
都是默认开启的,通常不必手动配置。
安装 tftpd-hpa
,同样可禁止其自动启动(临时使用)。
$ sudo systemctl disable tftpd-hpa
tftpd-hpa.service is not a native service, redirecting to systemd-sysv-install
Executing /lib/systemd/systemd-sysv-install disable tftpd-hpa
insserv: warning: current start runlevel(s) (empty) of script `tftpd-hpa' overrides LSB defaults (2 3 4 5).
insserv: warning: current stop runlevel(s) (0 1 2 3 4 5 6) of script `tftpd-hpa' overrides LSB defaults (0 1 6).
另外发现其可执行文件名为 in.tftpd
,指定使用的 tftp 文件夹为 /var/lib/tftpboot
。
$ sudo systemctl status tftpd-hpa
● tftpd-hpa.service - LSB: HPA's tftp server
Loaded: loaded (/etc/init.d/tftpd-hpa; bad; vendor preset: enabled)
Active: active (running) since 日 2017-11-05 14:09:29 CST; 2min 1s ago
Docs: man:systemd-sysv-generator(8)
CGroup: /system.slice/tftpd-hpa.service
└─23964 /usr/sbin/in.tftpd --listen --user tftp --address :69 --secure /var/lib/tftpboot
按安装文档说明,从软件仓库下载 netboot/netboot.tar.gz,
解压到 tftp 文件夹,DHCP 配置 filename 为 pxelinux.0
即可启动安装。
如何更进一步的控制安装过程呢?解压 netboot.tar.gz
查看其内容如下:
$ ls -Al
总用量 8
lrwxrwxrwx 1 hanyong hanyong 47 4月 20 2016 ldlinux.c32 -> ubuntu-installer/amd64/boot-screens/ldlinux.c32
lrwxrwxrwx 1 hanyong hanyong 33 4月 20 2016 pxelinux.0 -> ubuntu-installer/amd64/pxelinux.0
lrwxrwxrwx 1 hanyong hanyong 35 4月 20 2016 pxelinux.cfg -> ubuntu-installer/amd64/pxelinux.cfg
drwxrwxr-x 3 hanyong hanyong 4096 4月 20 2016 ubuntu-installer
-rw-rw-r-- 1 hanyong hanyong 58 4月 20 2016 version.info
$ ls -Al pxelinux.cfg/
总用量 0
lrwxrwxrwx 1 hanyong hanyong 28 4月 20 2016 default -> ../boot-screens/syslinux.cfg
使用了 syslinux 配置,这是什么? 简单看了下 SYSLINUX 是可在 DOS/FAT 文件系统下运行的 boot loader, 目的是简化(在 DOS/Windows)下第一次安装 Linux。 而 PXELINUX 是 SYSLINUX 的衍生,是符合 iPXE 规范的网络启动镜像。
看了下其配置文件内容如下:
# D-I config version 2.0
# search path for the c32 support libraries (libcom32, libutil etc.)
path ubuntu-installer/amd64/boot-screens/
include ubuntu-installer/amd64/boot-screens/menu.cfg
default ubuntu-installer/amd64/boot-screens/vesamenu.c32
prompt 0
timeout 0
很显然,其支持从网络上继续拉取更多启动所需文件。
DHCP 服务器子网添加配置并重启:
filename "pxelinux.0";
重启虚拟机,果然成功启动到安装界面。可见当 TFTP 与 DHCP 与同一台服务器时,DHCP 不必配置 next-server
。
说到 boot loader,怎能不想起熟悉而强大的 grub 呢? 看了下 Grub 网络启动 的文档, 首先准备网络启动的 grub 文件夹,放到 tftp 目录下。
$ grub-mknetdir --net-directory=/var/lib/tftpboot/ --subdir=/boot/grub/ -d /usr/lib/grub/i386-pc/
Netboot directory for i386-pc created. Configure your DHCP server to point to /var/lib/tftpboot/boot/grub/i386-pc/core.0
简单比较了下生成的目录 /var/lib/tftpboot/boot/grub/i386-pc/
下的文件,自动生成了 core.0
和 grub.cfg
,其他文件都跟源文件是一样的。
而看了下 grub.cfg
的内容,只是尝试加载 /boot/grub/grub.cfg
。
$ cat /var/lib/tftpboot/boot/grub/i386-pc/grub.cfg
source /boot/grub//grub.cfg
注意这里的根目录是 grub 的根目录,不是 Linux 系统的根目录。
按照提示配置使用 core.0
启动,修改 DHCP 服务器配置如下并重启:
filename "boot/grub/i386-pc/core.0";
重启虚拟机果然成功启动到 grub 界面。
按 grub 文档说明,启动成功后 TFTP 上的文件可在 grub 下通过 (tftp)
设备访问,
还可以通过 (tftp,server-ip)
指定要访问的 TFTP 服务器 IP,访问网络像访问本地文件一样方便,简直强大到没谁了。
另外 grub 还提供了若干变量查询网络相关信息,如 net_default_ip
。
实际测试发现:
-
ls
命令看不到(tftp)
设备,也看不到 TFTP 上的文件, 但添加grub.cfg
文件后是可以进入 grub 菜单的,source
,cat
等命令也是可以读取到文件的。 所以只是ls
不支持查询 TFTP,相应的search
命令也不能用,但实际访问文件是 OK 的。 -
tftp 文件夹下建立软连接,发现目标文件在 tftp 目录外时访问不到,貌似 grub tftp 客户端能够识别软链接,出乎意料的高级。 解决办法(1)使用硬连接,但硬连接不能跨设备。(2) tftp 目录本身可以是软连接。
查看 grub 的镜像和模块说明,pxeboot.img
是 PXE 启动镜像的头,可以尝试自己做 PXE 启动镜像。
看了下 grub-mkimage
的文档,其输出格式已经支持 PXE 启动镜像 i386-pc-pxe
,可以方便的自定义 PXE 启动镜像。
PXE 启动镜像会自动设置好 root 为 tftp 路径,grub-mkimage
制作镜像时不需要设置 --config
。
最后 DHCP 服务器配置好域名和 DNS 服务器,就可以使用自定义 grub 配置启动 ubuntu 网络安装了。
物理机网卡也桥接到了 br0,在 libvirt 中配置为 local 网络。 虚拟机切换到物理机网络只需要将网络配置从 nat 修改为 local 即可。
物理机路由器默认也开启了 DHCP,两个 DHCP 冲突后不知会如何处理。 先在我们的 DHCP 中配置物理机子网,DHCP 网段与路由器的网段区分开。 DHCP 添加如下 subnet 配置并重启:
subnet 192.168.100.0 netmask 255.255.255.0 {
range 192.168.100.32 192.168.100.63;
option routers 192.168.100.1;
filename "grub-i386-pc-pxe.img";
}
多次重启测试,第一次报错 “Error: No configuration methods succeeded”,随后几次访问到路由器的 DHCP 服务无法启动。
一个局域网不应该有多个 DHCP 服务。关闭路由器的 DHCP 服务后即启动成功。
新建一个使用 UEFI 固件的虚拟机 node2,libvirt 配置 domain/os
下添加如下配置:
<loader>OVMF.fd</loader>
启动后报错启动镜像格式不对。
UEFI 固件应加载 efi 启动器,grub-mkimage
制作一个 grub efi 启动器拷贝到 tftp 目录,修改 DHCP 配置并重启。
重启虚拟机可以启动到 grub 界面,但是无法访问 tftp。
看了下 grub efi 没有 pxe 相关模块,只有 tftp 模块,制作 efi 启动器时加上 tftp 模块, 重启虚拟机后 root 未设置好,手动设置好 root 和 prefix 后还是不能访问 tftp。
使用 grub-mknetdir
制作 efi PXE 启动器,按提示更新 DHCP 配置并重启。
$ grub-mknetdir --net-directory /repo/tftp/ --subdir=/grub -d /usr/lib/grub/x86_64-efi
Netboot directory for x86_64-efi created. Configure your DHCP server to point to /repo/tftp/grub/x86_64-efi/core.efi
结果更悲剧,重启虚拟机后只能进入 grub rescue 模式。
grub-mknetdir
添加上若干模块重新制作,grub 能够进入 normal 模式了,但跟最开始一样,还是无法访问。
考虑到 iPXE 刚启动时有个报错:“Error: Operation not supported”, 不知道是否跟这个有关,先跳过不管吧。
物理机使用 UEFI 网络启动成功,可见虚拟机启动失败应该是虚拟机 UEFI 固件的问题。
看了下 ubuntu 16.04 仓库的 ovmf 版本是 20160408
,在 ubuntu 17.10 的仓库上可以找到更新版本 20170911
,但安装此新版本后还是问题依旧。
$ sudo aptitude versions ovmf
软件包 ovmf:
i 0~20160408.ffea0a2c-2 xenial 500
p 0~20170911.5dfba97c-1 artful 500
注意到虚拟机启动时有显示一个 iPXE 的版本号 iPXE 1.0.0+git-20150424.a25a16d-1ubuntu1
。
看了下果然 iPXE 是另一个独立的软件包。
$ dpkg -l '*pxe*'
期望状态=未知(u)/安装(i)/删除(r)/清除(p)/保持(h)
| 状态=未安装(n)/已安装(i)/仅存配置(c)/仅解压缩(U)/配置失败(F)/不完全安装(H)/触发器等待(W)/触发器未决(T)
|/ 错误?=(无)/须重装(R) (状态,错误:大写=故障)
||/ 名称 版本 体系结构: 描述
+++-===========================-==================-==================-===========================================================
ii ipxe-qemu 1.0.0+git-20150424 all PXE boot firmware - ROM images for qemu
un pxelinux <无> <无> (无可用描述)
$ sudo aptitude show ipxe-qemu
软件包: ipxe-qemu
状态: 已安装
自动安装: 是
Multi-Arch: foreign
版本号: 1.0.0+git-20150424.a25a16d-1ubuntu1
优先级: 可选
部分: admin
维护者: Ubuntu Developers <[email protected]>
体系: all
未压缩尺寸: 2,086 k
提供: ipxe-qemu:i386 (= 1.0.0+git-20150424.a25a16d-1ubuntu1)
描述: PXE boot firmware - ROM images for qemu
iPXE is network boot firmware. It supports a variety of network cards, including some wireless cards, and variety of network
protocols (traditional DHCP, BOOTP and TFTP and also HTTP, iSCSI, SAN via FCoE and Infiniband). It supports scripting.
It is possible to use iPXE as a PXE ROM in the network card or to chainload it from other boot methods.
This package provides boot code for the qemu emulated network cards in as boot ROMs.
主页: http://ipxe.org/
看了下 ubuntu 17.10 上也有其新版本: https://launchpad.net/ubuntu/artful/amd64/ipxe-qemu 。
还好这些包都没有依赖,但是安装新版本后好像还是不行,really20150424
什么意思,还是旧版吗?
$ sudo aptitude versions ipxe-qemu
软件包 ipxe-qemu:
p A 1.0.0+git-20150424.a25a16d-1ubuntu1 xenial 500
i A 1.0.0+git-20161027.b991c67+really20150424.a25a16d-1ubuntu2 artful 500
看了下 ipxe-qemu
保护了若干网卡的文件:
$ dpkg -L ipxe-qemu
/.
/usr
/usr/lib
/usr/lib/ipxe
/usr/lib/ipxe/qemu
/usr/lib/ipxe/qemu/efi-e1000.rom
/usr/lib/ipxe/qemu/efi-eepro100.rom
/usr/lib/ipxe/qemu/efi-ne2k_pci.rom
/usr/lib/ipxe/qemu/efi-pcnet.rom
/usr/lib/ipxe/qemu/efi-rtl8139.rom
/usr/lib/ipxe/qemu/efi-virtio.rom
/usr/lib/ipxe/qemu/pxe-e1000.rom
/usr/lib/ipxe/qemu/pxe-eepro100.rom
/usr/lib/ipxe/qemu/pxe-ne2k_isa.rom
/usr/lib/ipxe/qemu/pxe-ne2k_pci.rom
/usr/lib/ipxe/qemu/pxe-pcnet.rom
/usr/lib/ipxe/qemu/pxe-rtl8139.rom
/usr/lib/ipxe/qemu/pxe-virtio.rom
# ... ...
尝试换了一个网卡类型 rtl8139
,还是不行。
看了下 iPXE 官网下载页面,可以尝试自己构建。iPXE git 很慢,可从 github 仓库拉代码。
sudo aptitude install gcc binutils make perl liblzma-dev mtools
git clone [email protected]:ipxe/ipxe.git
cd ipxe/src
make bin-x86_64-efi/ipxe.efi
构建 virtio.efirom
失败,但构建 ipxe.efi
和 rtl8139.efirom
都可以成功。
$ make bin-x86_64-efi/virtio.efirom -j8
# ... ...
[VERSION] bin-x86_64-efi/version.virtio.efidrv.o
[AR] bin-x86_64-efi/blib.a
ar: 正在创建 bin-x86_64-efi/blib.a
[LD] bin-x86_64-efi/virtio.efidrv.tmp
--defsym:2:未定义的符号‘obj_virtio’在表达式中被引用
Makefile.housekeeping:1179: recipe for target 'bin-x86_64-efi/virtio.efidrv.tmp' failed
make: *** [bin-x86_64-efi/virtio.efidrv.tmp] Error 1
rm bin-x86_64-efi/version.virtio.efidrv.o
$ make bin-x86_64-efi/ipxe.efi -j8
[VERSION] bin-x86_64-efi/version.ipxe.efi.o
[LD] bin-x86_64-efi/ipxe.efi.tmp
[FINISH] bin-x86_64-efi/ipxe.efi
rm bin-x86_64-efi/version.ipxe.efi.o
$ make bin-x86_64-efi/rtl8139.efirom -j8
[VERSION] bin-x86_64-efi/version.rtl8139.efidrv.o
[LD] bin-x86_64-efi/rtl8139.efidrv.tmp
[FINISH] bin-x86_64-efi/rtl8139.efidrv
[FINISH] bin-x86_64-efi/rtl8139.efirom
rm bin-x86_64-efi/rtl8139.efidrv bin-x86_64-efi/version.rtl8139.efidrv.o
直接用新编译的 rom 替换系统安装的 rom,重启虚拟机可看到 iPXE 版本变了,然而 grub 访问 tftp 还是不行。
参考: https://wiki.ubuntu.com/LiveCDNetboot
- LiveCD 解压,并设置 nfs 共享。
- 启动 LiveCD 内核,设置参数
boot=casper netboot=nfs nfsroot=server:/path
。
本机安装 capser 软件包后 man capser
可以查看相关参数说明,
简单看了下 toram
参数应该很有用,拷贝到内存可以保持断网后正常运行(确认?)。
参考:
- https://linux.cn/article-3511-1.html
- https://help.ubuntu.com/community/DisklessUbuntuHowto
- https://www.kernel.org/doc/Documentation/filesystems/nfs/nfsroot.txt
- 定制 initrd,设置
MODULES=netboot
。启动内核时设置root=/dev/nfs nfsroot=xx
。 - 通过内核参数
ip=xx
设置 IP,系统内去掉网络设置。 - 订正 fstab。
- 禁用 grub update,脚本
/etc/kernel/postinst.d/zz-update-grub
。