如何在不啟動 livecd 的情況下縮小根文件系統
我發現自己需要重新排列系統的分區,以便將之前根文件系統下的數據移動到專用的掛載點。這些卷都在 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 身份執行。
- 確保系統處於穩定狀態
確保沒有其他人在使用它,並且沒有其他重要的事情發生。停止提供服務的單元(如 httpd 或 ftpd)可能是個好主意,只是為了確保外部連接不會中斷中間的事情。
systemctl stop httpd systemctl stop nfs-server # and so on....
- 解除安裝所有未使用的文件系統
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...
- 製作臨時根 注意:如果 /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
- 解除安裝舊根
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,他為我提供了前者的連結。