Centos

如何在不啟動 livecd 的情況下縮小根文件系統

  • December 31, 2021

我發現自己需要重新排列系統的分區,以便將之前根文件系統下的數據移動​​到專用的掛載點。這些卷都在 LVM 中,所以這相對容易:創建新卷,將數據移動到其中,縮小根文件系統,然後在適當的位置掛載新卷。

問題是第 3 步,縮小根文件系統。涉及的文件系統是ext4,所以支持線上調整大小;但是,在掛載時,文件系統只能增長。要縮小分區需要解除安裝它,這對於正常執行的根分區當然是不可能的。

Web 上的答案似乎圍繞著啟動 LiveCD 或其他應急媒體,進行收縮操作,然後重新啟動到已安裝的系統。但是,有問題的系統是遠端的,我只能通過 SSH 訪問。我可以重新啟動,但無法從控制台啟動應急光碟和執行操作。

如何在保持遠端 shell 訪問的同時解除安裝根文件系統?

在解決這個問題時,http: //www.ivarch.com/blogs/oss/2007/01/resize-a-live-root-fs-a-howto.shtml 提供的資訊是關鍵。但是,該指南適用於非常舊的 RHEL 版本,並且各種資訊已過時。

下面的說明是為與 CentOS 7 一起工作而設計的,但它們應該很容易轉移到任何執行 systemd 的發行版。所有命令都以 root 身份執行。

  1. 確保系統處於穩定狀態

確保沒有其他人在使用它,並且沒有其他重要的事情發生。停止提供服務的單元(如 httpd 或 ftpd)可能是個好主意,只是為了確保外部連接不會中斷中間的事情。

systemctl stop httpd
systemctl stop nfs-server
# and so on....
  1. 解除安裝所有未使用的文件系統
umount -a

這將為根卷本身和各種臨時/系統 FS 列印許多“目標忙”警告。這些暫時可以忽略。重要的是除了根文件系統本身之外,沒有任何磁碟文件系統保持掛載。驗證這一點:

# mount alone provides the info, but column makes it possible to read
mount | column -t

如果您看到任何磁碟上的文件系統仍然掛載,那麼某些不應該的東西仍在執行。檢查它正在使用什麼fuser

# if necessary:
yum install psmisc
# then:
fuser -vm <mountpoint>
systemctl stop <whatever>
umount -a
# repeat as required...
  1. 製作臨時根 注意:如果 /tmp 是 / 上的目錄,如果我們使用 /tmp/tmproot,我們將無法在此過程中解除安裝 /。因此,可能需要使用替代掛載點,例如 /tmproot。
mkdir /tmp/tmproot
mount -t tmpfs none /tmp/tmproot
mkdir /tmp/tmproot/{proc,sys,dev,run,usr,var,tmp,oldroot}
cp -ax /{bin,etc,mnt,sbin,lib,lib64} /tmp/tmproot/
cp -ax /usr/{bin,sbin,lib,lib64} /tmp/tmproot/usr/
cp -ax /var/{account,empty,lib,local,lock,nis,opt,preserve,run,spool,tmp,yp} /tmp/tmproot/var/

這會創建一個非常小的根系統,它會破壞(除其他外)聯機幫助頁查看(否/usr/share)、使用者級自定義(否/root/home)等等。這是故意的,因為它鼓勵不要在這種由陪審團操縱的根系統中停留超過必要的時間。

此時,您還應該確保安裝了所有必要的軟體,因為它也肯定會破壞包管理器。瀏覽所有步驟,並確保您擁有必要的執行檔。 4. 轉入根

mount --make-rprivate / # necessary for pivot_root to work
pivot_root /tmp/tmproot /tmp/tmproot/oldroot
for i in dev proc sys run; do mount --move /oldroot/$i /$i; done

systemd 預設情況下會導致掛載允許子樹共享(與 一樣mount --make-shared),這會導致pivot_root失敗。因此,我們使用 全域關閉它mount --make-rprivate /。系統和臨時文件系統被整體移動到新的根目錄中。這是使它完全起作用的必要條件;用於與 systemd 通信的套接字,除其他外,存在於 中/run,因此無法使正在執行的程序關閉它。 5. 確保遠端訪問在轉換過程中倖存下來

