Cara tukar kernel but VPS Ubuntu yang betul
Tetapan GRUB_DEFAULT sering gagal pada imej awan Ubuntu. Ketahui cara menyemak entri menu sebenar dan menetapkan kernel but seterusnya dengan selamat tanpa risiko konsol pemulihan.
Perkara yang menentukan kernel yang digunakan oleh VPS anda semasa but
Kernel yang akan digunakan oleh VPS anda semasa but seterusnya ditentukan oleh satu fail yang dijana, iaitu /boot/grub/grub.cfg. Anda tidak boleh menyunting fail tersebut secara terus. Anda perlu menyunting inputnya dan menjana semula fail tersebut. Pada imej awan Ubuntu, salah satu input tersebut datang daripada vendor imej, dan ia boleh menyebabkan pemilihan menu menjadi tidak relevan. Inilah sebabnya mengapa GRUB_DEFAULT=1 diikuti dengan update-grub tidak membawa sebarang perubahan pada pelayan sewaan, sedangkan dua langkah yang sama berfungsi pada pemasangan komputer riba.
Lakukan kerja mengikut urutan ini. Sahkan bahawa anda mempunyai hak untuk memilih kernel. Baca setiap fail input, termasuk fail yang ditambah oleh vendor. Baca output yang dijana dan kira bilangan entri yang terkandung di dalamnya. Hanya selepas itu, pilih kaedah penetapan (pinning). Jika anda melakukan kesilapan ini pada mesin yang hanya boleh dicapai melalui SSH, anda mungkin memerlukan konsol pemulihan. Oleh itu, jawapan yang paling selamat berada di penghujung halaman ini dan ia sering kali merupakan pilihan yang tepat.
Semak dahulu sama ada kernel tersebut milik anda untuk disematkan (pin)
uname -r
systemd-detect-virt
ls -1 /boot/vmlinuz-*systemd-detect-virt mencetak kvm, qemu atau xen bermaksud anda menjalankan kernel anda sendiri dan semua perkara di bawah adalah terpakai. Mencetak lxc atau openvz bermaksud pelayan anda berkongsi kernel hos, jadi tiada bootloader milik anda dan tiada apa-apa untuk disematkan. Dalam kes tersebut, uname -r melaporkan versi yang tidak muncul langsung dalam /boot/vmlinuz-*, kerana kernel yang sedang berjalan adalah milik hos dan tiada tetapan pada cakera anda boleh mengubahnya.
ls -1 /boot/vmlinuz-* ialah senarai sebenar kernel yang boleh anda pilih. Jika ia mengandungi satu baris, kernel sebelumnya telah pun dipadamkan, dan tiada tetapan bootloader yang boleh mengembalikannya. Perkara itu biasanya berlaku semasa autoremove, yang perlu difahami sebelum anda membersihkan kernel lama pada Ubuntu pada mesin yang penting bagi anda.
Fail yang anda sunting bukanlah fail yang dibaca oleh GRUB
/etc/default/grub mengandungi tugasan pemboleh ubah shell biasa. Ia merupakan input. /boot/grub/grub.cfg ialah output, dan ia bermula dengan # DO NOT EDIT THIS FILE serta sebabnya. Sebarang perkara yang anda tulis ke dalam output akan hilang pada kali seterusnya pakej kernel dipasang atau dibuang, kerana skrip pakej tersebut menjana semula fail itu.
cat /usr/sbin/update-grubupdate-grub ialah pembalut (wrapper). Ia menjalankan grub-mkconfig -o /boot/grub/grub.cfg, yang membaca pemboleh ubah tersebut, menjalankan setiap skrip dalam /etc/grub.d/, dan menulis hasilnya. Dua arahan, satu arah: input dimasukkan, grub.cfg dikeluarkan.
Perkara yang mengatasi tetapan anda: /etc/default/grub.d
grep -rn '^[^#]' /etc/default/grub /etc/default/grub.d/Laluan kedua ialah bahagian yang sering terlepas pandang. grub-mkconfig memuatkan /etc/default/grub terlebih dahulu, kemudian setiap fail *.cfg dalam /etc/default/grub.d/ mengikut susunan glob. Baca kod yang melaksanakannya:
grep -n 'default/grub' /usr/sbin/grub-mkconfigProses memuatkan (sourcing) adalah shell biasa, jadi tugasan terakhir yang akan diguna pakai. Imej cloud Ubuntu menyertakan fail dalam direktori tersebut, dan ia menetapkan perkara seperti tempoh masa tamat (timeout) serta baris arahan kernel selepas fail anda dibaca. GRUB_TIMEOUT=10 anda dalam /etc/default/grub ditimpa seketika kemudian oleh fail vendor yang menetapkannya kepada 0. Arahan grep di atas memaparkan tugasan sebenar pada imej anda, jadi bacalah maklumat tersebut daripada mempercayai ayat ini.
Peraturan praktikal yang perlu diikuti: letakkan tetapan anda sendiri dalam fail yang disusun paling akhir, contohnya /etc/default/grub.d/99-local.cfg, bukannya menyunting /etc/default/grub. Dengan cara ini, tiada apa-apa yang disertakan oleh imej tersebut boleh dilaksanakan selepas anda.
Mengapa GRUB_FORCE_PARTUUID menjadikan pemilihan menu tidak relevan
grep -rn GRUB_FORCE_PARTUUID /etc/default/grub /etc/default/grub.d/
grep -n GRUB_FORCE_PARTUUID /etc/grub.d/10_linux
sudo grep -n 'root=PARTUUID' /boot/grub/grub.cfgGRUB_FORCE_PARTUUID memberitahu penjana untuk mencari sistem fail root mengikut UUID partition, yang ditulis terus pada baris arahan kernel sebagai root=PARTUUID=..., bukannya mencari UUID sistem fail semasa but. Vendor imej menetapkannya kerana ia menjadikan satu imej cakera boleh but dengan pasti pada perkakasan yang ia tidak dibina untuknya. Arahan grep kedua menunjukkan kod yang bertindak ke atas pemboleh ubah tersebut, dalam /etc/grub.d/10_linux. Skrip itu berada pada cakera anda sendiri, dan ia merupakan autoriti tentang perkara yang dilakukan oleh imej anda.
Akibatnya adalah perkara yang penting di sini: pada laluan tersebut, penjana menulis entri but terus dan bukannya senarai penuh kernel yang dipasang. Kira jumlah yang anda perolehi.
sudo grep -cE '^\s*(menuentry|submenu) ' /boot/grub/grub.cfg
sudo grep -nE '^\s*(menuentry|submenu) ' /boot/grub/grub.cfgJika jumlahnya ialah 1, tiada entri kedua untuk dipilih, jadi GRUB_DEFAULT=1 menamakan entri yang tidak wujud. GRUB tidak dapat menyelesaikannya, jadi ia memulakan entri pertama, iaitu kernel baharu yang anda cuba elakkan. grub-set-default juga tidak membantu, kerana lalai (default) bukanlah bahagian yang rosak. Menu yang anda cuba pilih tidak pernah dijana.
Untuk mendapatkan semula menu penuh, alihkan fail vendor ke tepi dan pratonton hasilnya sebelum melaksanakannya. grub-mkconfig tanpa -o menulis kepada output standard dan tidak menyentuh apa-apa pada cakera.
sudo grub-mkconfig 2>/dev/null | grep -cE '^\s*(menuentry|submenu) '
sudo mkdir -p /root/grub-backup
sudo mv /etc/default/grub.d/<the file your grep named> /root/grub-backup/
sudo grub-mkconfig 2>/dev/null | grep -cE '^\s*(menuentry|submenu) 'Jumlah yang melonjak daripada 1 kepada beberapa bermakna entri muncul sebaik sahaja pemaksaan (forcing) tiada. Tiada apa-apa yang telah ditulis lagi. Letakkan semula fail tersebut jika jumlah kedua tidak kelihatan betul, kerana PARTUUID yang dipaksa adalah cara imej pembekal anda mencari sistem fail rootnya, dan mengalih keluarnya akan memindahkan mesin ke laluan carian sebaliknya. Ambil syot kilat (snapshot) sebelum anda menjalankan update-grub secara sebenar.
Jika matlamat tunggal anda adalah untuk bertahan daripada satu kernel yang rosak, berhenti di sini dan gunakan pilihan yang lebih selamat di bawah. Membina semula menu but pada pelayan jauh untuk melarikan diri daripada satu naik taraf adalah risiko yang lebih besar daripada masalah itu sendiri.
Mengapa nombor entri bukan cara yang betul untuk melakukan pinning
GRUB_DEFAULT menerima nombor, tajuk atau pengecam. Nombor mengira entri peringkat atas bermula daripada 0. Entri bersarang menggunakan > sebagai pemisah, jadi GRUB_DEFAULT="1>2" bermaksud entri pada indeks 2 di dalam submenu pada indeks 1.
Indeks boleh berubah. 10_linux menyenaraikan kernel dengan yang terbaharu di atas, jadi memasang kernel akan menolak setiap entri lama ke bawah sebanyak satu kedudukan, dan membuang kernel akan menariknya ke atas. 1>2 anda yang teliti masih akan selesai selepas itu. Ia kini menamakan kernel yang berbeza. Tiada ralat, tiada amaran, dan anda hanya akan mengetahuinya selepas but semula.
Pengecam tidak berubah, kerana setiap satunya mengandungi versi kernel. Baca milik anda:
sudo awk -F"'" '/menuentry_id_option/ {print $2, "==>", $4}' /boot/grub/grub.cfgAbaikan beberapa baris pertama output, iaitu pemboleh ubah yang ditakrifkan dalam pengepala. Selepas itu, sebelah kiri ialah tajuk yang dilihat oleh pembaca dan sebelah kanan ialah pengecam yang anda berikan kepada alatan tersebut. Untuk entri di dalam submenu, gabungkan pengecam submenu dan pengecam entri dengan >, mengikut urutan tersebut, tepat seperti bentuk berangka.
But semula kernel sebelumnya sekali sahaja dengan grub-reboot
Pemilihan sekali sahaja adalah langkah yang tepat pada pelayan jauh, kerana ia membatalkan dirinya sendiri. grub-reboot menulis next_entry ke dalam /boot/grub/grubenv. GRUB membaca pemboleh ubah tersebut, mengosongkannya, dan menyimpan nilai yang telah dikosongkan sebelum ia memulakan apa-apa, jadi kernel yang mengalami panic tidak akan dicuba semula pada but seterusnya. Anda mendapat satu percubaan, kemudian mesin akan kembali kepada tetapan lalai asalnya secara automatik.
Pertama, sahkan konfigurasi yang dijana oleh anda membaca pemboleh ubah tersebut:
sudo grep -n -B2 -A5 'next_entry' /boot/grub/grub.cfgAnda mahukan baris load_env dan blok yang menetapkan default daripada next_entry. Jika grep tidak memaparkan apa-apa, imej anda tidak pernah membaca grubenv semasa but, jadi grub-reboot akan diterima pada shell tetapi diabaikan oleh bootloader. Ini adalah laluan but terus yang sama seperti bahagian sebelumnya yang muncul di tempat kedua.
sudo grub-reboot '<the identifier you copied>'
sudo grub-editenv listgrub-editenv list sepatutnya memaparkan baris next_entry= yang mengandungi tepat apa yang anda masukkan. Buka konsol pembekal anda dalam tab pelayar, kemudian but semula dan semak hasilnya.
sudo rebootuname -runame -r yang melaporkan versi lama bermakna pin tersebut berjaya. Jika ia melaporkan versi baharu, ini bermakna sama ada pengecam tidak dapat diselesaikan atau grubenv tidak dibaca, dan mesin tetap hidup dalam kedua-dua keadaan, itulah tujuan menggunakan bentuk sekali jalan (one shot).
Jadikan pilihan kekal dengan GRUB_DEFAULT=saved
GRUB_DEFAULT=saved menjadikan pilihan lalai diambil daripada saved_entry dalam grubenv, dan anda menetapkan nilai tersebut dengan grub-set-default. Nilai ini kekal selepas pemasangan kernel, kerana update-grub menulis semula grub.cfg dan tidak pernah mengubah grubenv.
echo 'GRUB_DEFAULT=saved' | sudo tee /etc/default/grub.d/99-local.cfg
sudo update-grub
sudo grub-set-default '<the identifier you copied>'
sudo grub-editenv list
sudo grep -n 'set default' /boot/grub/grub.cfgPerintah terakhir mesti memaparkan set default="${saved_entry}". Jika ia memaparkan set default="0", sesuatu yang dimuatkan selepas fail anda telah menetapkan semula GRUB_DEFAULT kepada nilai literal, jadi senaraikan /etc/default/grub.d/ sekali lagi dan pastikan 99-local.cfg benar-benar berada di urutan terakhir.
GRUB_SAVEDEFAULT=true ialah tetapan yang berbeza dan mudah dikelirukan dengan tetapan ini. Ia menyimpan apa sahaja yang baru anda but sebagai lalai baharu, jadi pilihan lalai akan mengikut but berjaya yang terakhir. Pada pelayan, ini bermakna but semula tanpa pengawasan boleh mengubah pilihan anda secara senyap. Biarkan ia dimatikan kecuali jika itu yang anda mahukan.
Pilihan menggunakan pengecam (identifier) masih boleh gagal dalam satu keadaan. Padamkan kernel yang dinamakan dan pengecam tersebut akan berhenti berfungsi, yang menyebabkan sistem kembali kepada entri pertama. Jadi, tahan (hold) pakej tersebut atau pastikan kernel itu tidak termasuk dalam autoremove.
Memaparkan menu pada konsol pembekal
Pemilihan secara interaktif memerlukan menu dipaparkan pada skrin, namun imej awan menyembunyikannya. Masukkan tetapan ini ke dalam fail yang disusun paling akhir, kemudian jalankan sudo update-grub.
GRUB_TIMEOUT=10
GRUB_TIMEOUT_STYLE=menu
GRUB_RECORDFAIL_TIMEOUT=10GRUB_TIMEOUT_STYLE=hidden bersama-sama dengan GRUB_TIMEOUT=0 tidak memaparkan apa-apa, jadi sesiapa yang memantau konsol akan melihat mesej kernel bermula serta-merta dan membuat kesimpulan bahawa bootloader telah dilangkau. GRUB_RECORDFAIL_TIMEOUT ialah tempoh tamat masa berasingan yang digunakan selepas but yang tidak lengkap, dan imej awan menetapkannya kepada 0. Inilah sebabnya pelayan yang gagal but masih tidak berhenti dan menunggu anda.
Jika pembekal anda menyediakan konsol bersiri dan bukannya konsol grafik namun anda masih tidak melihat apa-apa, GRUB sedang menulis ke terminal yang tidak dapat anda lihat. Tambahkan kedua-dua baris tersebut bersama-sama, kerana baris pertama memilih output dan baris kedua mengkonfigurasi port:
GRUB_TERMINAL="console serial"
GRUB_SERIAL_COMMAND="serial --speed=115200 --unit=0 --word=8 --parity=no --stop=1"Sepuluh saat akan ditambah pada setiap proses but mulai sekarang. Tetapkan semula tempoh tamat masa kepada 0 sebaik sahaja anda selesai.
Pilihan yang lebih selamat daripada menyunting bootloader
Menukar input bootloader pada mesin yang hanya dicapai melalui SSH ialah pilihan paling berisiko dalam halaman ini. Terdapat penyelesaian yang lebih murah, dan biasanya ia menyelesaikan masalah sebenar.
Tahan (hold) pakej kernel. Jika matlamatnya adalah "jangan berikan saya kernel yang lebih baharu", nyatakan perkara itu kepada pengurus pakej dan bukannya kepada bootloader.
apt list --installed 2>/dev/null | grep -E '^linux-(image|headers|generic|virtual|kvm|aws|azure|gcp|oracle)'
sudo apt-mark hold linux-image-virtual linux-headers-virtual
apt-mark showholdGunakan apa jua nama yang dicetak oleh arahan pertama, kerana imej awan biasanya memasang varian virtual atau kvm dan bukannya generic. Pakej yang ditahan akan dilangkau oleh apt upgrade, yang akan memaklumkannya dengan The following packages have been kept back:, dan ia juga dilangkau oleh unattended upgrades pada Ubuntu. Kosnya nyata: kernel yang ditahan tidak akan menerima tampalan keselamatan, jadi anggap ia sebagai jeda yang mempunyai tarikh luput dan lepaskan ia dengan sudo apt-mark unhold. Jika anda mengelakkan kemas kini kernel kerana but semula menyebabkan downtime dan bukannya kerana kernel tersebut bermasalah, live kernel patching pada VPS menjawab perkara itu sebaliknya.
Ambil snapshot sebelum naik taraf. Snapshot memulihkan sistem dalam beberapa minit, tanpa perlu menaip pada konsol dan tiada risiko perubahan bootloader yang tidak lengkap. Ambil snapshot, naik taraf, but semula, dan sahkan. Jika kernel baharu berkelakuan tidak sepatutnya, buat rollback dan laluan but akan kembali tepat seperti asal.
Gunakan konsol atau imej pemulihan untuk kotak yang sudah tidak berfungsi. Apabila pelayan tidak mahu but, konfigurasi bootloader bukanlah tempat untuk membaikinya, dan laluan pemulihan itu mempunyai prosedurnya sendiri: apa yang perlu dilakukan apabila VPS tidak mahu but selepas kemas kini kernel.
Apa yang rosak, dan mesej yang akan anda lihat
Suntingan anda pada /boot/grub/grub.cfg hilang. Pakej kernel telah dipasang atau dibuang, skrip penyelenggaranya menjalankan update-grub, dan fail tersebut dijana semula daripada input. Pengepala # DO NOT EDIT THIS FILE menamakan dua lokasi input tersebut. Sunting lokasi-lokasi itu.
grub-editenv: error: environment block too small. /boot/grub/grubenv hilang atau terpotong. Cipta semula dengan sudo grub-editenv /boot/grub/grubenv create, kemudian tetapkan nilai anda semula dan sahkan dengan sudo grub-editenv list.
Kernel yang dipin (pinned) mengalami panic dengan VFS: Unable to mount root fs on unknown-block(0,0). Entri yang anda pin merujuk kepada kernel atau initrd yang tidak lagi berada pada cakera, biasanya kerana pakej tersebut telah dibuang sementara pengecamnya kekal dalam grubenv. Pemulihan dilakukan dengan but konsol menggunakan entri yang berfungsi, kemudian bersihkan nilai yang lapuk itu.
uname -r tidak berubah selepas but semula yang anda jangkakan akan mengubahnya. Periksa tiga perkara mengikut urutan: adakah grub-editenv list masih menunjukkan nilai anda atau adakah ia telah digunakan; adakah pengecam yang anda tetapkan muncul dalam grub.cfg semasa; adakah grub.cfg mengandungi baris set default yang membaca pemboleh ubah yang anda tetapkan. Salah satu daripada tiga perkara ini sentiasa menjadi puncanya.
Menu muncul dengan sendirinya selepas kegagalan sistem (crash). GRUB merekodkan but yang gagal dalam grubenv sebagai recordfail=1, dan ini memaksa menu muncul pada but seterusnya supaya pengguna boleh campur tangan. Kosongkan rekod tersebut dengan sudo grub-editenv /boot/grub/grubenv unset recordfail sebaik sahaja mesin kembali sihat.
Satu ayat yang perlu diingat: fail yang anda sunting bukanlah fail yang dibaca oleh GRUB, dan pada imej awan, jurang antara kedua-duanya adalah punca kekeliruan. Baca konfigurasi yang dijana terlebih dahulu. Setiap keputusan pada halaman ini adalah berdasarkan apa yang tertulis di dalamnya.
FAQ
Mengapa GRUB_DEFAULT=1 tidak menukar kernel yang digunakan oleh VPS saya untuk boot?
Kerana pada imej awan Ubuntu, /boot/grub/grub.cfg yang dijana selalunya hanya mengandungi satu entri boot, jadi indeks 1 tidak merujuk kepada apa-apa dan GRUB akan kembali kepada entri pertama. Sahkan perkara ini dengan sudo grep -cE '^\s*(menuentry|submenu) ' /boot/grub/grub.cfg. Jumlah kiraan 1 adalah jawapannya. Puncanya ialah GRUB_FORCE_PARTUUID, yang ditetapkan oleh pembekal imej dalam fail di bawah /etc/default/grub.d/, yang meletakkan penjana pada laluan boot terus dan bukannya membina senarai penuh kernel yang dipasang. Cari fail tersebut dengan grep -rn GRUB_FORCE_PARTUUID /etc/default/grub /etc/default/grub.d/.
Bagaimanakah cara untuk boot kernel sebelumnya hanya untuk sekali sahaja?
Jalankan sudo grub-reboot '<identifier>' dengan pengecam yang disalin daripada grub.cfg anda sendiri, kemudian reboot dengan konsol pembekal sudah dibuka. GRUB akan mengosongkan next_entry sebelum ia boot, jadi pilihan tersebut hanya terpakai untuk satu percubaan sahaja dan kernel yang mengalami panic tidak akan dicuba semula. Sahkan nilai tersebut telah ditetapkan dengan sudo grub-editenv list. Sebelum bergantung kepadanya, jalankan sudo grep -n next_entry /boot/grub/grub.cfg, kerana imej yang konfigurasinya tidak pernah memuatkan grubenv akan mengabaikan arahan tersebut tanpa sebarang ralat.
Adakah saya perlu menetapkan (pin) mengikut nombor entri atau pengecam?
Mengikut pengecam. Nombor entri adalah kedudukan dalam senarai yang disusun semula oleh 10_linux dengan yang terbaharu di atas, jadi memasang atau membuang mana-mana kernel akan mengubah kedudukannya, dan 1>2 yang lapuk masih akan merujuk kepada entri yang sah tetapi salah tanpa sebarang amaran dicetak. Pengecam mengandungi versi kernel, jadi ia sama ada sepadan dengan kernel yang anda maksudkan atau gagal untuk diselesaikan. Senaraikan ia dengan sudo grep -n menuentry_id_option /boot/grub/grub.cfg dan salin rentetan bertanda petikan yang muncul pada setiap baris entri.
Adakah menahan (hold) pakej kernel lebih selamat daripada menukar bootloader?
Untuk tujuan biasa, ya. sudo apt-mark hold linux-image-virtual linux-headers-virtual menghalang kernel yang lebih baharu daripada dipasang, jadi laluan boot tidak akan berubah dan tiada risiko kesilapan daripada konsol yang mungkin tidak anda miliki. Semak nama varian (flavour) yang dipasang pada mesin anda sendiri terlebih dahulu dengan apt list --installed, dan sahkan status hold dengan apt-mark showhold. Pertukarannya ialah kernel yang ditahan tidak akan menerima sebarang kemas kini keselamatan, jadi tentukan bila anda akan menjalankan sudo apt-mark unhold sebelum anda menetapkan hold tersebut.