Ubuntu VPS boot kernel sabitleme rehberi
Ubuntu bulut imajlarinda GRUB_DEFAULT ayarinin neden etkisiz kaldigini ogrenin. Sunucunuzdaki menu girdilerini listeleyerek bir sonraki acilista kernel secimini hatasiz yapin.
VPS'nizin hangi çekirdek ile başlatılacağına ne karar verir
VPS'nizin bir sonraki başlatma işleminde hangi çekirdeği kullanacağı, oluşturulan tek bir dosya olan /boot/grub/grub.cfg ile belirlenir. Bu dosyayı asla doğrudan düzenlemeyin. Bunun yerine, dosyayı besleyen girdileri düzenleyin ve dosyayı yeniden oluşturun. Ubuntu bulut imajlarında bu girdilerden biri imaj sağlayıcısı tarafından sağlanır ve bu durum menü seçimini geçersiz kılabilir. Kiralık bir sunucuda GRUB_DEFAULT=1 komutunu takiben update-grub komutunun hiçbir şeyi değiştirmemesinin, ancak aynı adımların dizüstü bilgisayar kurulumunda çalışmasının nedeni budur.
İşlemleri şu sırayla gerçekleştirin. Çekirdek seçme yetkisinin sizde olduğunu doğrulayın. Sağlayıcının ekledikleri de dahil olmak üzere tüm girdi dosyalarını okuyun. Oluşturulan çıktı dosyasını okuyun ve içinde gerçekten kaç girdi bulunduğunu sayın. Ancak bu aşamadan sonra bir sabitleme yöntemi seçin. Bu işlemi yalnızca SSH üzerinden erişebildiğiniz bir makinede yanlış yapmak, kurtarma konsolu kullanmanızı gerektirir; bu nedenle en güvenli yanıtlar bu sayfanın sonundadır ve genellikle doğru olanlar da bunlardır.
Sabitleme işleminden önce çekirdeğin size ait olduğunu doğrulayın
uname -r
systemd-detect-virt
ls -1 /boot/vmlinuz-*systemd-detect-virt çıktısı kvm, qemu veya xen ise kendi çekirdeğinizi çalıştırıyorsunuz demektir ve aşağıdaki tüm adımlar geçerlidir. lxc veya openvz çıktısı, sunucunuzun ana makinenin çekirdeğini paylaştığı anlamına gelir; bu durumda size ait bir önyükleyici (bootloader) yoktur ve sabitlenecek bir şey bulunmaz. Bu senaryoda uname -r, /boot/vmlinuz-* içerisinde hiç yer almayan bir sürüm bildirir; çünkü çalışan çekirdek ana makineye aittir ve diskinizdeki hiçbir ayar bunu değiştiremez.
ls -1 /boot/vmlinuz-*, seçebileceğiniz çekirdeklerin gerçek listesidir. Eğer liste tek bir satırdan oluşuyorsa, önceki çekirdek zaten silinmiştir ve hiçbir önyükleyici ayarı onu geri getiremez. Bu durum genellikle bir autoremove işlemi sırasında gerçekleşir; bu nedenle önemsediğiniz bir sistemde Ubuntu üzerinde eski çekirdekleri temizleme işleminden önce bu mekanizmayı anlamak önemlidir.
Düzenlediğiniz dosya GRUB'ın okuduğu dosya değildir
/etc/default/grub, düz kabuk değişkeni atamalarını tutar. Bu bir girdidir. /boot/grub/grub.cfg ise çıktıdır ve # DO NOT EDIT THIS FILE ile gerekçesiyle başlar. Çıktı dosyasına yazdığınız her şey, bir çekirdek paketi kurulduğunda veya kaldırıldığında silinir; çünkü paket betikleri bu dosyayı yeniden oluşturur.
cat /usr/sbin/update-grubupdate-grub bir sarmalayıcıdır. Değişkenleri okuyan, /etc/grub.d/ içindeki her betiği çalıştıran ve sonucu yazan grub-mkconfig -o /boot/grub/grub.cfg aracını çalıştırır. İki komut, tek yön: girdiler içeri girer, grub.cfg dışarı çıkar.
Ayarlarınızı ne geçersiz kılar: /etc/default/grub.d
grep -rn '^[^#]' /etc/default/grub /etc/default/grub.d/İkinci yol, insanların gözden kaçırdığı kısımdır. grub-mkconfig önce /etc/default/grub dosyasını, ardından /etc/default/grub.d/ dizinindeki her bir *.cfg dosyasını glob sıralamasına göre kaynak olarak kullanır. Bu işlemi gerçekleştiren kodu inceleyin:
grep -n 'default/grub' /usr/sbin/grub-mkconfigKaynak kullanımı (sourcing) düz bir kabuk (shell) işlemidir, bu nedenle en son yapılan atama geçerli olur. Ubuntu bulut imajları bu dizin içerisinde dosyalarla birlikte gelir ve sizin dosyanız okunduktan sonra zaman aşımı (timeout) ve kernel komut satırı gibi ayarları yeniden yapılandırırlar. /etc/default/grub içindeki GRUB_TIMEOUT=10 değeriniz, kısa bir süre sonra onu 0 olarak ayarlayan bir üretici dosyası tarafından üzerine yazılır. Yukarıdaki grep komutu, imajınızdaki kesin atamaları listeler; bu nedenle bu cümleye güvenmek yerine çıktıları okuyun.
Buradan çıkan pratik kural şudur: /etc/default/grub dosyasını düzenlemek yerine, kendi ayarlarınızı sıralamada en sona kalacak bir dosyaya, örneğin /etc/default/grub.d/99-local.cfg dosyasına ekleyin. Böylece imaj ile birlikte gelen hiçbir dosya, sizin ayarlarınızdan sonra çalışamaz.
GRUB_FORCE_PARTUUID neden menü seçimini geçersiz kılar
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, oluşturucuya kök dosya sistemini önyükleme sırasında bir dosya sistemi UUID'si aramak yerine, doğrudan çekirdek komut satırına root=PARTUUID=... olarak yazılmış olan bölüm UUID'si ile bulmasını söyler. Görüntü sağlayıcısı bunu, tek bir disk görüntüsünün oluşturulmadığı donanımlarda güvenilir bir şekilde önyüklenmesini sağladığı için ayarlar. İkinci grep komutu, /etc/grub.d/10_linux içinde değişken üzerinde işlem yapan kodu gösterir. Bu betik kendi diskinizdedir ve görüntünüzün ne yaptığı konusunda yetkili kaynaktır.
Burada önemli olan sonuç şudur: bu yolda oluşturucu, yüklü çekirdeklerin tam bir listesi yerine doğrudan bir önyükleme girdisi yazar. Elinizde ne kaldığını sayın.
sudo grep -cE '^\s*(menuentry|submenu) ' /boot/grub/grub.cfg
sudo grep -nE '^\s*(menuentry|submenu) ' /boot/grub/grub.cfgEğer sayı 1 ise, seçilecek ikinci bir girdi yoktur, bu nedenle GRUB_DEFAULT=1 mevcut olmayan bir girdiyi adlandırır. GRUB bunu çözümleyemez, bu yüzden kaçınmaya çalıştığınız yeni çekirdek olan ilk girdiyi önyükler. grub-set-default de yardımcı olmaz, çünkü varsayılan ayar hatalı olan kısım değildir. Seçmeye çalıştığınız menü hiçbir zaman oluşturulmamıştır.
Tam bir menüye geri dönmek için, sağlayıcı dosyasını kenara taşıyın ve uygulamadan önce sonucu önizleyin. -o olmadan kullanılan grub-mkconfig, standart çıktıya yazar ve diskte hiçbir şeye dokunmaz.
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'den fazlasına sıçrayan bir sayı, zorlama kaldırıldığında girdilerin göründüğü anlamına gelir. Henüz hiçbir şey yazılmamıştır. Eğer ikinci sayı doğru görünmüyorsa dosyayı geri koyun, çünkü zorunlu tutulan PARTUUID, sağlayıcınızın görüntüsünün kök dosya sistemini nasıl bulduğudur ve bunu kaldırmak makineyi arama yoluna yönlendirir. update-grub komutunu gerçek anlamda çalıştırmadan önce bir anlık görüntü (snapshot) alın.
Tek amacınız hatalı bir çekirdekten kurtulmaksa, burada durun ve aşağıda belirtilen daha güvenli seçenekleri kullanın. Tek bir yükseltmeden kaçmak için uzak bir sunucuda önyükleme menüsünü yeniden oluşturmak, sorunun kendisinden daha fazla risk taşır.
Giriş numaralarını sabitlemenin neden yanlış olduğu
GRUB_DEFAULT bir sayı, başlık veya tanımlayıcı kabul eder. Sayılar, en üst düzey girişleri 0'dan başlayarak sayar. İç içe geçmiş bir giriş, ayırıcı olarak > kullanır; bu nedenle GRUB_DEFAULT="1>2", 1. dizindeki alt menünün içindeki 2. dizinde bulunan girişi ifade eder.
Dizinler değişebilir. 10_linux çekirdekleri en yenisi en üstte olacak şekilde listeler; bu nedenle yeni bir çekirdek yüklemek tüm eski girişleri bir sıra aşağı iter, bir çekirdeği kaldırmak ise onları yukarı çeker. Özenle belirlediğiniz 1>2 ayarı, bu işlemden sonra da çözümlenmeye devam eder. Ancak artık farklı bir çekirdeği işaret eder. Hiçbir hata oluşmaz, hiçbir uyarı verilmez ve durumu ancak yeniden başlatma sonrasında fark edersiniz.
Tanımlayıcılar yer değiştirmez çünkü her biri çekirdek sürümünü içerir. Kendi tanımlayıcılarınızı şu şekilde okuyun:
sudo awk -F"'" '/menuentry_id_option/ {print $2, "==>", $4}' /boot/grub/grub.cfgÇıktının ilk birkaç satırını görmezden gelin; bunlar başlıkta tanımlanan değişkenlerdir. Bundan sonra sol tarafta kullanıcının gördüğü başlık, sağ tarafta ise araçlara ileteceğiniz tanımlayıcı yer alır. Bir alt menü içindeki giriş için, alt menü tanımlayıcısı ile giriş tanımlayıcısını, sayısal biçimde olduğu gibi tam olarak o sırada > ile birleştirin.
grub-reboot ile önceki çekirdeği bir kez başlatma
Uzak bir sunucuda tek seferlik seçim yapmak en doğru yöntemdir çünkü bu işlem kendi kendini geri alır. grub-reboot, next_entry değerini /boot/grub/grubenv içine yazar. GRUB bu değişkeni okur, temizler ve herhangi bir şeyi başlatmadan önce temizlenmiş değeri kaydeder; böylece çekirdek panik yaşarsa bir sonraki açılışta tekrar denenmez. Bir deneme hakkınız olur, ardından makine kendiliğinden normal varsayılan ayarlarına döner.
Öncelikle oluşturulan yapılandırmanızın bu değişkeni okuduğunu doğrulayın:
sudo grep -n -B2 -A5 'next_entry' /boot/grub/grub.cfgload_env satırını ve next_entry üzerinden default değerini atayan bir bloğu görmeniz gerekir. Eğer grep hiçbir çıktı vermezse, imajınız açılışta grubenv değerini okumuyor demektir; bu durumda grub-reboot komutu kabukta kabul edilecek ancak önyükleyici tarafından görmezden gelinecektir. Bu, önceki bölümde görülen zorunlu doğrudan önyükleme yolunun ikinci bir yerde karşımıza çıkmasıdır.
sudo grub-reboot '<the identifier you copied>'
sudo grub-editenv listgrub-editenv list artık tam olarak ilettiğiniz değeri içeren bir next_entry= satırı yazdırmalıdır. Tarayıcı sekmesinde sağlayıcınızın konsolunu açın, ardından yeniden başlatın ve sonucu kontrol edin.
sudo rebootuname -runame -r komutunun eski sürümü bildirmesi, sabitlemenin (pin) çalıştığı anlamına gelir. Yeni sürümü bildirmesi ise tanımlayıcının çözümlenemediği veya grubenv dosyasının okunmadığı anlamına gelir; her iki durumda da makine açılmış olur ki tek seferlik (one shot) yöntemi kullanmanın amacı da budur.
GRUB_DEFAULT=saved ile seçimi kalıcı hale getirin
GRUB_DEFAULT=saved, varsayılan değerin grubenv içindeki saved_entry dosyasından alınmasını sağlar; bu değeri grub-set-default ile ayarlarsınız. Bu ayar çekirdek kurulumlarından etkilenmez, çünkü update-grub, grub.cfg dosyasını yeniden yazar ancak grubenv dosyasına asla dokunmaz.
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.cfgSon komut set default="${saved_entry}" çıktısını vermelidir. Eğer set default="0" çıktısını veriyorsa, dosyanızdan sonra işlenen bir yapılandırma GRUB_DEFAULT değerini tekrar sabit bir değere döndürmüş demektir; bu durumda /etc/default/grub.d/ listesini tekrar kontrol edin ve 99-local.cfg değerinin gerçekten en sonda yer aldığından emin olun.
GRUB_SAVEDEFAULT=true farklı bir ayardır ve bu ayarla kolayca karıştırılabilir. Bu ayar, en son başlattığınız sistemi yeni varsayılan yapar; böylece varsayılan değer, en son başarılı önyüklemeyi takip eder. Bir sunucuda bu, gözetimsiz bir yeniden başlatmanın sabitlediğiniz çekirdeği sessizce değiştirebileceği anlamına gelir. İstediğiniz davranış bu değilse, bu ayarı kapalı tutun.
Tanımlayıcıya göre sabitleme işlemi tek bir durumda başarısız olur. İsmi geçen çekirdeği kaldırırsanız, tanımlayıcı çözümlenemez hale gelir ve sistem sizi tekrar ilk girdiye yönlendirir. Bu nedenle paketi tutun (hold) veya ilgili çekirdeği autoremove kapsamı dışında bırakın.
Menüyü sağlayıcı konsoluna getirme
Etkileşimli seçim yapmak için menünün ekranda görünmesi gerekir, ancak bulut imajları bunu gizler. Aşağıdakileri alfabetik olarak en son sırada yer alan dosyaya ekleyin ve ardından sudo update-grub komutunu çalıştırın.
GRUB_TIMEOUT=10
GRUB_TIMEOUT_STYLE=menu
GRUB_RECORDFAIL_TIMEOUT=10GRUB_TIMEOUT_STYLE=hidden ve GRUB_TIMEOUT=0 birlikte kullanıldığında hiçbir şey görünmez; bu nedenle konsolu izleyen kişi çekirdek mesajlarının hemen başladığını görür ve önyükleyicinin (bootloader) atlandığı sonucuna varır. GRUB_RECORDFAIL_TIMEOUT, tamamlanmamış bir önyüklemeden sonra kullanılan ayrı bir zaman aşımı değeridir ve bulut imajları bunu da 0 olarak ayarlar. Önyükleme yapamayan bir sunucunun durup sizi beklememesinin nedeni budur.
Sağlayıcınız grafiksel bir konsol yerine seri konsol sağlıyorsa ve hala hiçbir şey göremiyorsanız, GRUB göremediğiniz bir terminale yazıyor demektir. Her iki satırı birlikte ekleyin; çünkü ilki çıktıları seçer, ikincisi ise portu yapılandırır:
GRUB_TERMINAL="console serial"
GRUB_SERIAL_COMMAND="serial --speed=115200 --unit=0 --word=8 --parity=no --stop=1"Bundan sonra her önyüklemeye on saniye eklenecektir. İşiniz bittiğinde zaman aşımı değerini tekrar 0 olarak ayarlayın.
Bootloader'ı düzenlemekten daha güvenli seçenekler
Yalnızca SSH üzerinden erişebildiğiniz bir makinede bootloader girdisini değiştirmek, bu sayfadaki en riskli seçenektir. Daha düşük maliyetli çözümler mevcuttur ve bunlar genellikle asıl sorunu çözer.
Kernel paketlerini sabitleyin. Amaç "bana daha yeni bir kernel verme" ise, bunu bootloader yerine paket yöneticisine bildirin.
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İlk komutun çıktısında yer alan isimleri kullanın; çünkü bulut imajları genellikle generic yerine virtual veya kvm sürümünü kurar. Sabitlenmiş (held) bir paket apt upgrade tarafından atlanır, bu durum The following packages have been kept back: ile bildirilir ve aynı zamanda Ubuntu üzerinde unattended upgrades tarafından da dikkate alınmaz. Bunun bir bedeli vardır: sabitlenmiş bir kernel güvenlik güncellemelerini almayı durdurur; bu nedenle bu işlemi süreli bir duraklatma olarak değerlendirin ve sudo apt-mark unhold ile sabitlemeyi kaldırın. Kernel güncellemelerinden kaçınma nedeniniz bir kernelin hatalı olması değil de yeniden başlatmaların kesinti yaratması ise, VPS üzerinde canlı kernel yamalama bu sorunu çözer.
Yükseltme öncesi snapshot alın. Bir snapshot dakikalar içinde geri yükleme sağlar; konsoldan yazma gerektirmez ve yarım kalmış bir bootloader değişikliği riski taşımaz. Snapshot alın, yükseltin, yeniden başlatın ve doğrulayın. Yeni kernel hatalı çalışırsa geri alın; böylece boot yolu tam olarak önceki haline döner.
Zaten kapalı olan bir sunucu için konsolu veya kurtarma imajını kullanın. Sunucu boot etmediğinde, bootloader yapılandırması sorunu gidereceğiniz yer değildir. Bu kurtarma süreci kendi prosedürüne sahiptir: kernel güncellemesi sonrası VPS boot etmediğinde ne yapılmalı.
Neler bozulur ve karşılaşacağınız mesajlar
/boot/grub/grub.cfg üzerindeki düzenlemeniz kayboldu. Bir çekirdek paketi kuruldu veya kaldırıldı, paket yöneticisi betiği update-grub komutunu çalıştırdı ve dosya girdilerden yeniden oluşturuldu. # DO NOT EDIT THIS FILE başlığı, iki girdi konumunu belirtir. Düzenlemeleri bu konumlarda yapın.
grub-editenv: error: environment block too small. /boot/grub/grubenv eksik veya kesilmiş. sudo grub-editenv /boot/grub/grubenv create ile dosyayı yeniden oluşturun, ardından değerinizi tekrar ayarlayın ve sudo grub-editenv list ile doğrulayın.
Sabitlenmiş bir çekirdek VFS: Unable to mount root fs on unknown-block(0,0) ile kernel panic veriyor. Sabitlediğiniz girdi, artık diskte bulunmayan bir çekirdeğe veya initrd dosyasına işaret ediyor; bu durum genellikle paket kaldırıldığı halde tanımlayıcının grubenv içinde kalmasından kaynaklanır. Kurtarma işlemi, çalışan bir girdi ile konsoldan önyükleme yapmayı ve ardından geçersiz değeri temizlemeyi gerektirir.
Beklediğiniz yeniden başlatma sonrasında uname -r değişmedi. Sırasıyla şu üç noktayı kontrol edin: grub-editenv list hala değerinizi gösteriyor mu yoksa değer tüketildi mi; ayarladığınız tanımlayıcı mevcut grub.cfg içinde görünüyor mu; grub.cfg, ayarladığınız değişkeni okuyan bir set default satırı içeriyor mu. Bu üç noktadan biri durumu her zaman açıklar.
Bir çökme sonrasında menü kendiliğinden belirdi. GRUB, başarısız bir önyüklemeyi grubenv içinde recordfail=1 olarak kaydeder ve bu durum, bir kullanıcının müdahale edebilmesi için sonraki önyüklemede menüyü zorunlu kılar. Makine sağlıklı duruma geldiğinde sudo grub-editenv /boot/grub/grubenv unset recordfail ile bu kaydı temizleyin.
Akılda tutulması gereken tek cümle: düzenlediğiniz dosya GRUB'un okuduğu dosya değildir ve bulut imajlarında bu ikisi arasındaki fark kafa karışıklığının kaynağıdır. Önce oluşturulan yapılandırmayı okuyun. Bu sayfadaki her karar, dosyanın gerçekte ne söylediğine dayanır.
FAQ
Neden GRUB_DEFAULT=1 ayarı VPS'imin hangi çekirdek ile açılacağını değiştirmiyor?
Çünkü bir Ubuntu bulut imajında oluşturulan /boot/grub/grub.cfg genellikle tek bir önyükleme girdisi barındırır; bu nedenle 1 indeksi hiçbir yeri işaret etmez ve GRUB ilk girdiye geri döner. Bunu sudo grep -cE '^\s*(menuentry|submenu) ' /boot/grub/grub.cfg ile doğrulayabilirsiniz. 1 sayısı, listenin tek elemanlı olduğunu gösterir. Bunun nedeni, imaj sağlayıcısı tarafından /etc/default/grub.d/ altındaki bir dosyada ayarlanan GRUB_FORCE_PARTUUID parametresidir; bu parametre, yüklü çekirdeklerin tam listesini oluşturmak yerine oluşturucuyu doğrudan önyükleme yoluna sokar. İlgili dosyayı grep -rn GRUB_FORCE_PARTUUID /etc/default/grub /etc/default/grub.d/ ile bulabilirsiniz.
Bir önceki çekirdeği sadece bir kez nasıl önyükleyebilirim?
Kendi grub.cfg dosyanızdan kopyaladığınız bir tanımlayıcı ile sudo grub-reboot '<identifier>' komutunu çalıştırın, ardından sağlayıcı konsolu zaten açıkken yeniden başlatın. GRUB, önyükleme yapmadan önce next_entry değerini temizler; bu nedenle seçim tam olarak bir deneme için geçerlidir ve hata veren (panic) bir çekirdek tekrar denenmez. Değerin yerleştiğini sudo grub-editenv list ile doğrulayın. Buna güvenmeden önce sudo grep -n next_entry /boot/grub/grub.cfg komutunu çalıştırın, çünkü yapılandırması grubenv dosyasını yüklemeyen bir imaj, komutu hiçbir hata vermeden yok sayacaktır.
Girdi numarasıyla mı yoksa tanımlayıcıyla mı sabitlemeliyim?
Tanımlayıcıyla sabitlemelisiniz. Girdi numaraları, 10_linux tarafından en yeni çekirdek en üstte olacak şekilde yeniden oluşturulan bir listedeki konumlardır; bu nedenle herhangi bir çekirdeği yüklemek veya kaldırmak numaraları kaydırır. Eski bir 1>2 değeri ise sizi uyarmadan, gerçek ancak yanlış bir girdiye yönlendirebilir. Tanımlayıcılar çekirdek sürümünü içerir, bu yüzden ya hedeflediğiniz çekirdekle eşleşirler ya da çözümlenemezler. Bunları sudo grep -n menuentry_id_option /boot/grub/grub.cfg ile listeleyin ve her girdi satırında tırnak içinde yer alan dizgiyi kopyalayın.
Çekirdek paketini tutmak (hold), önyükleyiciyi değiştirmekten daha mı güvenlidir?
Genel amaç için evet. sudo apt-mark hold linux-image-virtual linux-headers-virtual, daha yeni bir çekirdeğin gelmesini tamamen engeller; böylece önyükleme yolu asla değişmez ve konsol erişiminizin olmayabileceği bir durumda yanlış yapılandırma riski oluşmaz. Öncelikle kendi sisteminizde yüklü olan sürümleri apt list --installed ile kontrol edin ve tutma işlemini apt-mark showhold ile doğrulayın. Bunun dezavantajı, tutulan bir çekirdeğin güvenlik güncellemelerini almamasıdır; bu nedenle tutma işlemini uygulamadan önce sudo apt-mark unhold komutunu ne zaman çalıştıracağınıza karar verin.