SSD Nodes Learn 🎉 VPS از $5.50/ماه
راهنماها Matt Connorتوسط Matt Connor

آموزش تغییر و ثابت‌سازی کرنل بوت در VPS لینوکس

اگر تنظیم GRUB_DEFAULT در Ubuntu ابری کار نمی‌کند، این راهنما به شما می‌آموزد چگونه لیست واقعی منو را بخوانید و بدون نیاز به rescue console، کرنل بوت بعدی را دقیقاً تعیین کنید.

چه چیزی تعیین می‌کند VPS شما با کدام هسته (kernel) بوت شود

این‌که VPS شما در بوت بعدی با کدام هسته بالا می‌آید، توسط یک فایل تولیدشده به نام /boot/grub/grub.cfg تعیین می‌شود. شما هرگز نباید این فایل را ویرایش کنید. شما ورودی‌های آن را ویرایش کرده و سپس آن را بازتولید می‌کنید. در imageهای ابری Ubuntu، یکی از این ورودی‌ها توسط فروشنده (vendor) ارائه می‌شود و می‌تواند انتخاب منو را بی‌اثر کند؛ به همین دلیل است که اجرای GRUB_DEFAULT=1 و به دنبال آن update-grub در یک سرور اجاره‌ای هیچ تغییری ایجاد نمی‌کند، در حالی که همین دو مرحله در نصب روی لپ‌تاپ کارساز است.

به این ترتیب عمل کنید. ابتدا تأیید کنید که انتخاب هسته در اختیار شماست. تمام فایل‌های ورودی، از جمله مواردی که فروشنده اضافه کرده است را بخوانید. خروجی تولیدشده را بررسی کرده و تعداد ورودی‌های واقعی موجود در آن را بشمارید. تنها پس از آن، یک روش برای ثابت‌سازی (pinning) انتخاب کنید. اشتباه در این مرحله روی ماشینی که فقط از طریق SSH به آن دسترسی دارید، شما را نیازمند استفاده از rescue console می‌کند؛ بنابراین امن‌ترین پاسخ‌ها در انتهای این صفحه قرار دارند و اغلب همان‌ها گزینه‌های درست هستند.

ابتدا بررسی کنید که آیا کرنل متعلق به خودتان است تا بتوانید آن را Pin کنید

uname -r
systemd-detect-virt
ls -1 /boot/vmlinuz-*

systemd-detect-virt چاپ شدن kvm، qemu یا xen به این معنی است که شما کرنل اختصاصی خود را اجرا می‌کنید و تمام موارد زیر برای شما صدق می‌کند. چاپ شدن lxc یا openvz به این معنی است که سرور شما از کرنل میزبان (host) استفاده می‌کند، بنابراین هیچ bootloader مستقلی ندارید و چیزی برای Pin کردن وجود ندارد. در این حالت، uname -r نسخه‌ای را گزارش می‌دهد که اصلاً در /boot/vmlinuz-* وجود ندارد، زیرا کرنل در حال اجرا متعلق به میزبان است و هیچ تنظیمی روی دیسک شما نمی‌تواند آن را تغییر دهد.

ls -1 /boot/vmlinuz-* لیست واقعی کرنل‌هایی است که می‌توانید از میان آن‌ها انتخاب کنید. اگر این لیست فقط شامل یک خط باشد، کرنل قبلی حذف شده است و هیچ تنظیمات bootloader نمی‌تواند آن را بازگرداند. این اتفاق معمولاً در حین عملیات autoremove رخ می‌دهد؛ بنابراین پیش از آنکه اقدام به پاک‌سازی کرنل‌های قدیمی در Ubuntu روی سروری که برایتان اهمیت دارد کنید، درک این موضوع ضروری است.

فایلی که ویرایش می‌کنید، فایلی نیست که GRUB می‌خواند