systemctl restart sshd
systemctl status sshd

重新啟動 sshd 後,確保您可以進入,方法是打開另一個終端並通過 ssh 再次連接到機器。如果不能,請在繼續之前解決問題。

確認可以再次連接後,退出目前使用的 shell 並重新連接。這允許剩餘的分叉sshd退出並確保新的不持有/oldroot。 6. 關閉仍然使用舊根的所有內容

fuser -vm /oldroot

這將列印仍然保留在舊根目錄中的程序列表。在我的系統上,它看起來像這樣:

             USER        PID ACCESS COMMAND
/oldroot:    root     kernel mount /oldroot
             root          1 ...e. systemd
             root        549 ...e. systemd-journal
             root        563 ...e. lvmetad
             root        581 f..e. systemd-udevd
             root        700 F..e. auditd
             root        723 ...e. NetworkManager
             root        727 ...e. irqbalance
             root        730 F..e. tuned
             root        736 ...e. smartd
             root        737 F..e. rsyslogd
             root        741 ...e. abrtd
             chrony      742 ...e. chronyd
             root        743 ...e. abrt-watch-log
             libstoragemgmt    745 ...e. lsmd
             root        746 ...e. systemd-logind
             dbus        747 ...e. dbus-daemon
             root        753 ..ce. atd
             root        754 ...e. crond
             root        770 ...e. agetty
             polkitd     782 ...e. polkitd
             root       1682 F.ce. master
             postfix    1714 ..ce. qmgr
             postfix   12658 ..ce. pickup

在解除安裝之前,您需要處理這些程序中的每一個/oldroot。蠻力方法只kill $PID適用於每個人,但這可能會破壞事情。要更溫和地做到這一點:

systemctl | grep running

這將創建一個正在執行的服務列表。您應該能夠將其與持有的程序列表相關聯/oldroot,然後為每個程序發出systemctl restart。一些服務會拒絕在臨時根目錄中出現並進入失敗狀態;這些暫時不重要。

如果您要調整大小的根驅動器是 LVM 驅動器,您可能還需要重新啟動其他一些正在執行的服務,即使它們沒有出現在由fuser -vm /oldroot. 如果您發現無法在步驟 7 下調整 LVM 驅動器的大小,請嘗試systemctl restart systemd-udevd.

有些流程不能通過 simple 來處理systemctl restart。對我來說,這些包括auditd(不喜歡被殺死systemctl,所以只想要一個kill -15)。這些可以單獨處理。

通常,您會發現的最後一個過程就是systemd它本身。為此,執行systemctl daemon-reexec.

完成後,表格應如下所示:

             USER        PID ACCESS COMMAND
/oldroot:    root     kernel mount /oldroot
  1. 解除安裝舊根
umount /oldroot

此時,您可以執行所需的任何操作。最初的問題需要一個簡單的resize2fs呼叫,但你可以在這裡做任何你想做的事情;另一個案例是將根文件系統從一個簡單的分區轉移到 LVM/RAID/其他。 8. 將根轉回

mount <blockdev> /oldroot
mount --make-rprivate / # again
pivot_root /oldroot /oldroot/tmp/tmproot
for i in dev proc sys run; do mount --move /tmp/tmproot/$i /$i; done

這是第 4 步的直接反轉。 9. 處理臨時根

重複步驟 5 和 6,但使用/tmp/tmproot代替/oldroot。然後:

umount /tmp/tmproot
rmdir /tmp/tmproot

由於它是 tmpfs,此時臨時根溶解在乙太中,再也不會被看到。 10. 把東西放回原處

再次掛載文件系統:

   mount -a

此時,您還應該根據您在步驟 7 中所做的任何調整進行/etc/fstab更新。grub.cfg

重新啟動任何失敗的服務:

   systemctl | grep failed
   systemctl restart <whatever>

再次允許共享子樹:

   mount --make-rshared /

啟動停止的服務單元 - 你可以使用這個命令:

   systemctl isolate default.target

你完成了。

非常感謝 Andrew Wood,他在 RHEL4 上完成了這一演變,以及 steve,他為我提供了前者的連結。

引用自:https://unix.stackexchange.com/questions/226872