在 的文章中,我們展示了如何建立一個網路引導映象,在那個映象中使用了一個名為 liveuser
帳戶,它的家目錄位於記憶體中,重新啟動後家目錄中的內容將全部消失。然而很多使用者都希望機器重新啟動後儲存他們的檔案和設定。因此,在本系列的第二部分,我們將向你展示如何在第一部分的基礎上,重新設定網路引導映象,以便 活動目錄 中的使用者帳戶可以進行登入,然後從一個 NFS 伺服器上自動掛載他們的家目錄。
本系列的第三部分,我們將向你展示網路引導用戶端如何與中心化設定的 iPXE 引導選單進行互動。
按以前的文章 “使用 Kerberos 強化共用的 NFS Home 目錄安全性” 的指導來做這個設定。
刪除本系列文章第一部分中建立的 liveuser
帳戶:
$ sudo -i# sed -i '/automaticlogin/Id' /fc28/etc/gdm/custom.conf# rm -f /fc28/etc/sudoers.d/liveuser# for i in passwd shadow group gshadow; do sed -i '/^liveuser:/d' /fc28/etc/$i; done
接下來,我們需要將 NTP、KRB5 和 SSSD 的組態檔複製進用戶端使用的映象中,以便於它們能夠使用同一個帳戶:
# MY_HOSTNAME=$(</etc/hostname)# MY_DOMAIN=${MY_HOSTNAME#*.}# dnf -y --installroot=/fc28 install ntp krb5-workstation sssd# cp /etc/ntp.conf /fc28/etc# chroot /fc28 systemctl enable ntpd.service# cp /etc/krb5.conf.d/${MY_DOMAIN%%.*} /fc28/etc/krb5.conf.d# cp /etc/sssd/sssd.conf /fc28/etc/sssd
在已設定的識別服務的基礎上,重新設定 sssd 提供認證服務:
# sed -i '/services =/s/$/, pam/' /fc28/etc/sssd/sssd.conf
另外,設定成確保用戶端不能更改這個帳戶密碼:
# sed -i '/id_provider/a \ \ ad_maximum_machine_account_password_age = 0' /fc28/etc/sssd/sssd.conf
另外,複製 nfsnobody 的定義:
# for i in passwd shadow group gshadow; do grep "^nfsnobody:" /etc/$i >> /fc28/etc/$i; done
接下來,你將執行一個 chroot
將用戶端映象加入到活動目錄。從刪除預置在網路引導映象中同名的計算機帳戶開始:
# MY_USERNAME=jsmith# MY_CLIENT_HOSTNAME=$(</fc28/etc/hostname)# adcli delete-computer "${MY_CLIENT_HOSTNAME%%.*}" -U "$MY_USERNAME"
在網路引導映象中如果有 krb5.keytab
檔案,也刪除它:
# rm -f /fc28/etc/krb5.keytab
chroot
到網路引導映象中:
# 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
執行一個加入操作:
# MY_USERNAME=jsmith# MY_HOSTNAME=$(</etc/hostname)# MY_DOMAIN=${MY_HOSTNAME#*.}# MY_REALM=${MY_DOMAIN^^}# MY_OU="cn=computers,dc=${MY_DOMAIN//./,dc=}"# adcli join $MY_DOMAIN --login-user="$MY_USERNAME" --computer-name="${MY_HOSTNAME%%.*}" --host-fqdn="$MY_HOSTNAME" --user-principal="host/$MY_HOSTNAME@$MY_REALM" --domain-ou="$MY_OU"
現在登出 chroot,並清除 root 使用者的命令歷史:
# logout# for i in run sys proc dev/shm dev/pts dev; do umount /fc28/$i; done# > /fc28/root/.bash_history
我們希望用戶端登入後自動掛載使用者家目錄。為實現這個目的,我們將要使用 pam_mount
模組。安裝和設定 pam_mount
:
# dnf install -y --installroot=/fc28 pam_mount# cat << END > /fc28/etc/security/pam_mount.conf.xml<?xml version="1.0" encoding="utf-8" ?><!DOCTYPE pam_mount SYSTEM "pam_mount.conf.xml.dtd"><pam_mount><debug enable="0" /><volume uid="1400000000-1499999999" fstype="nfs4" server="$MY_HOSTNAME" path="/home/%(USER)" mountpoint="/home/%(USER)" options="sec=krb5" /><mkmountpoint enable="1" remove="0" /><msg-authpw>Password:</msg-authpw></pam_mount>END
重新設定 PAM 去使用 pam_mount
:
# dnf install -y patch# cp -r /fc28/usr/share/authselect/default/sssd /fc28/etc/authselect/custom# echo 'initgroups: files' >> /fc28/etc/authselect/custom/sssd/nsswitch.conf# patch /fc28/etc/authselect/custom/sssd/system-auth << END@@ -12 +12,2 @@-auth sufficient pam_sss.so forward_pass+auth requisite pam_mount.so {include if "with-pammount"}+auth sufficient pam_sss.so {if "with-pammount":use_first_pass|forward_pass}@@ -35,2 +36,3 @@ session required pam_unix.so+session optional pam_mount.so {include if "with-pammount"} session optional pam_sss.soEND# patch /fc28/etc/authselect/custom/sssd/password-auth << END@@ -9 +9,2 @@-auth sufficient pam_sss.so forward_pass+auth requisite pam_mount.so {include if "with-pammount"}+auth sufficient pam_sss.so {if "with-pammount":use_first_pass|forward_pass}@@ -32,2 +33,3 @@ session required pam_unix.so+session optional pam_mount.so {include if "with-pammount"} session optional pam_sss.soEND# chroot /fc28 authselect select custom/sssd with-pammount --force
另外,要確保從用戶端上總是可解析 NFS 伺服器的主機名:
# MY_IP=$(host -t A $MY_HOSTNAME | awk '{print $4}')# echo "$MY_IP $MY_HOSTNAME ${MY_HOSTNAME%%.*}" >> /fc28/etc/hosts
可選,允許所有使用者可以使用 sudo
:
# echo '%users ALL=(ALL) NOPASSWD: ALL' > /fc28/etc/sudoers.d/users
在一個 nfsroot 連線建立之後,目前版本的 nfs-utils 可能很難為家目錄建立一個從用戶端到 NFS 伺服器的第二個連線。當嘗試去存取家目錄時,用戶端將被掛起。因此,為了共用網路引導映象,我們將使用一個不同的協定(iSCSI)來規避這個問題。
首先 chroot
到映象中,重新設定它的 initramfs
,讓它從一個 iSCSI 根目錄中去引導:
# 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 install -y iscsi-initiator-utils# sed -i 's/nfs/iscsi/' /etc/dracut.conf.d/netboot.conf# echo 'omit_drivers+=" qedi "' > /etc/dracut.conf.d/omit-qedi.conf# echo 'blacklist qedi' > /etc/modprobe.d/blacklist-qedi.conf# KERNEL=$(ls -c /lib/modules | head -n 1)# INITRD=$(find /boot -name 'init*' | grep -m 1 $KERNEL)# dracut -f $INITRD $KERNEL# logout# for i in run sys proc dev/shm dev/pts dev; do umount /fc28/$i; done# > /fc28/root/.bash_history
在測試時,qedi 驅動會破壞 iSCSI,因此我們將它禁用。
接著,建立一個 fc28.img
稀疏檔案。這個稀疏檔案代表 iSCSI 目標的後備記憶體:
# FC28_SIZE=$(du -ms /fc28 | cut -f 1)# dd if=/dev/zero of=/fc28.img bs=1MiB count=0 seek=$(($FC28_SIZE*2))
(如果你有一個可使用的獨立分割區或磁碟驅動器,也可以用它,而不用再去建立這個稀疏檔案了。)
接著,使用一個檔案系統去格式化映象、掛載它、然後將網路引導映象複製進去:
# mkfs -t xfs -L NETROOT /fc28.img# TEMP_MNT=$(mktemp -d)# mount /fc28.img $TEMP_MNT# cp -a /fc28/* $TEMP_MNT# umount $TEMP_MNT
在使用 SquashFS 測試時,用戶端偶爾會出現小狀況。似乎是因為 SquashFS 在多處理器用戶端上沒法執行隨機 I/O。(更多內容見 squashfs 讀取卡頓的奇怪案例)。如果你希望使用檔案系統壓縮來提升吞吐效能,ZFS 或許是個很好的選擇。
如果你對 iSCSI 伺服器的吞吐效能要求非常高(比如,成百上千的用戶端要連線它),可能需要使用帶 負載均衡 的 Ceph 叢集了。更多相關內容,請檢視 使用 HAProxy 和 Keepalived 負載均衡的 Ceph 物件閘道器。
為了給我們的用戶端提供網路引導映象,安裝 scsi-target-utils
包:
# dnf install -y scsi-target-utils
設定 iSCSI 守護程式去提供 fc28.img
檔案:
# MY_REVERSE_HOSTNAME=$(echo $MY_HOSTNAME | tr '.' "\n" | tac | tr "\n" '.' | cut -b -${#MY_HOSTNAME})# cat << END > /etc/tgt/conf.d/fc28.conf<target iqn.$MY_REVERSE_HOSTNAME:fc28> backing-store /fc28.img readonly 1</target>END
開頭的 iqn.
是 /usr/lib/dracut/modules.d/40network/net-lib.sh
所需要的。
新增一個防火牆例外,並啟用和啟動這個服務:
# firewall-cmd --add-service=iscsi-target# firewall-cmd --runtime-to-permanent# systemctl enable tgtd.service# systemctl start tgtd.service
你現在應該能夠使用 tatadm
命令看到這個映象共用了:
# tgtadm --mode target --op show
上述命令的輸出應該類似如下的內容:
Target 1: iqn.edu.example.server-01:fc28 System information: Driver: iscsi State: ready I_T nexus information: LUN information: LUN: 0 Type: controller SCSI ID: IET 00010000 SCSI SN: beaf10 Size: 0 MB, Block size: 1 Online: Yes Removable media: No Prevent removal: No Readonly: No SWP: No Thin-provisioning: No Backing store type: null Backing store path: None Backing store flags: LUN: 1 Type: disk SCSI ID: IET 00010001 SCSI SN: beaf11 Size: 10488 MB, Block size: 512 Online: Yes Removable media: No Prevent removal: No Readonly: Yes SWP: No Thin-provisioning: No Backing store type: rdwr Backing store path: /fc28.img Backing store flags: Account information: ACL information: ALL
現在,我們可以去刪除本系列文章的第一部分中建立的 NFS 共用了:
# rm -f /etc/exports.d/fc28.exports# exportfs -rv# umount /export/fc28# rmdir /export/fc28# sed -i '/^\/fc28 /d' /etc/fstab
你也可以刪除 /fc28
檔案系統,但為了以後進一步更新,你可能需要保留它。
更新 ESP 去包含啟用了 iSCSI 的 initramfs
:
$ rm -vf $HOME/esp/linux/*.fc28.*$ MY_KRNL=$(ls -c /fc28/lib/modules | head -n 1)$ cp $(find /fc28/lib/modules -maxdepth 2 -name 'vmlinuz' | grep -m 1 $MY_KRNL) $HOME/esp/linux/vmlinuz-$MY_KRNL$ cp $(find /fc28/boot -name 'init*' | grep -m 1 $MY_KRNL) $HOME/esp/linux/initramfs-$MY_KRNL.img
更新 boot.cfg
檔案去傳遞新的 root
和 netroot
引數:
$ MY_NAME=server-01.example.edu$ MY_EMAN=$(echo $MY_NAME | tr '.' "\n" | tac | tr "\n" '.' | cut -b -${#MY_NAME})$ MY_ADDR=$(host -t A $MY_NAME | awk '{print $4}')$ sed -i "s! root=[^ ]*! root=/dev/disk/by-path/ip-$MY_ADDR:3260-iscsi-iqn.$MY_EMAN:fc28-lun-1 netroot=iscsi:$MY_ADDR::::iqn.$MY_EMAN:fc28!" $HOME/esp/linux/boot.cfg
現在,你只需要從 $HOME/esp/linux
目錄中複製更新後的檔案到所有用戶端系統的 ESP 中。你應該會看到類似下面螢幕截圖的結果:
首先,複製出一個當前映象的副本:
# cp -a /fc28 /fc29
chroot
進入到映象的新副本:
# for i in dev dev/pts dev/shm proc sys run; do mount -o bind /$i /fc29/$i; done# chroot /fc29 /usr/bin/bash --login
允許更新核心:
# sed -i 's/^exclude=kernel-\*$/#exclude=kernel-*/' /etc/dnf/dnf.conf
執行升級:
# dnf distro-sync -y --releasever=29
阻止更新過的核心被再次更新:
# sed -i 's/^#exclude=kernel-\*$/exclude=kernel-*/' /etc/dnf/dnf.conf
上述命令是可選的,但是在以後,如果在映象中新增和更新了幾個包,在你的用戶端之外儲存有一個最新核心的副本,會在關鍵時刻對你非常有幫助。
清理 dnf 的包快取:
# dnf clean all
退出 chroot 並清理 root 的命令歷史:
# logout# for i in run sys proc dev/shm dev/pts dev; do umount /fc29/$i; done# > /fc29/root/.bash_history
建立 iSCSI 映象:
# FC29_SIZE=$(du -ms /fc29 | cut -f 1)# dd if=/dev/zero of=/fc29.img bs=1MiB count=0 seek=$(($FC29_SIZE*2))# mkfs -t xfs -L NETROOT /fc29.img# TEMP_MNT=$(mktemp -d)# mount /fc29.img $TEMP_MNT# cp -a /fc29/* $TEMP_MNT# umount $TEMP_MNT
定義一個新的 iSCSI 目標,指向到新的映象並匯出它:
# MY_HOSTNAME=$(</etc/hostname)# MY_REVERSE_HOSTNAME=$(echo $MY_HOSTNAME | tr '.' "\n" | tac | tr "\n" '.' | cut -b -${#MY_HOSTNAME})# cat << END > /etc/tgt/conf.d/fc29.conf<target iqn.$MY_REVERSE_HOSTNAME:fc29> backing-store /fc29.img readonly 1</target>END# tgt-admin --update ALL
新增新核心和 initramfs
到 ESP:
$ MY_KRNL=$(ls -c /fc29/lib/modules | head -n 1)$ cp $(find /fc29/lib/modules -maxdepth 2 -name 'vmlinuz' | grep -m 1 $MY_KRNL) $HOME/esp/linux/vmlinuz-$MY_KRNL$ cp $(find /fc29/boot -name 'init*' | grep -m 1 $MY_KRNL) $HOME/esp/linux/initramfs-$MY_KRNL.img
更新 ESP 的 boot.cfg
:
$ MY_DNS1=192.0.2.91$ MY_DNS2=192.0.2.92$ MY_NAME=server-01.example.edu$ MY_EMAN=$(echo $MY_NAME | tr '.' "\n" | tac | tr "\n" '.' | cut -b -${#MY_NAME})$ MY_ADDR=$(host -t A $MY_NAME | awk '{print $4}')$ cat << END > $HOME/esp/linux/boot.cfg#!ipxekernel --name kernel.efi \${prefix}/vmlinuz-$MY_KRNL initrd=initrd.img ro ip=dhcp rd.peerdns=0 nameserver=$MY_DNS1 nameserver=$MY_DNS2 root=/dev/disk/by-path/ip-$MY_ADDR:3260-iscsi-iqn.$MY_EMAN:fc29-lun-1 netroot=iscsi:$MY_ADDR::::iqn.$MY_EMAN:fc29 console=tty0 console=ttyS0,115200n8 audit=0 selinux=0 quietinitrd --name initrd.img \${prefix}/initramfs-$MY_KRNL.imgboot || exitEND
最後,從我的 $HOME/esp/linux
目錄中複製檔案到所有用戶端系統的 ESP 中去使用它吧!