/etc/default/grub حاوی انتساب‌های متغیرهای سادهٔ shell است. این یک ورودی است. /boot/grub/grub.cfg خروجی است و با # DO NOT EDIT THIS FILE و دلیل آن آغاز می‌شود. هر چیزی که در خروجی بنویسید، دفعهٔ بعد که یک بستهٔ kernel نصب یا حذف شود، از بین می‌رود؛ زیرا اسکریپت‌های آن بسته، فایل را بازتولید می‌کنند.

cat /usr/sbin/update-grub

update-grub یک wrapper است. این ابزار grub-mkconfig -o /boot/grub/grub.cfg را اجرا می‌کند که متغیرها را می‌خواند، تمام اسکریپت‌های موجود در /etc/grub.d/ را اجرا کرده و نتیجه را می‌نویسد. دو دستور، یک جهت: ورودی‌ها وارد می‌شوند و grub.cfg خارج می‌شود.

چه چیزی تنظیمات شما را بازنویسی می‌کند: /etc/default/grub.d

grep -rn '^[^#]' /etc/default/grub /etc/default/grub.d/

مسیر دوم بخشی است که معمولاً نادیده گرفته می‌شود. grub-mkconfig ابتدا /etc/default/grub را فراخوانی (source) می‌کند و سپس تمام فایل‌های *.cfg موجود در /etc/default/grub.d/ را به ترتیب glob می‌خواند. کدی که این کار را انجام می‌دهد بررسی کنید:

grep -n 'default/grub' /usr/sbin/grub-mkconfig

فراخوانی (sourcing) یک عملیات ساده shell است، بنابراین آخرین مقدار انتساب‌یافته اعمال می‌شود. ایمیج‌های ابری Ubuntu فایل‌هایی را در آن دایرکتوری قرار می‌دهند و مواردی مانند timeout و خط فرمان هسته (kernel command line) را پس از خوانده شدن فایل شما تنظیم می‌کنند. مقدار GRUB_TIMEOUT=10 شما در /etc/default/grub لحظاتی بعد توسط یک فایل ارائه‌دهنده (vendor) که آن را روی 0 تنظیم می‌کند، بازنویسی می‌شود. دستور grep در بالا، انتساب‌های دقیق روی ایمیج شما را چاپ می‌کند، پس به جای اعتماد به این متن، خروجی آن را بخوانید.

قانون عملی که از این موضوع نتیجه می‌شود: تنظیمات خود را در فایلی قرار دهید که از نظر مرتب‌سازی در آخر قرار می‌گیرد، مانند /etc/default/grub.d/99-local.cfg، و از ویرایش /etc/default/grub خودداری کنید. بدین ترتیب، هیچ فایلی که توسط ایمیج ارائه شده باشد، نمی‌تواند پس از شما اجرا شود.

چرا GRUB_FORCE_PARTUUID باعث می‌شود انتخاب منو بی‌اثر باشد

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.cfg

متغیر GRUB_FORCE_PARTUUID به تولیدکننده دستور می‌دهد که سیستم‌فایل ریشه را با استفاده از PARTUUID پارتیشن پیدا کند و آن را مستقیماً به صورت root=PARTUUID=... در خط فرمان هسته بنویسد، به‌جای اینکه هنگام بوت به دنبال UUID سیستم‌فایل بگردد. فروشنده ایمیج این گزینه را تنظیم می‌کند تا یک ایمیج دیسک بتواند به‌طور قابل‌اطمینان روی سخت‌افزاری که برای آن ساخته نشده است، بوت شود. دستور grep دوم، کدی را به شما نشان می‌دهد که بر اساس این متغیر عمل می‌کند و در /etc/grub.d/10_linux قرار دارد. آن اسکریپت روی دیسک خود شماست و مرجع اصلی عملکرد ایمیج شما محسوب می‌شود.

نتیجهٔ این کار اهمیت دارد: در این مسیر، تولیدکننده به‌جای یک لیست کامل از هسته‌های نصب‌شده، یک ورودی بوت مستقیم می‌نویسد. تعداد ورودی‌هایی که در نهایت دارید را بشمارید.

