VPS không boot sau khi cập nhật kernel: cách khôi phục
Khôi phục VPS không boot sau khi nâng cấp kernel bằng console provider, chọn kernel cũ trong GRUB và xử lý lỗi initramfs, LVM trước khi sửa hệ thống.
Việc cần làm đầu tiên khi VPS không khởi động sau khi cập nhật kernel
VPS không khởi động được sau khi cập nhật kernel thường có thể khôi phục trong vài phút, vì bản cập nhật không xóa kernel đã hoạt động vào hôm qua. Ubuntu cài kernel mới cùng với kernel cũ và chỉ thay đổi entry mà GRUB khởi động mặc định. Vì vậy, việc đầu tiên không phải là sửa chữa. Hãy chọn kernel trước đó trong boot menu, đưa hệ thống trở lại màn hình đăng nhập, rồi chẩn đoán từ một hệ thống đang chạy.
Xử lý lỗi này trên server khác với trên laptop vì server không có keyboard và không có monitor để hiển thị lỗi panic. SSH cũng không phản hồi vì máy chưa chạy đến bước khởi động sshd. Toàn bộ thao tác dưới đây được thực hiện qua console của provider.
Hãy đọc console trước khi thay đổi bất kỳ thứ gì. Nội dung trên màn hình đó xác định loại lỗi bạn đang gặp, và hai server đều “không khởi động được” có thể cần các cách xử lý ngược nhau.
Làm thế nào để truy cập console khi SSH không hoạt động?
Mở control panel của nhà cung cấp và tìm console. Các tên thường gặp là VNC console, web console, noVNC và serial console. Nếu có cả hai, hãy ưu tiên serial console vì nó cung cấp văn bản thực để bạn cuộn và sao chép, trong khi VNC chỉ hiển thị hình ảnh của màn hình. Hãy tìm control này ngay khi máy vẫn đang hoạt động bình thường và xác nhận rằng bạn mở được nó. Nếu phải tìm trong lúc outage, bạn sẽ mất sự bình tĩnh cần thiết. Việc kiểm tra này thuộc 10 phút đầu tiên khi thiết lập một VPS mới, cùng với firewall rules và SSH keys.
Hầu hết panel cũng cung cấp rescue mode hoặc recovery image. Nó boot một hệ thống nhỏ từ network của nhà cung cấp và gắn disk của bạn như một device bổ sung, nên không có thành phần nào trên disk được chạy. Rescue mode là phương án dự phòng khi chính GRUB bị lỗi. Đây cũng là cách để sao chép dữ liệu khỏi một server mà bạn đã quyết định không khôi phục.
Thông thường, bạn sẽ cần hard reset từ panel để mở boot menu, vì bạn không thể chạy sudo reboot trên một máy mà mình không thể đăng nhập. Hard reset tương đương với việc ngắt nguồn điện. Filesystem sẽ bị shutdown không sạch, vì vậy hãy dự kiến hệ thống sẽ kiểm tra filesystem trong lần boot tiếp theo.
Cách chọn kernel cũ hơn trong menu GRUB
Theo dõi console ngay từ lúc bạn nhấn reset. Nhấn Esc liên tục trong những giây đầu tiên, hoặc giữ Shift trên máy khởi động ở chế độ legacy BIOS. Khoảng thời gian này rất ngắn, và trình xem console thường mất một giây để kết nối, nên hãy bắt đầu nhấn sớm và tiếp tục nhấn.
Khi menu xuất hiện, chọn "Advanced options for Ubuntu". Submenu này liệt kê mọi kernel đã cài, kernel mới nhất ở đầu danh sách, cùng một mục recovery mode cho từng kernel. Chọn mục bình thường thứ hai, tức kernel ngay dưới kernel mới nhất, rồi nhấn Enter. Recovery mode là chế độ khác: nó khởi động vào một hệ thống single-user tối giản và dành cho việc sửa chữa, không phải để đưa các service hoạt động trở lại.
Nếu kernel cũ khởi động được, bạn đã có lại một server đang chạy. Xác nhận bạn đang chạy kernel nào và ghi lại các số phiên bản.
uname -r
dpkg -l 'linux-image-*' | grep '^ii'Output của dpkg là danh sách các kernel đã cài. Nếu danh sách chỉ có một dòng, bạn hoàn toàn không có kernel dự phòng, và đó là việc đầu tiên cần khắc phục.
Menu GRUB không bao giờ xuất hiện. Phải làm gì?
Cloud image thường có cấu hình ẩn menu. Image Ubuntu thường đặt timeout bằng 0 trong một file dưới /etc/default/grub.d/, nên kernel mới nhất khởi động ngay và không có gì để nhấn.
Cũng có trường hợp ngược lại: menu hiện trên màn hình và chờ, khiến bạn tưởng hệ thống bị treo. GRUB ghi nhận lần boot thất bại, rồi ở lần khởi động tiếp theo có thể giữ menu mở cho đến khi có người nhấn phím. Trên máy không có keyboard, thời gian chờ đó sẽ không bao giờ kết thúc. Nếu console hiển thị menu nhưng không có gì thay đổi, đó là nguyên nhân. Chọn một mục rồi tiếp tục.
Hãy sửa cả hai trường hợp khi máy vẫn đang hoạt động bình thường. Chỉnh sửa /etc/default/grub:
GRUB_TIMEOUT_STYLE=menu
GRUB_TIMEOUT=10
GRUB_RECORDFAIL_TIMEOUT=10
GRUB_TERMINAL="console serial"
GRUB_SERIAL_COMMAND="serial --unit=0 --speed=115200"
GRUB_CMDLINE_LINUX_DEFAULT="console=tty1 console=ttyS0,115200"Sau đó áp dụng thay đổi và kiểm tra xem cấu hình có được giữ lại không, vì các file trong /etc/default/grub.d/ được đọc sau /etc/default/grub và có thể ghi đè thay đổi của bạn.
sudo update-grub
grep -rE 'TIMEOUT|TERMINAL' /etc/default/grub /etc/default/grub.d/GRUB_TERMINAL="console serial" gửi menu đến graphical console và serial port, nên menu sẽ xuất hiện trong viewer mà panel của bạn cung cấp. Các kernel argument console= cũng làm tương tự với boot message xuất hiện sau đó. Chờ 10 giây ở mỗi lần boot là cái giá nhỏ để có thể truy cập menu lúc 2 giờ sáng.
Tôi đang gặp nhóm lỗi nào?
Đọc 20 dòng cuối cùng trước khi console ngừng thay đổi. 4 mẫu lỗi bao quát phần lớn các sự cố xảy ra sau khi cập nhật kernel.
GRUB không tìm thấy các file của chính nó. Bạn thấy prompt grub rescue> hoặc lỗi về partition hay file không tồn tại, và không hề có thông báo nào của kernel. Kernel chưa được chạy. Lỗi này thường xảy ra sau khi thay đổi disk hoặc partition, hoặc khi bootloader được ghi vào sai device, chứ không phải do riêng kernel package.
Kernel khởi động nhưng không thể mount root. Các thông báo của kernel chạy trên màn hình, sau đó bạn rơi vào một shell busybox có prompt là (initramfs), hoặc quá trình boot kết thúc bằng panic vì không thể mount root filesystem. Kernel đã được load. initramfs, tức root tạm thời nhỏ dùng để tìm và mount root filesystem thật, không tìm thấy disk. Trên Ubuntu, shell này thường có một thông báo trước đó cho biết đã bỏ cuộc sau khi chờ root device, đồng thời nêu UUID mà hệ thống cần. Sao chép UUID đó và so sánh với output của blkid sau này.
Logical volume không xuất hiện. Đây là nhóm lỗi trước với một nguyên nhân cụ thể. Tại prompt (initramfs), chạy ls /dev/mapper. Nếu entry duy nhất là control, thì chưa có volume LVM (logical volume manager) nào được activate, nên root device chưa tồn tại. Tự đưa các volume group lên bằng tay:
lvm vgchange -ay
ls /dev/mapper
exitexit chuyển quyền điều khiển lại cho initramfs script, script này sẽ thử mount lại. Nếu hệ thống khởi động được sau đó, initramfs mới đang thiếu các thành phần LVM. Cách sửa là rebuild image đó thay vì can thiệp vào kernel.
Hoàn toàn không có gì từ Linux. Console hiển thị text của firmware, một UEFI (unified extensible firmware interface) shell, màn hình trống không có output của kernel hoặc vòng lặp reset. Lỗi xảy ra trước khi Linux chạy. Khi hệ thống hoạt động trở lại, hãy kiểm tra server thực sự đang dùng mode nào, vì nhiều VPS instance boot ở legacy BIOS mode và không bao giờ dùng đường dẫn EFI:
[ -d /sys/firmware/efi ] && echo UEFI || echo BIOS
mountpoint /boot/efi
sudo efibootmgr -v/boot/efi không được mount trong lúc upgrade là một nguyên nhân phổ biến trên máy UEFI, vì các package duy trì EFI system partition khi đó đã ghi vào một thư mục trống thông thường. Firmware tiếp tục khởi động boot entry cũ cho đến khi entry đó không còn khớp với nội dung trên disk.
Còn một mẫu khác thực ra không phải lỗi boot. Nếu bạn vào được root shell và shell cho biết hệ thống đang ở emergency mode, kernel đã boot nhưng userspace đã dừng. Nguyên nhân thường là một dòng sai trong /etc/fstab hoặc filesystem không vượt qua bước kiểm tra. Chạy journalctl -xb trong shell đó và đọc tên unit đã fail.
Gói kernel bị hỏng hay initramfs bị hỏng?
Hai trường hợp này trông giống hệt nhau trên console nhưng cần cách khắc phục khác nhau. Hãy boot vào kernel cũ, rồi so sánh các file.
ls -l /boot/vmlinuz-* /boot/initrd.img-*
df -h /bootMỗi version đã cài phải có một vmlinuz- và một initrd.img- tương ứng, với kích thước hợp lý. Nếu thiếu initrd hoặc file nhỏ hơn nhiều so với các version bên cạnh, quá trình tạo initramfs đã thất bại. Nguyên nhân thường gặp là /boot đã đầy. Bằng chứng nằm trong log của package:
sudo grep -iE 'no space|update-initramfs' /var/log/apt/term.log
sudo tail -n 40 /var/log/apt/history.loghistory.log cũng liệt kê chính xác các package được cài trong những lần chạy gần nhất và thời điểm cài, giúp xác định những gì đã thay đổi.
Nếu /boot đầy, trước tiên hãy giải phóng dung lượng. Sau đó tạo lại image cho version cần dùng và refresh menu. Lấy chuỗi version từ output ls của chính bạn, vì placeholder bên dưới không phải một release thực:
KVER=6.8.0-XX-generic
sudo update-initramfs -c -k "$KVER"
sudo update-grub
ls -l /boot/initrd.img-$KVERls cuối cùng là bước kiểm tra. File có kích thước bình thường nghĩa là image đã được tạo lại. Nếu chính kernel image bị hỏng, hoặc dpkg -l hiển thị package ở trạng thái khác ii, hãy cài lại package:
sudo apt install --reinstall linux-image-$KVER
sudo dpkg --configure -aSửa từ rescue mode khi không kernel nào khởi động được
Nếu mọi mục trong menu đều thất bại, hãy khởi động rescue image của nhà cung cấp rồi sửa disk từ bên ngoài. Disk của bạn sẽ xuất hiện dưới dạng một device chưa được mount, vì vậy không có gì trên đó đang chạy và không có tiến trình nào cản trở bạn.
Quy trình sửa lỗi chroot đầy đủ
Trước tiên, chạy lsblk -f và đọc đúng tên device trên chính máy của bạn. /dev/vda thường được dùng trên KVM, còn các bản cài Ubuntu server thường đặt root trên LVM dưới dạng /dev/ubuntu-vg/ubuntu-lv.
sudo lsblk -f
sudo vgchange -ay
sudo mount /dev/ubuntu-vg/ubuntu-lv /mnt
sudo mount /dev/vda2 /mnt/boot
sudo mount /dev/vda1 /mnt/boot/efiBỏ qua những dòng không áp dụng cho bạn. Nhiều image không có /boot riêng và cũng không có EFI partition. Sau đó bind các kernel interface vào rồi vào system:
for d in dev proc sys run; do sudo mount --rbind /$d /mnt/$d; done
sudo chroot /mnt /bin/bashBên trong chroot, bạn đang thao tác trên system bị lỗi trong khi một kernel khỏe mạnh vẫn chạy bên dưới. Hãy sửa lỗi tại đó:
df -h /boot
update-initramfs -u -k all
update-grub
grub-install /dev/vda
exitTrên system BIOS, grub-install sử dụng toàn bộ disk, không phải một partition. Trên system UEFI, hãy dùng grub-install --target=x86_64-efi --efi-directory=/boot/efi và xác nhận directory đó đã được mount trước khi chạy lệnh. Thoát bằng exit, unmount mọi thứ bằng sudo umount -R /mnt, sau đó chuyển panel về chế độ boot bình thường và restart.
Kiểm tra kernel mới mà không ảnh hưởng đến lần boot tiếp theo
GRUB có thể khởi động một entry đúng một lần, sau đó quay về default bạn đã chọn. Đặt default trỏ đến kernel mà bạn tin cậy, rồi khởi động kernel mới chỉ trong một lần boot. Nếu kernel mới lỗi, hard reset từ panel sẽ đưa bạn về kernel ổn định mà không cần thao tác kịp thời trên console.
Đặt GRUB_DEFAULT=saved trong /etc/default/grub, chạy sudo update-grub, rồi liệt kê tiêu đề các entry để bạn có thể ghi chính xác một entry:
grep -E "(menuentry|submenu) " /boot/grub/grub.cfg | cut -d"'" -f2
sudo grub-set-default "Advanced options for Ubuntu>Ubuntu, with Linux 6.8.0-XX-generic"
sudo grub-editenv list
sudo grub-reboot 0
sudo rebootgrub-editenv list phải in tiêu đề bạn đã chọn dưới dạng saved_entry. Kết quả này xác nhận cơ chế hoạt động, vì thao tác lưu cần /boot/grub/grubenv có quyền ghi, nhưng trên một số layout, file này không có quyền ghi mà không báo lỗi. Entry 0 là mục đầu tiên trong menu, tức kernel mới nhất. Trong trường hợp này, dùng tiêu đề an toàn hơn dùng số, vì các số sẽ thay đổi mỗi khi kernel được cài đặt hoặc gỡ bỏ.
Vì sao autoremove nguy hiểm trên máy không có giao diện quản trị trực tiếp
APT duy trì danh sách các kernel package không được tự ý gỡ. Hãy đọc danh sách này:
cat /etc/apt/apt.conf.d/01autoremove-kernels
dpkg -l 'linux-image-*' | grep -c '^ii'File đó được tạo lại mỗi khi kernel package thay đổi. Nó bảo vệ kernel đang chạy và các kernel mới nhất. Rủi ro nằm ở thời điểm thực hiện. Nếu chạy sudo apt autoremove --purge ngay sau khi reboot vào kernel mới, danh sách được bảo vệ đã chuyển sang kernel mới. Kernel cũ mà bạn dự định dùng dự phòng sẽ không còn được bảo vệ. Trên máy có keyboard, đây chỉ là một bất tiện. Trên headless server, đây là khác biệt giữa việc chọn một mục trong menu và việc phải mount disk từ rescue image.
Hãy luôn giữ ít nhất hai kernel. Giữ ba kernel khi /boot còn đủ dung lượng. Gỡ các kernel cũ theo tên sau khi kiểm tra uname -r, để không thể xóa kernel đang chạy:
uname -r
sudo apt purge linux-image-6.8.0-XX-generic
dpkg -l 'linux-image-*' | grep '^ii'Sau đó chạy lại command cuối cùng. Số lượng giảm từ ba xuống hai là cleanup. Số lượng giảm xuống một là outage chỉ chờ lần reboot tiếp theo.
Tạo snapshot trước khi nâng cấp
Snapshot được tạo trước apt upgrade là phương án khôi phục duy nhất không phụ thuộc vào việc khởi động bất kỳ thành phần nào. Khôi phục snapshot sẽ đưa disk về trạng thái trong đó kernel cũ vẫn là mặc định, để bạn có thể thử lại quá trình nâng cấp khi console đã được mở sẵn. Snapshot của một máy đang chạy có tính nhất quán như sau sự cố, nghĩa là nó ghi lại disk như thể nguồn điện vừa bị ngắt. Vì vậy, hãy tắt server trước nếu nhà cung cấp hỗ trợ tạo snapshot offline. Snapshot cũng không phải là backup, vì nó thường nằm trên cùng hạ tầng với volume mà nó sao chép. Hiểu sự khác biệt giữa snapshot của VPS và backup thực sự sẽ quyết định phương án nào cứu được bạn khi sự cố không chỉ liên quan đến kernel.
Điều này đặc biệt quan trọng khi nâng cấp release, vì kernel, các công cụ initramfs, bootloader và cấu hình GRUB đều thay đổi trong cùng một lần chạy. Hãy tạo snapshot ngay trước khi bắt đầu nâng cấp Ubuntu 24.04 lên 26.04, không phải vào đêm hôm trước, để điểm khôi phục khớp với máy bạn sắp thay đổi. Nếu bản nâng cấp đó chưa được cung cấp cho server của bạn, nguyên nhân là lịch phát hành chứ không phải cấu hình bị hỏng, vì quá trình chuyển từ LTS sang LTS chỉ mở từ bản point release đầu tiên, 26.04.1.
Cách unattended-upgrades xử lý các package kernel
unattended-upgrades của Ubuntu cài các bản cập nhật bảo mật mà không hỏi, và các package kernel cũng được cài qua security pocket như mọi package khác. Việc này có 2 hệ quả.
Thứ nhất, kernel mới đã được cài nhưng chưa chạy. Kernel chỉ có hiệu lực sau khi boot. File /var/run/reboot-required xuất hiện, còn /var/run/reboot-required.pkgs cho biết thành phần nào yêu cầu reboot, nhưng hệ thống sẽ không tự khởi động lại nếu bạn chưa bật Unattended-Upgrade::Automatic-Reboot trong /etc/apt/apt.conf.d/50unattended-upgrades.
cat /var/run/reboot-required.pkgs
grep -E 'Automatic-Reboot|Blacklist' /etc/apt/apt.conf.d/50unattended-upgradesThứ hai, khoảng thời gian này che khuất nguyên nhân. Server có thể cài kernel vào tháng 3 rồi reboot vào tháng 6 vì một lý do hoàn toàn không liên quan, sau đó không khởi động được. Thay đổi làm hỏng quá trình boot đã xảy ra từ 3 tháng trước, nên không có việc gì bạn làm trong ngày hôm đó giải thích được lỗi. /var/log/apt/history.log là nơi bạn tìm lần chạy đã cài kernel mà hiện tại server đang gặp lỗi khi khởi động.
Hãy chủ động reboot vào ngày bạn chọn, với cửa sổ console đã mở sẵn. Thói quen đơn giản này biến một sự cố mất dịch vụ khó xác định thành thao tác chọn trong menu chỉ mất 2 phút. Nếu muốn tự động cài đặt nhưng không muốn reboot bất ngờ, hãy bật tự động cài đặt và tắt tự động reboot, rồi xem cách cấu hình unattended-upgrades trên Ubuntu để biết các thiết lập chính xác. Dùng sudo apt-mark hold linux-image-generic để giữ các package kernel sẽ chặn hoàn toàn việc cài đặt chúng, đồng thời chặn cả các bản vá bảo mật cho kernel. Vì vậy, hãy xem đây là một đánh đổi có chủ đích, không phải một biện pháp an toàn.
FAQ
Làm cách nào để khởi động kernel cũ trên VPS không có bàn phím?
Mở console của nhà cung cấp (VNC hoặc serial), rồi thực hiện hard reset từ control panel vì bạn không thể đăng nhập để reboot đúng cách. Khi máy bắt đầu khởi động lại, nhấn liên tục Esc hoặc giữ Shift khi boot bằng BIOS legacy để giữ menu GRUB hiển thị. Chọn "Advanced options for Ubuntu", rồi chọn entry nằm ngay dưới kernel mới nhất. Khi đã thấy login prompt, chạy uname -r để xác nhận kernel đang dùng và dpkg -l 'linux-image-*' để xem các kernel khác đã được cài. Chỉ chẩn đoán sau khi hệ thống đã chạy lại.
Vì sao VPS của tôi hoàn toàn không hiển thị menu GRUB?
Cloud image thường đặt GRUB timeout bằng 0 trong một file bên dưới /etc/default/grub.d/, nên kernel mới nhất khởi động ngay và không có thời gian để nhấn phím. Đặt GRUB_TIMEOUT=10 và GRUB_TIMEOUT_STYLE=menu trong /etc/default/grub, thêm GRUB_TERMINAL="console serial" để menu cũng hiển thị trên serial console, rồi chạy sudo update-grub. Kiểm tra bằng grep -r TIMEOUT /etc/default/grub /etc/default/grub.d/ vì các file trong thư mục đó được đọc sau file chính và có thể ghi đè thay đổi của bạn.
Có nên xóa kernel cũ để giải phóng dung lượng trong /boot không?
Xóa các kernel cũ nhất và giữ lại ít nhất 2 kernel. /boot đầy là một dạng lỗi riêng vì khi đó quá trình tạo initramfs sẽ thất bại, khiến bạn chỉ còn kernel không có image hoạt động. Xóa theo đúng tên package sau khi kiểm tra uname -r để kernel đang chạy không bao giờ bị chọn. Tránh chạy sudo apt autoremove --purge trên máy không có màn hình hoặc bàn phím, vì danh sách kernel được bảo vệ sẽ được tạo lại sau mỗi lần thay đổi kernel và một lần chạy không đúng thời điểm có thể khiến bạn chỉ còn 1 kernel mà không có entry dự phòng trong menu.
Unattended-upgrades có thể làm hỏng quá trình boot không?
Có thể cài một kernel không boot được sau đó, nhưng nó không restart máy trừ khi Unattended-Upgrade::Automatic-Reboot được đặt thành true trong /etc/apt/apt.conf.d/50unattended-upgrades. Trường hợp thường gặp là lỗi xuất hiện muộn: kernel được cài trong một lần chạy tự động, /var/run/reboot-required xuất hiện, nhưng sự cố chỉ lộ ra khi bạn reboot lần tiếp theo sau vài tuần. Hãy chủ động reboot khi console đã mở sẵn, rồi đọc /var/log/apt/history.log để xác định lần chạy nào đã cài kernel mà bạn đang boot.