Ubuntu 清理舊核心,釋放 /boot 空間
當 /boot 被舊 linux-image 套件填滿,apt 會停止設定套件。先找出可安全移除的核心,並保留目前正在開機使用的版本。
/boot 填滿舊核心時,apt 為何會停止運作
在 Ubuntu 上,每次更新核心都會將一組新檔案寫入 /boot,並保留先前的檔案。因此,容量較小的 /boot 分割區可能會填滿,導致 apt 無法完成安裝。修復分為兩個步驟。先確認主機上的哪些套件是核心,以及目前開機使用的是哪個核心,再使用 apt autoremove --purge 移除其餘核心。
操作順序很重要。正在執行的核心是絕對不能移除的套件。此外,主機可能已處於 apt 完全無法執行的狀態。請先進行診斷。
實際的失敗狀況
核心版本會在 /boot 中安裝 2 個大型檔案:壓縮核心(vmlinuz-<version>)以及 initramfs(初始 RAM 檔案系統,initrd.img-<version>;核心會先解開這個小型封存檔,再掛載真正的 root)。initramfs 會在安裝時於本機建立,因此安裝時需要可用磁碟空間,而不只是下載頻寬。磁碟空間用盡時,建置會失敗,並連帶導致套件安裝失敗。
update-initramfs: Generating /boot/initrd.img-6.8.0-64-generic
gzip: stdout: No space left on device
E: mkinitramfs failure gzip 1
update-initramfs: failed for /boot/initrd.img-6.8.0-64-generic with 1.
dpkg: error processing package linux-image-6.8.0-64-generic (--configure):
installed linux-image-6.8.0-64-generic package post-installation script subprocess returned error exit status 1版本字串會依你的系統而定。壓縮程式名稱來自 COMPRESS= 中的 /etc/initramfs-tools/initramfs.conf,因此較新的映像檔可能會將 zstd 命名為該名稱,而較舊的映像檔則會將其命名為 gzip。能識別此問題的 2 行是 No space left on device,以及其下方的 dpkg: error processing package 行。
之後,套件會停留在半設定狀態。每次後續執行 apt 時,都會再次嘗試設定該套件,以相同方式失敗,最後顯示 E: Sub-process /usr/bin/dpkg returned an error code (1)。這是除了磁碟空間之外需要注意的部分:unattended-upgrades 會依排程執行,遇到相同錯誤後停止。伺服器表面上仍然正常運作,卻會悄悄停止套用安全性修補程式。這也表示你嘗試安裝任何不相關的套件時,都會因相同錯誤而失敗,問題看起來會像是由當時新增的套件造成。因此,在 Ubuntu 上安裝 Tailscale 時失敗時,先將其視為 apt 錯誤來檢查。如果 apt update 在到達這個階段前就失敗,則是另一個問題,通常是deb822 sources 遷移後產生重複項目。
確認 /boot 是否為獨立分割區
刪除任何內容前,先確認實際要釋放的是哪個檔案系統。
findmnt /boot
findmnt -T /boot
df -h /boot /第一個命令只有在 /boot 是獨立掛載點時才會輸出一行。第二個命令一定會輸出,並列出實際存放 /boot 的檔案系統。如果兩者列出的檔案系統與 / 相同,表示 /boot 只是根檔案系統中的目錄,不會自行填滿:目前已滿的是根檔案系統,而舊核心只是眾多因素之一。此時執行 sudo apt clean,會清除 /var/cache/apt/archives 下已下載的 .deb 檔案,藉此釋放空間。若機器具有真正的 /boot 分割區,apt clean 完全不會釋放該分割區的空間,因為快取位於另一個檔案系統。
接著取得要比對的數值。
df -h /boot
ls -lh /boot/vmlinuz-$(uname -r) /boot/initrd.img-$(uname -r)將 Avail 欄位與這兩個檔案的大小比較。initrd 較大。下一次核心更新還需要足以容納另一組大約相同大小的檔案,因此如果 Avail 小於目前 initrd 的大小,下一次更新就會失敗。
尋找目前執行中的 kernel
uname -r
cat /var/run/reboot-required.pkgsuname -r 會輸出目前載入記憶體中的 kernel release 字串。請將該字串複製到其他位置。這是絕對不可移除的版本。
只有在套件要求重新開機時,第二個檔案才會存在。檔案中的 linux-image 行表示磁碟上已安裝較新的 kernel,但尚未使用,因為該版本安裝後機器尚未重新開機。如果可以,請先重新開機,再進行清理。apt 會保護目前執行中的 kernel 與最新版本,因此在舊版 kernel 上執行清理時,會比必要情況多保留一個版本。
列出 kernel 套件並查看其狀態
dpkg --list | grep -E 'linux-(image|modules|headers|tools)' | awk '{print $1, $2}'第一個欄位是 dpkg 的狀態碼。ii 表示已安裝且已完成設定。iF 表示已安裝但只完成部分設定,這正是上述升級失敗後留下的狀態。rc 表示已移除,但設定仍保留在磁碟上。這類套件不佔用 /boot 中的空間,可以安全清除。
第二個欄位表示套件類型。名稱中包含版本,例如 linux-image-6.8.0-64-generic,代表某個特定的 kernel。沒有版本的名稱,例如 linux-image-generic、linux-headers-generic 或 linux-generic,則是 meta 套件。它不包含 kernel,唯一用途是相依於最新版本的 kernel,讓 apt upgrade 能拉取新的 kernel。移除 meta 套件後,主機將不再收到 kernel 更新,而且之後不會顯示任何警告。
這些套件可分為以下幾類。linux-image-* 在 /boot 中保存壓縮後的 kernel。linux-modules-* 和 linux-modules-extra-* 在 /lib/modules 下保存驅動程式。linux-headers-* 在 /usr/src 下保存建置標頭檔,因此清除標頭檔會釋放 root filesystem 的空間,而不是 /boot 的空間。如果問題是 /boot 分割區已滿,應尋找的是 image 套件。
ls -1 /boot/vmlinuz-*
ls -1 /lib/modules/這兩份清單應彼此相符,也應與 dpkg --list 的輸出相符。若 /lib/modules 中有目錄,但找不到相符的已安裝套件,表示有人曾手動刪除檔案,留下了殘留目錄。
apt 如何決定要保留哪些核心
apt autoremove 不會移除它判定為受保護的核心,其中包括目前正在執行的核心。不同 Ubuntu 發行版本的保留政策可能不同,因此請直接查看自己的機器,不要相信任何地方記載的數字。
apt-config dump | grep -i -e neverautoremove -e versionedkernel
ls -l /etc/apt/apt.conf.d/01autoremove /etc/apt/apt.conf.d/01autoremove-kernelsAPT::NeverAutoRemove 是 apt autoremove 拒絕處理的套件名稱模式清單。APT::VersionedKernelPackages 是 apt 用來判定版本化核心套件的名稱前綴清單。在會產生 /etc/apt/apt.conf.d/01autoremove-kernels 的發行版本中,每次安裝核心套件時,/etc/kernel/postinst.d/apt-auto-removal 都會重新寫入該檔案,因此手動編輯沒有作用:下次安裝核心時,原本的修改就會被覆寫。在檔案不存在的發行版本中,apt 會在內部套用相同的保護機制。無論是哪種情況,apt-config dump 都會顯示目前系統套用的規則;該輸出就是你所使用發行版本的正確依據。
可安全執行的清理作業
sudo apt update
sudo apt autoremove --purge --dry-run--dry-run 不會變更磁碟內容,只會列出實際執行時會移除的項目。請閱讀清單。有兩種情況應立即停止。若移除清單中出現 linux-generic 或 linux-image-generic 這類 meta package,表示某個項目將其標記為自動安裝;移除後,核心便不會再更新。若移除清單中出現 uname -r 的字串,表示正在執行的核心未受到保護。這種情況不應發生,必須先調查清楚再繼續。
如果清單看起來正確,請正式執行。
sudo apt autoremove --purge
df -h /boot--purge 模式除了刪除套件,也會刪除其殘留的設定。它只能額外釋放少量空間,但能避免 dpkg --list 持續累積 rc 行,讓下一次稽核更容易閱讀。
接著確認開機選單已重新建立。移除核心套件時,系統會替你執行 update-grub,因此選單應只參照仍然存在的檔案。
sudo grep -o 'vmlinuz-[^ ]*' /boot/grub/grub.cfg | sort -u
ls -1 /boot/vmlinuz-*第一個輸出中的每個版本,都必須出現在第二個輸出中。若選單項目指向已不存在的檔案,正常運作的伺服器就可能在 GRUB 提示字元處停止啟動。這是導致 核心更新後無法啟動的 VPS 的其中一種原因;相較於事先避免,等到 rescue console 才修復困難得多。
為什麼 apt autoremove 有時不會移除任何套件
apt autoremove 只會移除標記為自動安裝的套件,也就是作為其他套件相依性而安裝的套件。您使用 apt install linux-image-6.8.0-40-generic 自行安裝的 kernel 會標記為手動安裝。無論它有多舊,autoremove 都不會移除它。
apt-mark showmanual | grep -E '^linux-'該輸出中的任何具版本號碼的 kernel 都不會被 autoremove 視為可移除項目。請使用您自己列出的版本字串,將它交還給自動相依性管理:
sudo apt-mark auto linux-image-6.8.0-40-generic linux-modules-6.8.0-40-generic
sudo apt autoremove --purge --dry-run請保留標記為手動安裝的 meta packages。它們本來就應標記為手動安裝,因為這些是您明確要求安裝的套件。
刻意移除指定的 kernel
有時您需要立即移除特定版本,而不是等到政策允許時才處理。指定 image package,讓 apt 處理其餘作業。
sudo apt purge linux-image-6.8.0-40-genericapt 會在執行任何動作前列出移除清單,因為 linux-modules-extra-* 相依於 image package,必須在同一筆交易中一併移除。這份清單是實際的安全檢查,可用來確認是否有 meta package 隨著您原本要移除的版本一併被移除。若清單中有任何非預期項目,請回答 n。接著執行 sudo apt autoremove --purge,找出已失去存在必要的 module 和 header package。
為何絕對不能移除正在執行的 kernel
已載入記憶體的 kernel 會在其檔案刪除後繼續執行,因此一開始看不出任何問題。真正發生問題的是 kernel 尚未載入的內容。清除 linux-modules-$(uname -r) 會刪除 /lib/modules/$(uname -r)/,因此下一次載入模組時會失敗:
modprobe: FATAL: Module nf_tables not found in directory /lib/modules/6.8.0-64-generic從此之後,重新載入防火牆會失敗,掛載此 kernel 自開機後尚未處理過的檔案系統類型也會失敗。同時,/boot/vmlinuz-$(uname -r) 已不存在,因此開機選單不再提供目前正在執行的 kernel,下一次重新開機時會進入其他 kernel。此機器仍持續處理網路流量,但實際上已無法正常開機。每次都要將 uname -r 與移除清單比對。
/boot 空間太滿,導致 apt 完全無法執行時
這是促使使用者尋找本頁的情況。apt autoremove 需要 dpkg 先完成半配置狀態核心套件的設定,而該步驟會重建 initramfs;重建時需要空間,但 /boot 已沒有可用空間。手動中斷這個循環一次即可。
uname -r
ls -1 /boot/initrd.img-*選擇一個版本不是 uname -r 顯示之字串的 initrd,然後刪除該單一檔案。
sudo rm /boot/initrd.img-6.8.0-40-generic
sudo apt --fix-broken install
sudo apt autoremove --purge
sudo update-grub每一行都有其原因。rm 是刻意保留的例外,會讓 dpkg 認為某個檔案存在,即使該檔案實際上不存在。現在已有足夠空間容納 initramfs,apt --fix-broken install 會完成先前失敗的設定。接著,autoremove --purge 會移除你刪除其檔案的套件,以及其他舊版本,讓 dpkg 恢復與磁碟內容一致。update-grub 會根據實際存在的檔案重建選單。不要在 rm 與 update-grub 之間重新開機,因為在此期間,選單仍可能指向你剛刪除的檔案。如果 dpkg 顯示作業已中斷,sudo dpkg --configure -a 會執行與 apt --fix-broken install 相同的修復。
dnf 系統中的相同作業
如果 VPS 執行 Fedora 或 Rocky Linux 等 RHEL 重建版,採用的機制正好相反。Debian 和 Ubuntu 透過 apt autoremove 規則保護核心,將清理工作留給您或由 unattended-upgrades 觸發;dnf 則強制套用名為 installonly_limit 的數量限制,只要安裝新核心後會超過該限制,就會自動移除最舊的核心。使用 grep installonly_limit /etc/dnf/dnf.conf 和 man 5 dnf.conf 讀取目前生效的數值,並使用 sudo dnf remove --oldinstallonly 清除現有的待清理項目。正在執行的核心同樣受到保護。如需了解兩個套件管理器之間更完整的對照,請參閱 dnf 與 apt 指令對照。
避免問題再次發生
依賴人工記得執行的清理工作,最終一定會失效。因此,應將它設定在安裝 kernel 的元件中。開啟 /etc/apt/apt.conf.d/50unattended-upgrades,尋找下列設定鍵;發行的檔案已將它們列為註解:
Unattended-Upgrade::Remove-Unused-Kernel-Packages "true";
Unattended-Upgrade::Remove-Unused-Dependencies "true";請取消註解,不要在檔案結尾再附加一份。apt 設定中,同一設定鍵的最後一個指定值會生效,因此重複設定會使檔案內容互相矛盾,也會掩蓋實際使用的值。確認解析器最後採用的設定值,並觀察一次不會變更任何內容的執行結果:
apt-config dump | grep -i 'Unattended-Upgrade::Remove'
sudo unattended-upgrade --dry-run --debug
sudo tail -n 40 /var/log/unattended-upgrades/unattended-upgrades.log日誌就是證據。它會記錄每次執行,因此因空間不足而失敗的升級,會在任何人注意到主機未套用最新修補程式之前,就先出現在日誌中。其餘設定內容請參閱 Ubuntu 的自動安全性更新。
下一個 kernel 安裝前,請先確認一個數值;這與本指南開頭的同一組指令相同:
df -h /boot
ls -lh /boot/initrd.img-$(uname -r)如果 Avail 沒有明顯大於該檔案,下一個 kernel 就會如上所述確切失敗。因此,請現在修正,不要等到升級期間才處理。這項檢查只需一分鐘,也應納入 VPS 的其他 磁碟健康檢查。在進行 release upgrade 前,這項檢查尤其重要,因為 將 Ubuntu 24.04 升級至 26.04 會在流程早期安裝新的 kernel;當 /boot 可用空間不足時,do-release-upgrade 會拒絕繼續。如果您的 LTS server 尚未收到該升級,原因是時程而非故障,因為 Ubuntu 會等到 26.04.1 point release 發行後,才開放 LTS 至 LTS 的升級。這會提供明確的時間窗口,讓您先整理好 /boot。
FAQ
為什麼 Ubuntu 會保留舊核心,而不是將其刪除?
因為如果某個核心無法開機,您就沒有其他核心可供選擇。保留上一個版本,可讓您從 GRUB 選單復原錯誤更新,不必依賴供應商的救援主控台。apt 因此會保護一組核心套件,避免它們遭到自動移除,其中一定包含目前正在執行的核心。執行 apt-config dump | grep -i neverautoremove,即可查看您所用版本實際保護的模式,因為不同版本的政策可能有所變更。
在 production server 上執行 apt autoremove --purge 是否安全?
可以,但前提是先閱讀 dry run 的結果。執行 sudo apt autoremove --purge --dry-run;此命令不會寫入任何內容,請檢查列出的清單。如果清單包含 linux-generic 或 linux-image-generic 這類 meta package,請停止操作,因為移除這類套件會使後續核心更新停止。如果清單也包含 uname -r 輸出的版本字串,請同樣停止操作。若兩者皆未出現,列出的就是舊核心與孤立相依套件。
apt autoremove 未移除任何內容,而 /boot 仍然已滿。接下來該怎麼辦?
舊核心幾乎可以確定被標記為手動安裝,而 autoremove 只會處理標記為自動安裝的套件。執行 apt-mark showmanual | grep -E '^linux-'。其中列出的任何特定版本核心,都表示它曾經由手動方式安裝。使用 sudo apt-mark auto linux-image-<version> 將其標記為自動安裝,然後再次執行 dry run;或者使用 sudo apt purge linux-image-<version> 直接清除該版本。
可以手動刪除 /boot 中的檔案嗎?
只有在 /boot 已滿到 apt 無法設定有問題的核心套件時,才應有意地執行這種一次性操作。刪除單一 initrd.img-<version> 檔案,但其版本不得是 uname -r 的輸出內容;接著立即執行 sudo apt --fix-broken install、sudo apt autoremove --purge 和 sudo update-grub。刪除檔案後若未執行這些步驟,dpkg 會記錄檔案已不存在的套件,而 GRUB 選單也會保留指向遺失檔案的項目。如此一來,機器不會在您犯錯時立即失敗,而會在下一次重新開機時失敗。