sudo grep -cE '^\s*(menuentry|submenu) ' /boot/grub/grub.cfg
sudo grep -nE '^\s*(menuentry|submenu) ' /boot/grub/grub.cfg

اگر تعداد ورودی‌ها 1 باشد، ورودی دومی برای انتخاب وجود ندارد، بنابراین GRUB_DEFAULT=1 به ورودی‌ای اشاره می‌کند که اصلاً وجود ندارد. GRUB نمی‌تواند آن را پیدا کند، بنابراین اولین ورودی را بوت می‌کند که همان هسته جدیدی است که سعی داشتید از آن اجتناب کنید. grub-set-default نیز کمکی نمی‌کند، زیرا مشکل از بخش پیش‌فرض نیست. منویی که سعی دارید از آن انتخاب کنید، هرگز تولید نشده است.

برای بازگرداندن منوی کامل، فایل فروشنده را به مسیر دیگری منتقل کنید و پیش از اعمال تغییرات، نتیجه را پیش‌نمایش کنید. دستور grub-mkconfig بدون -o، خروجی را در standard output می‌نویسد و هیچ تغییری روی دیسک ایجاد نمی‌کند.

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) '

اگر تعداد ورودی‌ها از 1 به چند مورد افزایش یابد، یعنی پس از حذف اجبار (forcing)، ورودی‌ها ظاهر می‌شوند. هنوز هیچ چیزی نوشته نشده است. اگر تعداد ورودی‌های دوم درست به نظر نمی‌رسد، فایل را به جای قبلی برگردانید، زیرا PARTUUID اجباری همان روشی است که ایمیج ارائه‌دهنده شما برای پیدا کردن سیستم‌فایل ریشه استفاده می‌کند و حذف آن، ماشین را به مسیر جستجوی معمولی منتقل می‌کند. پیش از اجرای واقعی update-grub، حتماً یک snapshot بگیرید.

اگر تنها هدف شما عبور از یک هسته معیوب است، همین‌جا متوقف شوید و از گزینه‌های ایمن‌تر در ادامه استفاده کنید. بازسازی منوی بوت روی یک سرور از راه دور برای فرار از یک به‌روزرسانی تکی، ریسک بیشتری نسبت به مشکل اصلی دارد.

چرا شماره‌های ورودی برای پین کردن مناسب نیستند

GRUB_DEFAULT یک عدد، عنوان یا شناسه را می‌پذیرد. شماره‌ها، ورودی‌های سطح بالا را از 0 شمارش می‌کنند. یک ورودی تو در تو از > به عنوان جداکننده استفاده می‌کند، بنابراین GRUB_DEFAULT="1>2" به معنای ورودی در ایندکس 2 داخل زیرمنوی ایندکس 1 است.

ایندکس‌ها تغییر می‌کنند. 10_linux کرنل‌ها را از جدیدترین به قدیمی‌ترین فهرست می‌کند، بنابراین نصب یک کرنل جدید، تمام ورودی‌های قدیمی‌تر را یک پله به پایین می‌راند و حذف یک کرنل، آن‌ها را به بالا می‌کشد. تنظیم دقیق 1>2 شما همچنان پس از این تغییرات حل می‌شود، اما اکنون به کرنل متفاوتی اشاره دارد. هیچ خطایی رخ نمی‌دهد، هیچ هشداری صادر نمی‌شود و شما تنها پس از reboot متوجه موضوع خواهید شد.

شناسه‌ها تغییر نمی‌کنند، زیرا هر کدام شامل نسخه کرنل هستند. شناسه خود را بخوانید:

sudo awk -F"'" '/menuentry_id_option/ {print $2, "==>", $4}' /boot/grub/grub.cfg

