如何構(gòu)建一臺(tái)網(wǎng)絡(luò)引導(dǎo)服務(wù)器(一)
有些計(jì)算機(jī)網(wǎng)絡(luò)需要在各個(gè)物理機(jī)器上維護(hù)相同的軟件和配置。學(xué)校的計(jì)算機(jī)實(shí)驗(yàn)室就是這樣的一個(gè)環(huán)境。 網(wǎng)絡(luò)引導(dǎo) 服務(wù)器能夠被配置為基于網(wǎng)絡(luò)去提供一個(gè)完整的操作系統(tǒng),以便于客戶端計(jì)算機(jī)從一個(gè)中央位置獲取配置。本教程將向你展示構(gòu)建一臺(tái)網(wǎng)絡(luò)引導(dǎo)服務(wù)器的一種方法。
本教程的***部分將包括創(chuàng)建一臺(tái)網(wǎng)絡(luò)引導(dǎo)服務(wù)器和鏡像。第二部分將展示如何去添加 Kerberos 驗(yàn)證的家目錄到網(wǎng)絡(luò)引導(dǎo)配置中。
初始化配置
首先去下載 Fedora 服務(wù)器的 netinst 鏡像,將它刻錄到一張光盤上,然后用它引導(dǎo)服務(wù)器來重新格式化。我們只需要一個(gè)典型的 Fedora Server 的“最小化安裝”來作為我們的開端,安裝完成后,我們可以使用命令行去添加我們需要的任何額外的包。
注意:本教程中我們將使用 Fedora 28。其它版本在“最小化安裝”中包含的包可能略有不同。如果你使用的是不同的 Fedora 版本,如果一個(gè)預(yù)期的文件或命令不可用,你可能需要做一些調(diào)試。
最小化安裝的 Fedora Server 運(yùn)行起來之后,以 root 用戶登入:
$ sudo -i
并設(shè)置主機(jī)名字:
$ MY_HOSTNAME=server-01.example.edu
$ hostnamectl set-hostname $MY_HOSTNAME
注意:Red Hat 建議靜態(tài)和臨時(shí)名字應(yīng)都要與這個(gè)機(jī)器在 DNS 中的完全合格域名相匹配,比如 host.example.com(了解主機(jī)名字)。
注意:本指南為了方便“復(fù)制粘貼”。需要自定義的任何值都聲明為一個(gè)
MY_*
變量,在你運(yùn)行剩余命令之前,你可能需要調(diào)整它。如果你注銷之后,變量的賦值將被清除。注意:Fedora 28 Server 在默認(rèn)情況下往往會(huì)轉(zhuǎn)儲(chǔ)大量的日志到控制臺(tái)上。你可以通過運(yùn)行命令:
sysctl -w kernel.printk=0
去禁用控制臺(tái)日志輸出。
接下來,我們需要在我們的服務(wù)器上配置一個(gè)靜態(tài)網(wǎng)絡(luò)地址。運(yùn)行下面的一系列命令將找到并重新配置你的默認(rèn)網(wǎng)絡(luò)連接:
$ 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
注意:上面***的一組命令被封裝到一個(gè)
nohup
腳本中,因?yàn)樗鼘⑴R時(shí)禁用網(wǎng)絡(luò)。這個(gè)nohup
命令可以讓nmcli
命令運(yùn)行完成,即使你的 SSH 連接斷開。注意,連接恢復(fù)可能需要 10 秒左右的時(shí)間,如果你改變了服務(wù)器 IP 地址,你將需要重新啟動(dòng)一個(gè)新的 SSH 連接。注意:上面的網(wǎng)絡(luò)配置在默認(rèn)的連接之上創(chuàng)建了一個(gè) 網(wǎng)橋,這樣我們在后面的測試中就可以直接運(yùn)行一個(gè)虛擬機(jī)實(shí)例。如果你不想在這臺(tái)服務(wù)器上去直接測試網(wǎng)絡(luò)引導(dǎo)鏡像,你可以跳過創(chuàng)建網(wǎng)橋的命令,并直接在你的默認(rèn)網(wǎng)絡(luò)連接上配置靜態(tài) IP 地址。
安裝和配置 NFS4
從安裝 nfs-utils 包開始:
$ dnf install -y nfs-utils
為發(fā)布 NFS 去創(chuàng)建一個(gè)***的 偽文件系統(tǒng),然后在你的網(wǎng)絡(luò)上共享它:
$ MY_SUBNET=192.0.2.0
$ mkdir /export
$ echo "/export -fsid=0,ro,sec=sys,root_squash $MY_SUBNET/$MY_PREFIX" > /etc/exports
SELinux 會(huì)干擾網(wǎng)絡(luò)引導(dǎo)服務(wù)器的運(yùn)行。為它配置例外規(guī)則超出了本教程中,因此我們這里直接禁用它:
$ 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
注意:應(yīng)該不需要編輯 grub 命令行,但我們在測試過程中發(fā)現(xiàn),直接編輯
/etc/sysconfig/selinux
被證明重啟后是無效的,因此這樣做再次確保設(shè)置了selinux=0
標(biāo)志。
現(xiàn)在,在本地防火墻中為 NFS 服務(wù)添加一個(gè)例外規(guī)則,然后啟動(dòng) NFS 服務(wù):
$ firewall-cmd --add-service nfs
$ firewall-cmd --runtime-to-permanent
$ systemctl enable nfs-server.service
$ systemctl start nfs-server.service
創(chuàng)建網(wǎng)絡(luò)引導(dǎo)鏡像
現(xiàn)在我們的 NFS 服務(wù)器已經(jīng)啟動(dòng)運(yùn)行了,我們需要為它提供一個(gè)操作系統(tǒng)鏡像,以便于它提供給客戶端計(jì)算機(jī)。我們將從一個(gè)非常小的鏡像開始,等一切順利之后再添加。
首先,創(chuàng)建一個(gè)存放我們鏡像的新目錄:
$ mkdir /fc28
使用 dnf
命令在新目錄下用幾個(gè)基礎(chǔ)包去構(gòu)建鏡像:
$ dnf -y --releasever=28 --installroot=/fc28 install fedora-release systemd passwd rootfiles sudo dracut dracut-network nfs-utils vim-minimal dnf
在上面的命令中省略了很重要的 kernel
包。在它們被安裝完成之前,我們需要去調(diào)整一下 initramfs
鏡像中包含的驅(qū)動(dòng)程序集,kernel
***安裝時(shí)將自動(dòng)構(gòu)建這個(gè)鏡像。尤其是,我們需要禁用 hostonly
模式,以便于 initramfs
鏡像能夠在各種硬件平臺(tái)上正常工作,并且我們還需要添加對網(wǎng)絡(luò)和 NFS 的支持:
$ echo 'hostonly=no' > /fc28/etc/dracut.conf.d/hostonly.conf
$ echo 'add_dracutmodules+=" network nfs "' > /fc28/etc/dracut.conf.d/netboot.conf
現(xiàn)在,安裝 kernel
包:
$ dnf -y --installroot=/fc28 install kernel
設(shè)置一個(gè)阻止 kernel
包被更新的規(guī)則:
$ echo 'exclude=kernel-*' >> /fc28/etc/dnf/dnf.conf
設(shè)置 locale:
$ echo 'LANG="en_US.UTF-8"' > /fc28/etc/locale.conf
注意:如果 locale 沒有正確配置,一些程序(如 GNOME Terminal)將無法正常工作。
設(shè)置客戶端的主機(jī)名字:
$ MY_CLIENT_HOSTNAME=client-01.example.edu
$ echo $MY_CLIENT_HOSTNAME > /fc28/etc/hostname
禁用控制臺(tái)日志輸出:
$ echo 'kernel.printk = 0 4 1 7' > /fc28/etc/sysctl.d/00-printk.conf
定義網(wǎng)絡(luò)引導(dǎo)鏡像中的本地 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
啟用自動(dòng)創(chuàng)建家目錄:
$ 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
由于多個(gè)客戶端將會(huì)同時(shí)掛載我們的鏡像,我們需要去配置鏡像工作在只讀模式中:
$ sed -i 's/^READONLY=no$/READONLY=yes/' /fc28/etc/sysconfig/readonly-root
配置日志輸出到內(nèi)存而不是持久存儲(chǔ)中:
$ 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
繞開編寫本教程時(shí)存在的根目錄只讀掛載的 bug(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
***,為我們鏡像創(chuàng)建 NFS 文件系統(tǒng),并將它共享到我們的子網(wǎng)中:
$ 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
創(chuàng)建引導(dǎo)加載器
現(xiàn)在,我們已經(jīng)有了可以進(jìn)行網(wǎng)絡(luò)引導(dǎo)的操作系統(tǒng),我們需要一個(gè)引導(dǎo)加載器去從客戶端系統(tǒng)上啟動(dòng)它。在本教程中我們使用的是 iPXE。
注意:本節(jié)和接下來的節(jié)使用 QEMU 測試,也能在另外一臺(tái)單獨(dú)的計(jì)算機(jī)上來完成;它們并不需要在網(wǎng)絡(luò)引導(dǎo)服務(wù)器上來運(yùn)行。
安裝 git
并使用它去下載 iPXE:
$ dnf install -y git
$ git clone http://git.ipxe.org/ipxe.git $HOME/ipxe
現(xiàn)在我們需要去為我們的引導(dǎo)加載器創(chuàng)建一個(gè)指定的啟動(dòng)腳本:
$ 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
啟動(dòng) “file” 下載協(xié)議:
$ echo '#define DOWNLOAD_PROTO_FILE' > $HOME/ipxe/src/config/local/general.h
安裝 C 編譯器以及相關(guān)的工具和庫:
$ dnf groupinstall -y "C Development Tools and Libraries"
構(gòu)建引導(dǎo)加載器:
$ cd $HOME/ipxe/src
$ make clean
$ make bin-x86_64-efi/ipxe.efi EMBED=../init.ipxe
記下新編譯的引導(dǎo)加載器的存儲(chǔ)位置。我們將在接下來的節(jié)中用到它:
$ IPXE_FILE="$HOME/ipxe/src/bin-x86_64-efi/ipxe.efi"
用 QEMU 測試
這一節(jié)是可選的,但是你需要去復(fù)制下面顯示在物理機(jī)器上的 EFI 系統(tǒng)分區(qū) 的布局,在網(wǎng)絡(luò)引導(dǎo)時(shí)需要去配置它們。
注意:如果你想實(shí)現(xiàn)一個(gè)完全的無盤系統(tǒng),你也可以復(fù)制那個(gè)文件到一個(gè) TFTP 服務(wù)器,然后從 DHCP 上指向那臺(tái)服務(wù)器。
為了使用 QEMU 去測試我們的引導(dǎo)加載器,我們繼續(xù)去創(chuàng)建一個(gè)僅包含一個(gè) EFI 系統(tǒng)分區(qū)和我們的啟動(dòng)文件的、很小的磁盤鏡像。
從創(chuàng)建 EFI 系統(tǒng)分區(qū)所需要的目錄布局開始,然后把我們在前面節(jié)中創(chuàng)建的引導(dǎo)加載器復(fù)制進(jìn)去:
$ mkdir -p $HOME/esp/efi/boot
$ mkdir $HOME/esp/linux
$ cp $IPXE_FILE $HOME/esp/efi/boot/bootx64.efi
下面的命令將識別我們的引導(dǎo)加載器鏡像正在使用的內(nèi)核版本,并將它保存到一個(gè)變量中,以備后續(xù)的配置命令去使用它:
$ DEFAULT_VER=$(ls -c /fc28/lib/modules | head -n 1)
定義我們的客戶端計(jì)算機(jī)將使用的引導(dǎo)配置:
$ 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
注意:上面的引導(dǎo)腳本展示了如何使用 iPXE 去網(wǎng)絡(luò)引導(dǎo) Linux 的最小示例。還可以做更多更復(fù)雜的配置。值得注意的是,iPXE 支持交互式引導(dǎo)菜單,它可以讓你配置默認(rèn)選項(xiàng)和超時(shí)時(shí)間。比如,一個(gè)更高級一點(diǎn) iPXE 腳本可以默認(rèn)從本地磁盤引導(dǎo)一個(gè)操作系統(tǒng),如果在倒計(jì)時(shí)結(jié)束之前用戶按下了一個(gè)鍵,才會(huì)去網(wǎng)絡(luò)引導(dǎo)一個(gè)操作系統(tǒng)。
復(fù)制 Linux 內(nèi)核并分配 initramfs 給 EFI 系統(tǒng)分區(qū):
$ 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
我們最終的目錄布局應(yīng)該看起來像下面的樣子:
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
要讓 QEMU 去使用我們的 EFI 系統(tǒng)分區(qū),我們需要去創(chuàng)建一個(gè)小的 uefi.img
磁盤鏡像來包含它,然后將它連接到 QEMU 作為主引導(dǎo)驅(qū)動(dòng)器。
開始安裝必需的工具:
$ dnf install -y parted dosfstools
現(xiàn)在創(chuàng)建 uefi.img
文件,并將 esp
目錄中的文件復(fù)制進(jìn)去:
$ 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=$(losetup --show -f $HOME/uefi.img)
$ parted ${UEFI_DEV} -s mklabel gpt mkpart EFI FAT16 1MiB 100% toggle 1 boot
$ mkfs -t msdos ${UEFI_DEV}p1
$ mkdir -p $HOME/mnt
$ mount ${UEFI_DEV}p1 $HOME/mnt
$ cp -r $HOME/esp/* $HOME/mnt
$ umount $HOME/mnt
$ losetup -d ${UEFI_DEV}
注意:在物理計(jì)算機(jī)上,你只需要從
esp
目錄中復(fù)制文件到計(jì)算機(jī)上已存在的 EFI 系統(tǒng)分區(qū)中。你不需要使用uefi.img
文件去引導(dǎo)物理計(jì)算機(jī)。注意:在一個(gè)物理計(jì)算機(jī)上,如果文件名已存在,你可以重命名
bootx64.efi
文件,如果你重命名了它,就需要去編輯計(jì)算機(jī)的 BIOS 設(shè)置,并添加重命令后的 efi 文件到引導(dǎo)列表中。
接下來我們需要去安裝 qemu 包:
$ dnf install -y qemu-system-x86
允許 QEMU 訪問我們在本教程“初始化配置”一節(jié)中創(chuàng)建的網(wǎng)橋:
$ echo 'allow br0' > /etc/qemu/bridge.conf
創(chuàng)建一個(gè) OVMF_VARS.fd
鏡像的副本去保存我們虛擬機(jī)的持久 BIOS 配置:
$ cp /usr/share/edk2/ovmf/OVMF_VARS.fd $HOME
現(xiàn)在,啟動(dòng)虛擬機(jī):
$ 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
如果一切順利,你將看到類似下圖所示的結(jié)果:
你可以使用 shutdown
命令關(guān)閉虛擬機(jī)回到我們的服務(wù)器上:
$ sudo shutdown -h now
注意:如果出現(xiàn)了錯(cuò)誤或虛擬機(jī)掛住了,你可能需要啟動(dòng)一個(gè)新的 SSH 會(huì)話去連接服務(wù)器,使用
kill
命令去終止qemu-system-x86_64
進(jìn)程。
鏡像中添加包
鏡像中添加包應(yīng)該是一個(gè)很簡單的問題,在服務(wù)器上 chroot
進(jìn)鏡像,然后運(yùn)行 dnf install <package_name>
。
在網(wǎng)絡(luò)引導(dǎo)鏡像中并不限制你能安裝什么包。一個(gè)完整的圖形化安裝應(yīng)該能夠***地工作。
下面是一個(gè)如何將最小化安裝的網(wǎng)絡(luò)引導(dǎo)鏡像變成完整的圖形化安裝的示例:
$ 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
用戶的自動(dòng)登錄:
$ sed -i '/daemon/a AutomaticLoginEnable=true' /fc28/etc/gdm/custom.conf
$ sed -i '/daemon/a AutomaticLogin=liveuser' /fc28/etc/gdm/custom.conf