如何构建 Netboot 服务器,第 1 部分

一些计算机网络需要在多台物理机器上维护相同的软件安装和配置。 一个这样的环境是学校的计算机实验室。 一种 网络引导 服务器可以设置为通过网络为整个操作系统提供服务,以便可以从一个中央位置配置客户端计算机。 本教程将展示一种构建网络引导服务器的方法。

本教程的第 1 部分将介绍如何创建网络引导服务器和映像。 第 2 部分将展示如何将 Kerberos 认证的主目录添加到网络引导配置。

初始配置

首先下载其中一个 Fedora 服务器的 网络安装 映像,将其刻录到 CD 上,然后启动将被重新格式化的服务器。 我们只需要一个典型的“最小安装” Fedora 服务器作为我们的起点,我们将使用命令行添加安装完成后所需的任何其他包。

注意:对于本教程,我们将使用 Fedora 28. 其他版本的“最小安装”中可能包含一组略有不同的软件包。 如果您从不同版本的 Fedora,那么如果预期的文件或命令不可用,您可能需要进行一些故障排除。

一旦你有你的最小安装 Fedora 服务器启动并运行,登录然后使用以下命令成为 root:

$ sudo -i

设置主机名:

# MY_HOSTNAME=server-01.example.edu
# hostnamectl set-hostname $MY_HOSTNAME

注意:Red Hat 建议静态名称和临时名称都与 DNS 中用于机器的完全限定域名 (FQDN) 匹配,例如 host。example.com (了解主机名)。

注意:本指南旨在便于复制和粘贴。 您可能需要自定义的任何值都将表示为 MY_* 变量,您可以在运行其余命令之前对其进行调整。 请注意,如果您注销,变量分配将被清除。

笔记: Fedora 28 默认情况下,服务器倾向于将大量日志记录输出转储到控制台。 您可能希望通过运行以下命令暂时禁用控制台日志记录: sysctl -w kernel.printk=0

接下来,我们需要服务器上的静态网络地址。 以下命令序列应找到并适当地重新配置您的默认网络连接:

# MY_DNS1=192.0.2.91
# MY_DNS2=192.0.2.92
# MY_IP=192.0.2.158
# MY_PREFIX=24
# MY_GATEWAY=192.0.2.254
# DEFAULT_DEV=$(ip route show default | awk '{print $5}')
# DEFAULT_CON=$(nmcli d show $DEFAULT_DEV | sed -n '/^GENERAL.CONNECTION:/s!.*:s*!! p')
# nohup bash << END
nmcli con mod "$DEFAULT_CON" connection.id "$DEFAULT_DEV"
nmcli con mod "$DEFAULT_DEV" connection.interface-name "$DEFAULT_DEV"
nmcli con mod "$DEFAULT_DEV" ipv4.method disabled
nmcli con up "$DEFAULT_DEV"
nmcli con add con-name br0 ifname br0 type bridge
nmcli con mod br0 bridge.stp no
nmcli con mod br0 ipv4.dns $MY_DNS1,$MY_DNS2
nmcli con mod br0 ipv4.addresses $MY_IP/$MY_PREFIX
nmcli con mod br0 ipv4.gateway $MY_GATEWAY
nmcli con mod br0 ipv4.method manual
nmcli con up br0
nmcli con add con-name br0-slave0 ifname "$DEFAULT_DEV" type bridge-slave master br0
nmcli con up br0-slave0
END

注意:上面的最后一组命令包含在“nohup”脚本中,因为它会暂时禁用网络。 nohup 命令应该允许 nmcli 命令完成运行,即使您的 ssh 连接断开也是如此。 请注意,连接可能需要 10 秒左右才能恢复,并且如果您更改了服务器的 IP 地址,则必须启动新的 ssh 连接。

注意:上述网络配置创建了一个 网桥 在默认连接之上,以便我们可以直接在服务器上运行虚拟机实例以供以后测试。 如果您不想直接在服务器上测试 netboot 映像,则可以跳过创建网桥并直接在默认网络连接上设置静态 IP 地址。

安装和配置 NFS4

首先安装 nfs-utils 包:

# dnf install -y nfs-utils

创建顶层 伪文件系统 用于 NFS 导出并将其共享到您的网络:

# MY_SUBNET=192.0.2.0
# mkdir /export
# echo "/export -fsid=0,ro,sec=sys,root_squash $MY_SUBNET/$MY_PREFIX" > /etc/exports

