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

2018-12-24 23:49:00

有些計算機網路需要在各個物理機器上維護相同的軟體和設定。學校的計算機實驗室就是這樣的一個環境。 網路引導 伺服器能夠被設定為基於網路去提供一個完整的作業系統,以便於用戶端計算機從一個中央位置獲取設定。本教學將向你展示構建一台網路引導伺服器的一種方法。

本教學的第一部分將包括建立一台網路引導伺服器和映象。第二部分將展示如何去新增 Kerberos 驗證的家目錄到網路引導設定中。

初始化設定

首先去下載 Fedora 伺服器的 netinst 映象,將它燒錄到一張光碟上,然後用它引導伺服器來重新格式化。我們只需要一個典型的 Fedora Server 的“最小化安裝”來作為我們的開端,安裝完成後,我們可以使用命令列去新增我們需要的任何額外的包。

注意:本教學中我們將使用 Fedora 28。其它版本在“最小化安裝”中包含的包可能略有不同。如果你使用的是不同的 Fedora 版本,如果一個預期的檔案或命令不可用,你可能需要做一些偵錯。

最小化安裝的 Fedora Server 執行起來之後,以 root 使用者登入:

$ sudo -i

並設定主機名字:

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

注意:Red Hat 建議靜態和臨時名字應都要與這個機器在 DNS 中的完全合格域名相匹配,比如 host.example.com(了解主機名字)。

注意:本指南為了方便“複製貼上”。需要自定義的任何值都宣告為一個 MY_* 變數,在你執行剩餘命令之前,你可能需要調整它。如果你登出之後,變數的賦值將被清除。

注意:Fedora 28 Server 在預設情況下往往會轉儲大量的紀錄檔到控制台上。你可以通過執行命令: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 << ENDnmcli 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 disablednmcli con up "$DEFAULT_DEV"nmcli con add con-name br0 ifname br0 type bridgenmcli con mod br0 bridge.stp nonmcli con mod br0 ipv4.dns $MY_DNS1,$MY_DNS2nmcli con mod br0 ipv4.addresses $MY_IP/$MY_PREFIXnmcli con mod br0 ipv4.gateway $MY_GATEWAYnmcli con mod br0 ipv4.method manualnmcli con up br0nmcli con add con-name br0-slave0 ifname "$DEFAULT_DEV" type bridge-slave master br0nmcli con up br0-slave0END

注意:上面最後的一組命令被封裝到一個 nohup 指令碼中,因為它將臨時禁用網路。這個 nohup 命令可以讓 nmcli 命令執行完成,即使你的 SSH 連線斷開。注意,連線恢復可能需要 10 秒左右的時間,如果你改變了伺服器 IP 地址,你將需要重新啟動一個新的 SSH 連線。

注意:上面的網路設定在預設的連線之上建立了一個 網橋,這樣我們在後面的測試中就可以直接執行一個虛擬機器範例。如果你不想在這台伺服器上去直接測試網路引導映象,你可以跳過建立網橋的命令,並直接在你的預設網路連線上設定靜態 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 被證明重新啟動後是無效的,因此這樣做再次確保設定了 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

在上面的命令中省略了很重要的 kernel 包。在它們被安裝完成之前,我們需要去調整一下 initramfs 映象中包含的驅動程式集,kernel 首次安裝時將自動構建這個映象。尤其是,我們需要禁用 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

現在,安裝 kernel 包:

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

設定一個阻止 kernel 包被更新的規則:

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

設定 locale:

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

注意:如果 locale 沒有正確設定,一些程式(如 GNOME Terminal)將無法正常工作。

設定用戶端的主機名字:

$ 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

設定紀錄檔輸出到記憶體而不是持久儲存中:

$ 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.confnameserver $MY_DNS1nameserver $MY_DNS2END

繞開編寫本教學時存在的根目錄唯讀掛載的 bug(BZ1542567):

$ echo 'dirs /var/lib/gssproxy' > /fc28/etc/rwtab.d/gssproxy$ cat << END > /fc28/etc/rwtab.d/systemddirs /var/lib/systemd/catalogdirs /var/lib/systemd/coredumpEND

最後,為我們映象建立 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

建立引導載入器

現在,我們已經有了可以進行網路引導的作業系統,我們需要一個引導載入器去從用戶端系統上啟動它。在本教學中我們使用的是 iPXE

注意:本節和接下來的節使用 QEMU 測試,也能在另外一台單獨的計算機上來完成;它們並不需要在網路引導伺服器上來執行。

安裝 git 並使用它去下載 iPXE:

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

現在我們需要去為我們的引導載入器建立一個指定的啟動指令碼:

$ cat << 'END' > $HOME/ipxe/init.ipxe#!ipxeprompt --key 0x02 --timeout 2000 Press Ctrl-B for the iPXE command line... && shell ||dhcp || exitset prefix file:///linuxchain ${prefix}/boot.cfg || exitEND

啟動 “file” 下載協定:

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

安裝 C 編譯器以及相關的工具和庫:

$ 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

下面的命令將識別我們的引導載入器映象正在使用的核心版本,並將它儲存到一個變數中,以備後續的設定命令去使用它:

$ 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#!ipxekernel --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 quietinitrd --name initrd.img \${prefix}/initramfs-$DEFAULT_VER.imgboot || exitEND

注意:上面的引導指令碼展示了如何使用 iPXE 去網路引導 Linux 的最小範例。還可以做更多更複雜的設定。值得注意的是,iPXE 支援互動式引導選單,它可以讓你設定預設選項和超時時間。比如,一個更高階一點 iPXE 指令碼可以預設從本地磁碟引導一個作業系統,如果在倒計時結束之前使用者按下了一個鍵,才會去網路引導一個作業系統。

複製 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

要讓 QEMU 去使用我們的 EFI 系統分割區,我們需要去建立一個小的 uefi.img 磁碟映象來包含它,然後將它連線到 QEMU 作為主引導驅動器。

開始安裝必需的工具:

$ 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=$(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}

注意:在物理計算機上,你只需要從 esp 目錄中複製檔案到計算機上已存在的 EFI 系統分割區中。你不需要使用 uefi.img 檔案去引導物理計算機。

注意:在一個物理計算機上,如果檔名已存在,你可以重新命名 bootx64.efi 檔案,如果你重新命名了它,就需要去編輯計算機的 BIOS 設定,並新增重命令後的 efi 檔案到引導列表中。

接下來我們需要去安裝 qemu 包:

$ dnf install -y qemu-system-x86

允許 QEMU 存取我們在本教學“初始化設定”一節中建立的網橋:

$ echo 'allow br0' > /etc/qemu/bridge.conf

建立一個 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 進映象,然後執行 dnf install <package_name>

在網路引導映象中並不限制你能安裝什麼包。一個完整的圖形化安裝應該能夠完美地工作。

下面是一個如何將最小化安裝的網路引導映象變成完整的圖形化安裝的範例:

$ 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