از چند خط اول خروجی که متغیر تعریف‌شده در هدر است صرف‌نظر کنید. پس از آن، سمت چپ عنوانی است که کاربر می‌بیند و سمت راست شناسه‌ای است که باید به ابزارها بدهید. برای یک ورودی داخل زیرمنو، شناسه زیرمنو و شناسه ورودی را با > و دقیقاً به همان ترتیبی که در فرم عددی وجود دارد، به هم متصل کنید.

بوت کردن هسته قبلی برای یک بار با grub-reboot

انتخاب برای یک بار بوت، بهترین گزینه در سرورهای راه دور است، زیرا تنظیمات به‌طور خودکار به حالت قبل بازمی‌گردند. دستور grub-reboot مقدار next_entry را در /boot/grub/grubenv می‌نویسد. GRUB این متغیر را می‌خواند، آن را پاک می‌کند و مقدار پاک‌شده را پیش از بوت کردن هر چیزی ذخیره می‌کند؛ بنابراین اگر هسته دچار kernel panic شود، در بوت بعدی دوباره تلاش نمی‌کند. شما یک فرصت دارید و پس از آن، دستگاه به‌طور خودکار به حالت پیش‌فرض بازمی‌گردد.

ابتدا تأیید کنید که پیکربندی تولیدشدهٔ شما اصلاً این متغیر را می‌خواند یا خیر:

sudo grep -n -B2 -A5 'next_entry' /boot/grub/grub.cfg

شما باید یک خط load_env و بلوکی که default را از next_entry تنظیم می‌کند، ببینید. اگر دستور grep خروجی نداشت، یعنی تصویر (image) شما در زمان بوت هرگز grubenv را نمی‌خواند؛ بنابراین grub-reboot در شل پذیرفته می‌شود اما توسط بوت‌لودر نادیده گرفته خواهد شد. این همان مسیر بوت مستقیم و اجباری از بخش قبلی است که در جای دیگری ظاهر شده است.

sudo grub-reboot '<the identifier you copied>'
sudo grub-editenv list

دستور grub-editenv list اکنون باید یک خط next_entry= را چاپ کند که دقیقاً شامل مقداری است که شما وارد کرده‌اید. کنسول ارائه‌دهندهٔ خود را در یک تب مرورگر باز کنید، سپس سیستم را ری‌بوت کرده و نتیجه را بررسی کنید.

sudo reboot
uname -r

اگر uname -r نسخه قدیمی‌تر را گزارش کرد، یعنی پین کردن (pin) با موفقیت انجام شده است. اگر نسخه جدید گزارش شد، یا شناسه (identifier) به درستی شناسایی نشده یا grubenv خوانده نمی‌شود. در هر صورت دستگاه بالا آمده است، که این دقیقاً هدف استفاده از روش یک‌بار مصرف (one shot) است.

پایدارسازی انتخاب با استفاده از GRUB_DEFAULT=saved

GRUB_DEFAULT=saved باعث می‌شود مقدار پیش‌فرض از saved_entry در فایل grubenv خوانده شود و شما این مقدار را با grub-set-default تنظیم می‌کنید. این تنظیم پس از نصب هسته‌های جدید (kernel) باقی می‌ماند، زیرا update-grub فایل grub.cfg را بازنویسی می‌کند و هرگز به 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.cfg

دستور آخر باید set default="${saved_entry}" را چاپ کند. اگر خروجی set default="0" باشد، یعنی فایلی که پس از فایل شما پردازش شده، GRUB_DEFAULT را به یک مقدار ثابت بازگردانده است؛ بنابراین لیست /etc/default/grub.d/ را دوباره بررسی کنید و مطمئن شوید که 99-local.cfg واقعاً در آخرین جایگاه قرار دارد.

GRUB_SAVEDEFAULT=true یک تنظیم متفاوت است و به‌راحتی با این مورد اشتباه گرفته می‌شود. این گزینه هر آنچه را که به‌تازگی بوت کرده‌اید به‌عنوان پیش‌فرض جدید ذخیره می‌کند، بنابراین پیش‌فرض همیشه آخرین بوت موفق خواهد بود. در یک سرور، این یعنی یک reboot بدون نظارت می‌تواند پین (pin) شما را به‌طور خودکار تغییر دهد. مگر اینکه دقیقاً همین رفتار مد نظر شما باشد، آن را غیرفعال نگه دارید.