SELinux 会干扰网络引导服务器的运行。 为其配置异常超出了本教程的范围,因此我们将禁用它:

# sed -i '/GRUB_CMDLINE_LINUX/s/"$/ audit=0 selinux=0"/' /etc/default/grub
# grub2-mkconfig -o /boot/grub2/grub.cfg
# sed -i 's/SELINUX=enforcing/SELINUX=disabled/' /etc/sysconfig/selinux
# setenforce 0

注意:编辑 grub 命令行应该是不必要的,但简单地编辑 /etc/sysconfig/selinux 被证明在重启后无效 Fedora 服务器 28 在测试期间,所以这里设置了“selinux=0”标志,以确保双倍的确定。

现在,将 NFS 服务的例外添加到本地防火墙并启动 NFS 服务:

# firewall-cmd --add-service nfs
# firewall-cmd --runtime-to-permanent
# systemctl enable nfs-server.service
# systemctl start nfs-server.service

创建网络引导映像

现在我们的 NFS 服务器已启动并运行,我们需要为其提供操作系统映像以服务于客户端计算机。 我们将从一个非常小的图像开始,并在一切正常后添加到它。

首先,创建一个新目录来存储我们的图像:

# mkdir /fc28

使用“dnf”命令在新目录下构建镜像,只包含几个基本包:

# dnf -y --releasever=28 --installroot=/fc28 install fedora-release systemd passwd rootfiles sudo dracut dracut-network nfs-utils vim-minimal dnf

重要的是,上述命令中省略了“内核”包。 在安装它们之前,我们需要调整将包含在“initramfs”映像中的驱动程序集,该映像在首次安装内核时自动构建。 特别是,我们需要禁用“hostonly”模式,以便 initramfs 映像可以在更广泛的硬件平台上运行,并且我们需要添加对网络和 NFS 的支持:

# echo 'hostonly=no' > /fc28/etc/dracut.conf.d/hostonly.conf
# echo 'add_dracutmodules+=" network nfs "' > /fc28/etc/dracut.conf.d/netboot.conf

现在,安装内核:

# dnf -y --installroot=/fc28 install kernel

设置规则以防止内核被更新:

# echo 'exclude=kernel-*' >> /fc28/etc/dnf/dnf.conf

设置语言环境:

# echo 'LANG="en_US.UTF-8"' > /fc28/etc/locale.conf

注意:如果区域设置没有正确配置,某些程序(例如 GNOME 终端)将无法运行。

设置客户端的主机名:

# MY_CLIENT_HOSTNAME=client-01.example.edu
# echo $MY_CLIENT_HOSTNAME > /fc28/etc/hostname

禁用记录到控制台:

# echo 'kernel.printk = 0 4 1 7' > /fc28/etc/sysctl.d/00-printk.conf

在网络引导映像中定义一个本地“liveuser”:

# echo 'liveuser:x:1000:1000::/home/liveuser:/bin/bash' >> /fc28/etc/passwd
# echo 'liveuser::::::::' >> /fc28/etc/shadow
# echo 'liveuser:x:1000:' >> /fc28/etc/group
# echo 'liveuser:::' >> /fc28/etc/gshadow

允许“liveuser” sudo:

# echo 'liveuser ALL=(ALL) NOPASSWD: ALL' > /fc28/etc/sudoers.d/liveuser

启用自动主目录创建:

# dnf install -y --installroot=/fc28 authselect oddjob-mkhomedir
# echo 'dirs /home' > /fc28/etc/rwtab.d/home
# chroot /fc28 authselect select sssd with-mkhomedir --force
# chroot /fc28 systemctl enable oddjobd.service

由于多个客户端将同时挂载我们的镜像,我们需要配置镜像,使其以只读模式运行:

# sed -i 's/^READONLY=no$/READONLY=yes/' /fc28/etc/sysconfig/readonly-root

将日志配置为转到 RAM 而不是永久存储:

# sed -i 's/^#Storage=auto$/Storage=volatile/' /fc28/etc/systemd/journald.conf

配置 DNS:

# MY_DNS1=192.0.2.91
# MY_DNS2=192.0.2.92
# cat << END > /fc28/etc/resolv.conf
nameserver $MY_DNS1
nameserver $MY_DNS2
END

解决了编写本教程时只读根挂载存在的一些错误(BZ1542567):

