تغییر هسته پیشفرض در VPS و سرورهای ابری
تنظیم GRUB_DEFAULT در Ubuntu ابری اغلب بیاثر است. یاد بگیرید چگونه لیست منو را استخراج کنید و بدون خطر از دسترس خارج شدن سرور، هسته بوت بعدی را با دقت پین کنید.
چه چیزی تعیین میکند VPS شما با کدام هسته بوت شود
اینکه VPS شما در بوت بعدی با کدام هسته (kernel) بالا میآید، توسط یک فایل تولیدشده به نام /boot/grub/grub.cfg تعیین میشود. شما هرگز نباید این فایل را ویرایش کنید. شما ورودیهای آن را ویرایش کرده و سپس آن را بازتولید میکنید. در imageهای ابری Ubuntu، یکی از این ورودیها توسط فروشنده (vendor) ارائه میشود و میتواند انتخابهای منو را بیاثر کند؛ به همین دلیل است که اجرای GRUB_DEFAULT=1 و به دنبال آن update-grub در یک سرور اجارهای هیچ تغییری ایجاد نمیکند، در حالی که همین دو مرحله روی یک لپتاپ به درستی کار میکنند.
این مراحل را به ترتیب انجام دهید. ابتدا تأیید کنید که حق انتخاب هسته با شماست. تمام فایلهای ورودی، از جمله مواردی که توسط فروشنده اضافه شدهاند را مطالعه کنید. خروجی تولیدشده را بخوانید و تعداد ورودیهایی که واقعاً در آن وجود دارد را بشمارید. تنها پس از آن، یک روش برای ثابت نگهداشتن (pinning) هسته انتخاب کنید. اشتباه در این مورد روی ماشینی که فقط از طریق SSH به آن دسترسی دارید، شما را مجبور به استفاده از rescue console میکند؛ بنابراین امنترین پاسخها در انتهای این صفحه قرار دارند و اغلب همانها گزینههای درست هستند.
ابتدا بررسی کنید که آیا هسته متعلق به شماست تا بتوانید آن را پین کنید
uname -r
systemd-detect-virt
ls -1 /boot/vmlinuz-*systemd-detect-virt چاپ شدن kvm، qemu یا xen به این معنی است که شما هسته اختصاصی خود را اجرا میکنید و تمام موارد زیر صدق میکنند. چاپ شدن lxc یا openvz به این معنی است که سرور شما از هسته میزبان (host) استفاده میکند، بنابراین هیچ bootloader اختصاصی برای شما وجود ندارد و چیزی برای پین کردن نیست. در این حالت، 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-grubupdate-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 لحظاتی بعد توسط یک فایل ارائهشده توسط توزیعکننده که آن را روی 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، خروجی را در استاندارد خروجی (stdout) مینویسد و هیچ تغییری روی دیسک ایجاد نمیکند.
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 خروجی نداشت، یعنی ایمیج شما هرگز grubenv را در زمان بوت نمیخواند؛ بنابراین grub-reboot در شل پذیرفته میشود اما توسط bootloader نادیده گرفته خواهد شد. این همان مسیر بوت مستقیم و اجباری از بخش قبلی است که در اینجا نیز دیده میشود.
sudo grub-reboot '<the identifier you copied>'
sudo grub-editenv listاکنون grub-editenv list باید یک خط next_entry= را چاپ کند که دقیقاً حاوی همان مقداری است که وارد کردهاید. کنسول ارائهدهنده سرور خود را در یک تب مرورگر باز کنید، سپس سیستم را reboot کرده و نتیجه را بررسی کنید.
sudo rebootuname -rاگر uname -r نسخه قدیمیتر را گزارش کرد، یعنی pin کردن با موفقیت انجام شده است. اگر نسخه جدید گزارش شد، یعنی یا شناسه (identifier) به درستی شناسایی نشده یا grubenv خوانده نمیشود؛ در هر دو صورت دستگاه بالا آمده است که این دقیقاً هدف از استفاده از روش one-shot است.
تثبیت انتخاب با استفاده از GRUB_DEFAULT=saved
GRUB_DEFAULT=saved باعث میشود مقدار پیشفرض از saved_entry در فایل grubenv خوانده شود و شما این مقدار را با استفاده از grub-set-default تنظیم میکنید. این تنظیم پس از نصب کرنلهای جدید باقی میماند، زیرا 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=10GRUB_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"از این پس، ده ثانیه به هر بوت اضافه میشود. پس از اتمام کار، وقفه را دوباره روی 0 تنظیم کنید.
گزینههای ایمنتر از ویرایش بوتلودر
تغییر تنظیمات بوتلودر در ماشینی که فقط از طریق SSH به آن دسترسی دارید، پرخطرترین گزینه در این صفحه است. پاسخهای کمهزینهتری وجود دارند که معمولاً مشکل اصلی را حل میکنند.
بستههای هسته (kernel) را نگه دارید (Hold). اگر هدف شما این است که «هسته جدیدتر به من نده»، این موضوع را به جای بوتلودر، به مدیر بسته (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از نامهایی استفاده کنید که دستور اول چاپ کرده است، زیرا ایمیجهای ابری معمولاً به جای generic، نسخه virtual یا kvm را نصب میکنند. اگر هسته جدیدتر همزمان با تازهسازی ایمیج ظاهر شده و شک دارید که خودِ نسخه (release) تغییر کرده است، باید بدانید که اینطور نیست؛ زیرا یک point release همان بهروزرسانیهایی است که قبلاً دریافت کردهاید و در رسانه نصب جدید ادغام شدهاند و به سروری که از قبل پچ شده، چیزی ارائه نمیدهد که هفتهها پیش به آن پیشنهاد نشده باشد. بسته نگه داشته شده (held) توسط apt upgrade نادیده گرفته میشود که آن را با The following packages have been kept back: اعلام میکند، و همچنین توسط unattended upgrades در اوبونتو نیز نادیده گرفته میشود. هزینه این کار واقعی است: هسته نگه داشته شده دیگر اصلاحات امنیتی را دریافت نمیکند، بنابراین با آن به چشم یک وقفه زماندار نگاه کنید و با sudo apt-mark unhold آن را آزاد کنید. اگر به این دلیل از بهروزرسانی هسته اجتناب میکنید که ریبوت باعث downtime میشود و نه به این دلیل که یک هسته خاص مشکل دارد، live kernel patching روی یک VPS پاسخ مناسبتری است.
پیش از بهروزرسانی اسنپشات بگیرید. اسنپشات در عرض چند دقیقه سیستم را بازیابی میکند، بدون نیاز به تایپ در کنسول و بدون ریسک تغییر ناقص بوتلودر. اسنپشات بگیرید، بهروزرسانی کنید، ریبوت کنید و وضعیت را بررسی کنید. اگر هسته جدید بدرفتاری کرد، به حالت قبل برگردید؛ مسیر بوت دقیقاً همان چیزی خواهد بود که قبلاً بود.
برای سیستمی که از قبل از دسترس خارج شده، از کنسول یا ایمیج نجات (rescue image) استفاده کنید. وقتی سرور بوت نمیشود، پیکربندی بوتلودر جایی نیست که بتوانید آن را اصلاح کنید و آن مسیر بازیابی، رویه خاص خود را دارد: هنگامی که یک VPS پس از بهروزرسانی هسته بوت نمیشود چه باید کرد.
چه چیزی از کار میافتد و پیامی که مشاهده خواهید کرد
ویرایش شما در /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 تأیید کنید.
هستهای که پین (pin) شده با 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 میخواند و در ایمیجهای ابری، فاصله بین این دو همان جایی است که سردرگمی ایجاد میشود. ابتدا پیکربندی تولیدشده را بخوانید. تمام تصمیمات در این صفحه بر اساس چیزی است که واقعاً در آن فایل نوشته شده است.
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 را پیش از بوت پاک میکند، بنابراین این انتخاب دقیقاً برای یک بار اعمال میشود و کرنلی که دچار 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 را اجرا کنید.