پین کردن بر اساس شناسه (identifier) همچنان یک نقطه ضعف دارد. اگر هسته‌ای که نام برده شده را حذف کنید، شناسه دیگر قابل شناسایی نخواهد بود و سیستم به اولین ورودی بازمی‌گردد. بنابراین، بسته مربوطه را hold کنید یا آن هسته را از لیست autoremove خارج نگه دارید.

نمایش منو در کنسول ارائه‌دهنده

انتخاب تعاملی نیازمند نمایش منو روی صفحه است، اما ایمیج‌های ابری آن را مخفی می‌کنند. این موارد را در فایلی که آخرین اولویت مرتب‌سازی را دارد قرار دهید و سپس sudo update-grub را اجرا کنید.

GRUB_TIMEOUT=10
GRUB_TIMEOUT_STYLE=menu
GRUB_RECORDFAIL_TIMEOUT=10

GRUB_TIMEOUT_STYLE=hidden به همراه GRUB_TIMEOUT=0 هیچ چیزی را نمایش نمی‌دهند، بنابراین کسی که کنسول را مشاهده می‌کند، می‌بیند که پیام‌های هسته بلافاصله شروع می‌شوند و نتیجه می‌گیرد که بوت‌لودر نادیده گرفته شده است. GRUB_RECORDFAIL_TIMEOUT یک وقفه (timeout) جداگانه است که پس از یک بوت ناقص استفاده می‌شود و ایمیج‌های ابری آن را نیز روی 0 تنظیم می‌کنند؛ به همین دلیل است که سروری که بوت آن با شکست مواجه شده، متوقف نمی‌شود تا منتظر شما بماند.

اگر ارائه‌دهندهٔ شما به جای کنسول گرافیکی، کنسول سریال ارائه می‌دهد و همچنان چیزی نمی‌بینید، GRUB در حال نوشتن روی ترمینالی است که شما نمی‌توانید آن را ببینید. هر دو خط را با هم اضافه کنید، زیرا خط اول خروجی‌ها را انتخاب می‌کند و خط دوم پورت را پیکربندی می‌نماید:

GRUB_TERMINAL="console serial"
GRUB_SERIAL_COMMAND="serial --speed=115200 --unit=0 --word=8 --parity=no --stop=1"

از این پس، ده ثانیه به هر بوت اضافه می‌شود. پس از اتمام کار، مقدار timeout را دوباره روی 0 تنظیم کنید.

گزینه‌های ایمن‌تر از ویرایش bootloader

تغییر تنظیمات bootloader در ماشینی که فقط از طریق SSH به آن دسترسی دارید، پرخطرترین گزینه در این صفحه است. راه‌حل‌های کم‌هزینه‌تری وجود دارند که معمولاً مشکل اصلی را برطرف می‌کنند.

بسته‌های kernel را نگه دارید (Hold). اگر هدف این است که «kernel جدیدتر به من نده»، این موضوع را به جای bootloader، به package manager بگویید.

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 showhold

از نام‌هایی استفاده کنید که دستور اول چاپ کرده است، زیرا imageهای ابری معمولاً به جای generic، نسخه virtual یا kvm را نصب می‌کنند. بسته نگه‌داشته‌شده توسط apt upgrade نادیده گرفته می‌شود که آن را با The following packages have been kept back: اعلام می‌کند، و همچنین توسط unattended upgrades در Ubuntu نیز نادیده گرفته می‌شود. هزینه این کار واقعی است: kernel نگه‌داشته‌شده دیگر وصله‌های امنیتی را دریافت نمی‌کند، بنابراین با آن به عنوان یک توقف موقت با تاریخ انقضا برخورد کنید و با sudo apt-mark unhold آن را آزاد کنید. اگر به دلیل هزینه downtime ناشی از reboot از به‌روزرسانی kernel اجتناب می‌کنید و نه به این دلیل که یک kernel خاص مشکل دارد، live kernel patching در VPS پاسخ مناسب‌تری است.