# echo 'dirs /var/lib/gssproxy' > /fc28/etc/rwtab.d/gssproxy
# cat << END > /fc28/etc/rwtab.d/systemd
dirs /var/lib/systemd/catalog
dirs /var/lib/systemd/coredump
END

最后,我们可以为我们的镜像创建 NFS 文件系统并将其共享到我们的子网:

# mkdir /export/fc28
# echo '/fc28 /export/fc28 none bind 0 0' >> /etc/fstab
# mount /export/fc28
# echo "/export/fc28 -ro,sec=sys,no_root_squash $MY_SUBNET/$MY_PREFIX" > /etc/exports.d/fc28.exports
# exportfs -vr

创建引导加载程序

现在我们有一个可用于 netboot 的操作系统,我们需要一个引导加载程序来在客户端系统上启动它。 对于此设置,我们将使用 iPXE. 请注意,您应该在此处登录您的用户帐户,而不是 root。

注意:本节和下一节 — 使用 QEMU 进行测试 — 可以在单独的计算机上完成; 它们不必在 netboot 服务器上运行。

安装 git 并使用它来下载 iPXE:

$ sudo dnf install -y git
$ git clone https://git.ipxe.org/ipxe.git $HOME/ipxe

现在我们需要为我们的引导加载程序创建一个特殊的启动脚本:

$ cat << 'END' > $HOME/ipxe/init.ipxe
#!ipxe

prompt --key 0x02 --timeout 2000 Press Ctrl-B for the iPXE command line... && shell ||

dhcp || exit
set prefix file:///linux
chain ${prefix}/boot.cfg || exit
END

启用“文件”下载协议:

$ echo '#define DOWNLOAD_PROTO_FILE' > $HOME/ipxe/src/config/local/general.h

安装 C 编译器及相关工具和库:

$ sudo dnf groupinstall -y "C Development Tools and Libraries"

构建引导加载程序:

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

记下新编译的引导加载程序在哪里。 下一节我们将需要它:

$ IPXE_FILE="$HOME/ipxe/src/bin-x86_64-efi/ipxe.efi"

使用 QEMU 进行测试

此部分是可选的,但您需要复制 EFI系统分区 如下所示在您的物理机器上配置它们以进行网络引导。

注意:如果您想要一个完全无盘的系统,您还可以将文件复制到 TFTP 服务器并从 DHCP 引用该服务器。

为了使用 QEMU 测试我们的引导加载程序,我们将创建一个仅包含 EFI 系统分区和启动文件的小磁盘映像。

首先为 EFI 系统分区创建所需的目录布局,并将我们在上一节中创建的引导加载程序复制到它:

$ mkdir -p $HOME/esp/efi/boot
$ mkdir $HOME/esp/linux
$ cp $IPXE_FILE $HOME/esp/efi/boot/bootx64.efi

下面的命令应该识别我们的 netboot 映像正在使用的内核版本,并将其存储在一个变量中,以便在其余配置指令中使用:

$ DEFAULT_VER=$(ls -c /fc28/lib/modules | head -n 1)

定义我们的客户端计算机将使用的引导配置:

$ MY_DNS1=192.0.2.91
$ MY_DNS2=192.0.2.92
$ MY_NFS4=server-01.example.edu
$ cat << END > $HOME/esp/linux/boot.cfg
#!ipxe

kernel --name kernel.efi ${prefix}/vmlinuz-$DEFAULT_VER initrd=initrd.img ro ip=dhcp rd.peerdns=0 nameserver=$MY_DNS1 nameserver=$MY_DNS2 root=nfs4:$MY_NFS4:/fc28 console=tty0 console=ttyS0,115200n8 audit=0 selinux=0 quiet
initrd --name initrd.img ${prefix}/initramfs-$DEFAULT_VER.img
boot || exit
END

注意:上面的引导脚本显示了一个最小的 example 如何让 iPXE 进入 netboot Linux。 更复杂的配置是可能的。 最值得注意的是,iPXE 支持交互式启动菜单,可以使用默认选择和超时进行配置。 更高级的 iPXE 脚本可以用于 example默认从本地磁盘引导操作系统,并且只有在用户在倒计时达到零之前按下一个键时才进行网络引导操作。

将 Linux 内核及其关联的 initramfs 复制到 EFI 系统分区:

$ cp $(find /fc28/lib/modules -maxdepth 2 -name 'vmlinuz' | grep -m 1 $DEFAULT_VER) $HOME/esp/linux/vmlinuz-$DEFAULT_VER
$ cp $(find /fc28/boot -name 'init*' | grep -m 1 $DEFAULT_VER) $HOME/esp/linux/initramfs-$DEFAULT_VER.img