پیش از به‌روزرسانی snapshot بگیرید. یک snapshot در عرض چند دقیقه سیستم را بازیابی می‌کند، بدون نیاز به تایپ در کنسول و بدون ریسک تغییر ناقص bootloader. snapshot بگیرید، به‌روزرسانی کنید، reboot کنید و بررسی کنید. اگر kernel جدید رفتار نامناسبی داشت، به حالت قبل برگردید و مسیر boot دقیقاً همان چیزی خواهد بود که بود.

برای سیستمی که از قبل از دسترس خارج شده، از کنسول یا rescue image استفاده کنید. وقتی سرور boot نمی‌شود، پیکربندی bootloader جایی نیست که بتوانید آن را تعمیر کنید، و آن مسیر بازیابی، رویه خاص خود را دارد: هنگامی که VPS پس از به‌روزرسانی kernel بوت نمی‌شود چه باید کرد.

چه چیزی از کار می‌افتد و پیامی که مشاهده خواهید کرد

ویرایش شما در /boot/grub/grub.cfg ناپدید شده است. یک بسته هسته (kernel) نصب یا حذف شده است، اسکریپت نگهدارنده آن update-grub را اجرا کرده و فایل از روی ورودی‌ها بازسازی شده است. هدر # DO NOT EDIT THIS FILE نام دو مکان ورودی را مشخص می‌کند. آن‌ها را ویرایش کنید.

grub-editenv: error: environment block too small. فایل /boot/grub/grubenv گم شده یا ناقص است. آن را با sudo grub-editenv /boot/grub/grubenv create بازسازی کنید، سپس مقدار خود را دوباره تنظیم کرده و با sudo grub-editenv list تأیید کنید.

یک هسته پین‌شده (pinned) با خطای VFS: Unable to mount root fs on unknown-block(0,0) دچار kernel panic می‌شود. ورودی که پین کرده‌اید به هسته یا initrd اشاره دارد که دیگر روی دیسک موجود نیست؛ معمولاً به این دلیل که بسته حذف شده اما شناسه در grubenv باقی مانده است. بازیابی از طریق بوت کنسول با یک ورودی سالم و سپس پاک‌کردن مقدار قدیمی انجام می‌شود.

uname -r پس از ری‌بوتی که انتظار تغییر داشتید، بدون تغییر مانده است. سه مورد را به ترتیب بررسی کنید: آیا grub-editenv list هنوز مقدار شما را نشان می‌دهد یا مصرف شده است؛ آیا شناسه‌ای که تنظیم کرده‌اید در grub.cfg فعلی ظاهر می‌شود؛ آیا grub.cfg حاوی خط set default است که متغیر تنظیم‌شده توسط شما را می‌خواند. یکی از این سه مورد همیشه دلیل این اتفاق است.

منو پس از یک کرش به‌طور خودکار ظاهر شد. GRUB یک بوت ناموفق را در grubenv به عنوان recordfail=1 ثبت می‌کند و این کار باعث می‌شود منو در بوت بعدی ظاهر شود تا یک کاربر انسانی بتواند مداخله کند. پس از اطمینان از سلامت سیستم، آن را با sudo grub-editenv /boot/grub/grubenv unset recordfail پاک کنید.


تنها جمله‌ای که ارزش به خاطر سپردن دارد این است: فایلی که ویرایش می‌کنید همان فایلی نیست که GRUB می‌خواند، و در imageهای ابری، شکاف بین این دو منشأ سردرگمی است. ابتدا پیکربندی تولیدشده را بخوانید. هر تصمیمی در این صفحه بر اساس چیزی است که واقعاً در آن فایل نوشته شده است.

FAQ