我们生成的目录布局应如下所示:

esp
├── efi
│   └── boot
│       └── bootx64.efi
└── linux
    ├── boot.cfg
    ├── initramfs-4.18.18-200.fc28.x86_64.img
    └── vmlinuz-4.18.18-200.fc28.x86_64

要将我们的 EFI 系统分区与 QEMU 一起使用,我们需要创建一个包含它的小型“uefi.img”磁盘映像,然后将其连接到 QEMU 作为主引导驱动器。

首先安装必要的工具:

$ sudo dnf install -y parted dosfstools

现在创建“uefi.img”文件并将文件从“esp”目录复制到其中:

$ ESP_SIZE=$(du -ks $HOME/esp | cut -f 1)
$ dd if=/dev/zero of=$HOME/uefi.img count=$((${ESP_SIZE}+5000)) bs=1KiB
$ UEFI_DEV=$(sudo losetup --show -f $HOME/uefi.img)
$ sudo parted ${UEFI_DEV} -s mklabel gpt mkpart EFI FAT16 1MiB 100% toggle 1 boot
$ mkfs -t msdos ${UEFI_DEV}p1
$ mkdir -p $HOME/mnt
$ sudo mount ${UEFI_DEV}p1 $HOME/mnt
$ cp -r $HOME/esp/* $HOME/mnt
$ sudo umount $HOME/mnt
$ sudo losetup -d ${UEFI_DEV}

注意:在物理计算机上,您只需将文件从“esp”目录复制到计算机现有的 EFI 系统分区。 您不需要“uefi.img”文件来启动物理计算机。

注意:在物理计算机上,如果该名称的文件已经存在,您可以重命名“bootx64.efi”文件,但如果这样做,您可能需要编辑计算机的 BIOS 设置并将重命名的 efi 文件添加到引导列表。

接下来我们需要安装 qemu 包:

$ sudo dnf install -y qemu-system-x86

允许 QEMU 访问我们在本教程的“初始配置”部分创建的网桥:

$ sudo su -
# echo 'allow br0' > /etc/qemu/bridge.conf
# exit

创建“OVMF_VARS.fd”映像的副本以存储我们虚拟机的持久 BIOS 设置:

$ cp /usr/share/edk2/ovmf/OVMF_VARS.fd $HOME

现在,启动虚拟机:

$ qemu-system-x86_64 -machine accel=kvm -nographic -m 1024 -drive if=pflash,format=raw,unit=0,file=/usr/share/edk2/ovmf/OVMF_CODE.fd,readonly=on -drive if=pflash,format=raw,unit=1,file=$HOME/OVMF_VARS.fd -drive if=ide,format=raw,file=$HOME/uefi.img -net bridge,br=br0 -net nic,model=virtio

如果一切顺利,您应该会看到类似于下图所示的结果:

您可以使用“shutdown”命令退出虚拟机并返回服务器:

$ sudo shutdown -h now

注意:如果出现问题并且虚拟机挂起,您可能需要启动到服务器的新 ssh 会话并使用“kill”命令终止“qemu-system-x86_64”进程。

添加到图像

添加到镜像应该是一个简单的事情,在服务器上 chroot’ing 到镜像并运行“dnf install ”。

可以在 netboot 映像上安装的内容没有限制。 完整的图形安装应该可以完美运行。

这是一个 example 如何将我们的最小网络引导映像升级为完整的图形安装:

# for i in dev dev/pts dev/shm proc sys run; do mount -o bind /$i /fc28/$i; done
# chroot /fc28 /usr/bin/bash --login
# dnf -y groupinstall "Fedora Workstation"
# dnf -y remove gnome-initial-setup
# systemctl disable sshd.service
# systemctl enable gdm.service
# systemctl set-default graphical.target
# sed -i 's/SELINUX=enforcing/SELINUX=disabled/' /etc/sysconfig/selinux
# logout
# for i in run sys proc dev/shm dev/pts dev; do umount /fc28/$i; done

或者,您可能希望为“liveuser”帐户启用自动登录:

# sed -i '/daemon/a AutomaticLoginEnable=true' /fc28/etc/gdm/custom.conf
# sed -i '/daemon/a AutomaticLogin=liveuser' /fc28/etc/gdm/custom.conf