چرا تنظیم GRUB_DEFAULT=1 باعث تغییر کرنلی که VPS من با آن بوت می‌شود، نمی‌شود؟

زیرا در ایمیج‌های ابری Ubuntu، فایل /boot/grub/grub.cfg تولیدشده اغلب تنها شامل یک ورودی بوت است؛ بنابراین ایندکس 1 به هیچ موردی اشاره نمی‌کند و GRUB به ناچار به اولین ورودی بازمی‌گردد. این موضوع را با sudo grep -cE '^\s*(menuentry|submenu) ' /boot/grub/grub.cfg بررسی کنید. تعداد 1 پاسخ نهایی است. علت این امر GRUB_FORCE_PARTUUID است که توسط ارائه‌دهنده ایمیج در فایلی در مسیر /etc/default/grub.d/ تنظیم شده است. این تنظیم، تولیدکننده را به‌جای ساختن لیست کاملی از کرنل‌های نصب‌شده، روی مسیر بوت مستقیم قرار می‌دهد. فایل مربوطه را با grep -rn GRUB_FORCE_PARTUUID /etc/default/grub /etc/default/grub.d/ پیدا کنید.

چگونه می‌توانم فقط برای یک بار با کرنل قبلی بوت کنم؟

دستور sudo grub-reboot '<identifier>' را با شناسه‌ای که از grub.cfg خود کپی کرده‌اید اجرا کنید و سپس در حالی که کنسول ارائه‌دهنده باز است، سیستم را ریبوت کنید. GRUB مقدار next_entry را پیش از بوت پاک می‌کند، بنابراین این انتخاب دقیقاً برای یک بار اعمال می‌شود و کرنلی که دچار kernel panic شود، دوباره تلاش نمی‌شود. مقدار ثبت‌شده را با sudo grub-editenv list تأیید کنید. پیش از تکیه بر این روش، sudo grep -n next_entry /boot/grub/grub.cfg را اجرا کنید، زیرا ایمیجی که پیکربندی آن هرگز grubenv را بارگذاری نمی‌کند، این دستور را بدون هیچ خطایی نادیده می‌گیرد.

آیا باید از شماره ورودی استفاده کنم یا شناسه؟

از شناسه استفاده کنید. شماره‌های ورودی، موقعیت‌هایی در لیستی هستند که 10_linux آن‌ها را بر اساس جدیدترین‌ها بازسازی می‌کند؛ بنابراین نصب یا حذف هر کرنل، ترتیب آن‌ها را تغییر می‌دهد و یک 1>2 قدیمی همچنان به یک ورودی واقعی اما اشتباه اشاره می‌کند، بدون آنکه هشداری چاپ شود. شناسه‌ها حاوی نسخه کرنل هستند، بنابراین یا با کرنل مورد نظر شما مطابقت دارند یا در صورت عدم تطابق، با خطا مواجه می‌شوند. آن‌ها را با sudo grep -n menuentry_id_option /boot/grub/grub.cfg لیست کنید و رشته داخل کوتیشن که در هر خط ورودی آمده است را کپی کنید.

آیا نگه‌داشتن (hold) بسته کرنل امن‌تر از تغییر بوت‌لودر است؟

برای هدف معمول، بله. sudo apt-mark hold linux-image-virtual linux-headers-virtual از ورود کرنل جدیدتر جلوگیری می‌کند، بنابراین مسیر بوت هرگز تغییر نمی‌کند و خطایی در کنسولی که ممکن است به آن دسترسی نداشته باشید، رخ نمی‌دهد. ابتدا نام‌های flavour نصب‌شده روی سیستم خود را با apt list --installed بررسی کنید و وضعیت hold را با apt-mark showhold تأیید نمایید. نکته منفی این است که کرنلِ hold شده، هیچ وصله امنیتی دریافت نمی‌کند؛ بنابراین پیش از اجرای دستور hold، تصمیم بگیرید که چه زمانی قصد دارید sudo apt-mark unhold را اجرا کنید.