Linux'ta Servisleri Anlamak: systemd, Daemon ve Loglar
Bir servis çalışmadığında çoğu kişideki refleks aynıdır: systemctl restart <servis adı>
Servis yeniden ayağa kalkarsa sorun çözülmüş gibi hissedilir. Sistem tekrardan işlevseldir, kullanıcı şikayet etmiyordur ve her şey normale dönmüş gibidir ama çoğu zaman kökte farklı sebepler yatar. Servisin restartı sorunu çözmez, sadece erteler.
Restart yaklaşımı kısa vadede işe yarar gibi görünse de uzun vadede sistemin davranışını anlamayı, sistemi yakından tanımayı zorlaştırır. Her restart aslında bize bir şey anlatmaya çalışan bir durumu susturur. Servisin neden durduğu, aynı şeyin tekrar olup olmayacağı gibi sorular cevapsız kalır. Oysa ki ortada bir konfigürasyon hatası, dependency ile alakalı bir sorun gibi durumlar olabilir. Bu durumu analiz edip anlayabilmek için ilk refleksin restart değil, anlamaya çalışmak olması gerekir.
Bu yazıda odak noktamız komutlar değil refleksler olacak. systemctl ne yapar, journalctl bize ne söyler ve en önemlisi bir sistem gerçekten nasıl okunur gibi konuları ele alacağız.
Servis dediğimiz şey aslında nedir?
"Servis" kelimesi Linux'ta çok sık kullanılır ama çoğu zaman neyi ifade ettiği düşünülmez. Çoğu kişi için servis, systemctl status <servis adı> çıktısında görülen bir isimden ibarettir. Çalışıyorsa "up", çalışmıyorsa "down"...
Linux seviyesinde "servis" denen özel bir varlık yoktur. Kernel aslında servis diye bir şey bilmez. Kernel'ın bildiği şey process'tir. Bir servisi servis yapan şey onun nasıl başlatıldığı veya isminin ne olduğu değildir. Asıl mesele o yapının sistem tarafından nasıl yönetildiğidir. Yani aslında servis dediğimiz şey, systemd tarafından başlatılan ve belirli bir görevi yerine getirmesi beklenen process veya process'lerdir.
Tabii burada da önemli bir ayrım vardır. Her process bir servis değildir. Terminalde çalıştırdığımız herhangi bir komut da bir process'tir ama servis olarak değerlendirilmez. O process, process'i başlatan kullanıcının oturumuna bağlıdır. İşi bittiğinde kapanır ve sistem tarafından sürekli ayakta tutulmaz.
Servis dediğimiz yapı ise farklıdır. Arka planda çalışır, kullanıcıdan bağımsızdır. Yani bir süreklilik beklentisi vardır. Bu noktayı daha somut görmek için nginx üzerinden gidelim.
Nginx'i başlattığımızda aslında tek bir process çalışmaz. Bir ana süreç başlar ve bu süreç, istekleri karşılamak için birden fazla alt süreç oluşturur. Yani arka planda birden fazla process birlikte çalışır ama systemd bu detaylar ile ilgilenmez. systemd'nin derdi nginx'in kaç process ayaklandırdığı değildir. Onun için önemli olan şey nginx'i başlatan komutun verilmesi ve bu yapının genel olarak ayakta kalmasıdır. Bu yüzden systemctl status nginx.service çıktısında gördüğümüz şey tüm bu yapının tek bir servis olarak özetlenmiş halidir. Uzun lafın kısası systemd, nginx'in iç yapısını değil, sonucunu izler.
Daemon nedir ve hangi ihtiyacı giderir?
Linux'ta servislerden bahsederken sıkça geçen bir diğer kavram da daemon'dır. Çoğu zaman servis ve daemon kelimeleri birbirinin yerine kullanılır ama aslında aynı şeyi ifade etmezler.
systemd aslında "system daemon" ifadesinden gelir. Yani systemd'nin kendisi de bir daemon'dır. Sistem açıldığında çalışan ilk user-space process'tir (PID 1) ve diğer process'lerin nasıl çalışacağını yönetir. Bu bile tek başına aslında Linux'ta sistemi ayakta tutan şeylerin daemon'lar olduğunu anlatır.
Daemon dediğimiz şey aslında bir çalışma biçimidir. Bir process'in daemon olması onun arka planda çalıştığı, bir kullanıcı oturumuna bağlı olmadığı ve genellikle uzun ömürlü olduğu anlamına gelir. Bu ifade tek başına yetersiz kalır, biz örnek üzerinden gidelim.
SSH ile bir makineye bağlandığımızda aslında bağlandığımız şey bir servis değildir. Arka planda çalışan bir daemon vardır: sshd. Bu process sürekli ayaktadır ve gelen bağlantıları dinler. Biz bağlandığımızda yeni bir process oluşturur ve oturumu yönetir. Bağlantıyı kestiğimizde bu process sonlanır ama sshd çalışmaya devam eder. İşte bu davranışın kendisi daemon'dır.
Bir uygulamayı manuel olarak da başlatıp arka planda çalıştırabiliriz. Bu durumda o process bir daemon gibi davranır ama systemd tarafından yönetilmediği için bir servis olarak değerlendirilmez. Servis ve daemon arasındaki fark aslında oldukça basittir:
Daemon çalışan şeydir. Servis ise bu çalışan şeyin systemd tarafından tanımlanmış ve yönetilen halidir.
Bu ayrım özellikle troubleshooting sırasında önem kazanır. Çünkü systemd bize servis durumunu gösterir ama asıl işi yapan şey daemon process'leridir.
Bir problem olduğunda bazen servisi running görürüz ama daemon aslında beklenen işi yapmıyor olabilir. Ya da tam tersi, daemon crash olmuştur ve systemd bu durumu yönetmeye çalışıyordur. Bu yüzden servislere sadece bir isim olarak değil, arkasında çalışan daemon process'lerin bir temsili olarak bakmak gerekir. Bu bakış açısı oturduğunda sistemde olan biteni okumak çok daha kolay hale gelir.
systemctl bize ne anlatır?
Bir servisin durumunu kontrol etmek istediğimizde ilk yaptığımız şey bellidir: systemctl status <servis adı>
Bu komut bizlere servisin durumunu gösterir. Çalışıyor mu, durmuş mu, ne zamandan beri aktif... İlk bakışta ihtiyacımız olan her şey burada gibi görünür ama aslında systemctl bize sistemin tamamını değil, sadece systemd'nin gördüğü durumu gösterir. Bu önemli bir ayrımdır çünkü systemd bir gözlem aracı değildir. Bir yönetim katmanıdır. Yani systemctl çıktısında gördüğümüz şey sistemde gerçekten olan bitenin tamamı değil, systemd'nin bu durumu nasıl yorumladığıdır.
Örneğin bir servis "active (running)" görünüyor olabilir. Bu, systemd'nin o servisi başlatabildiği ve şu an için ayakta olduğunu düşündüğü anlamına gelir ama servisin gerçekten doğru çalıştığı anlamına gelmez.
Bir web servisi düşünelim. Process ayaktadır, port'a bind olmuştur ve systemd açısından her şey normaldir ama uygulama hata veriyor olabilir, request'lere cevap vermiyor olabilir ya da içeride bir dependency problemi vardır. İşte burada systemctl bize bunu söylemez, zaten görevi de bu değildir.
Aynı şekilde bir servis "failed" olarak da görünebilir. Bu durumda systemd, başlatmaya çalıştığı process'in beklenen şekilde çalışmadığını anlamıştır. systemctl status <servis adı> çıktısında çoğu zaman bu duruma ait birkaç log satırı da gösterilir ama bu genellikle yeterli değildir. Gösterilen şey logların tamamı değil, sadece son birkaç satırıdır.
systemctl bizlere ipucu verir, asıl cevabı vermez.
Bu sebeple ortada bir problem varken systemctl status <servis adı> çıktısını bir başlangıç olarak görmek gerekir. Servisin ayakta olup olmadığı, ne zamandan beri çalıştığı, exit status'u gibi sorulara cevabı burada buluruz.
Bu noktada çoğu kişinin yaptığı bir hata ise servisi failed gördüğünde systemctl restart <servis adı> komutunu verip servisi running gördüğünde sorunun çözüldüğünü sanmaktır. Halbuki çoğu zaman sadece belirtiler ortadan kalkmıştır. Asıl problem hâlâ oradadır.
İşte bu durumda yardımımıza loglar koşuyor. Yazının devamında journalctl'e değineceğiz.
journalctl ile sebebi görelim
Bir servisin çalışmadığını systemctl ile gördük. Peki bu servisin neden çalışmadığını nasıl troubleshoot edeceğiz? İşte burada bakmamız gereken yer loglardır. Linux'ta systemd kullanan bir sistemde bu logların merkez noktası journalctl'dir. systemctl bize sonucu gösterir ve ipucu verir, journalctl ise o sonuca nasıl gelindiğini anlatır.
Bir servis failed olduğunda aslında systemd bir şey söylemiştir ama yarım söylemiştir. "Başlatamadım" der ama neden başlatamadığını tam söylemez. O cevabı bulmak için loglara bakmak gerekir. Örneğin journalctl -u nginx komutu ile nginx servisine ait logları görebiliriz. Çoğu zaman da asıl problemi bu komutun çıktısında görürüz. Yanlış bir config, bind edilemeyen bir port, bulunamayan bir dosya veya permission hataları gibi şeyleri loglarda görebiliriz. systemctl bize bu detayları vermez ama journalctl verir.
Burada önemli olan şey sadece komutu bilmek değildir. Asıl mesele bir refleks geliştirmektir. Bir servis çalışmıyorsa systemctl ile ipucu alınır, journalctl ile sorun anlaşılır.
Aynı problemi yaşayan iki kişi düşünelim. Birisi servise restart atar ve yoluna devam eder. Diğeri ise logları okur ve sorunun neden olduğunu anlar. İşte bu kişi problemi anlık değil, kökünden çözmeye çabalar. Aynı problemin tekrar etmesini engeller. Bu yüzden troubleshooting dediğimiz şey sadece komut bilmek değil, sistemin bize ne anlatmaya çalıştığını anlayabilmektir. Bu anlatının en net olduğu yer loglardır.
Pratik kullanım: systemctl ve journalctl
Bu yazının odağı komut ezberlemek değil ama pratikte en sık kullanılan birkaç komutu bilmek işleri ciddi şekilde hızlandırır.
systemctl komutları
| Komut | Açıklama |
|---|---|
systemctl status <servis adı> |
Servisin mevcut durumunu ve son logları gösterir |
systemctl start <servis adı> |
Servisi başlatır |
systemctl stop <servis adı> |
Servisi durdurur |
systemctl restart <servis adı> |
Servisi yeniden başlatır |
systemctl reload <servis adı> |
Servisi kesintisiz şekilde yeniden yükler |
systemctl enable <servis adı> |
Servisi sistem açılışında otomatik başlatır |
systemctl disable <servis adı> |
Servisin sistem açılışında otomatik başlatılmasını kapatır |
journalctl komutları
| Komut | Açıklama |
|---|---|
journalctl -u <servis adı> |
Servise ait tüm logları gösterir |
journalctl -u <servis adı> -n 50 |
Son 50 log kaydını gösterir |
journalctl -u <servis adı> -f |
Logları canlı olarak gösterir |
journalctl -xe |
Logların sonuna gider ve mümkünse ek açıklamalarla birlikte gösterir |
journalctl --since "1 hour ago" |
Son 1 saate ait logları getirir |
journalctl -u <servis adı> --since today |
Bugünkü logları gösterir |
journalctl -u <servis adı> -p err |
Sadece error seviyesindeki logları gösterir |
Kullanılan bazı flag'ler şunlardır:
-u-> Belirli bir systemd unit'ini (servis) filtreler-n-> Son N log kaydını getirir-f-> Logları canlı getirir-p-> Log seviyesine göre filtreleme yapar (err, warning, info...)--since→ Zaman bazlı filtreleme yapar-e-> Çıktının sonuna gider-x-> Loglara mümkünse ek açıklamalar ekler
Linux'ta servis yönetimi çoğu zaman birkaç komutla sınırlıymış gibi anlatılır. Gerçek sistemlerde işler bu kadar basit değildir. Bir servis çalışmadığında asıl mesele o servisin neden çalışmadığını anlamaktır.
systemctl bize servisin durumunu gösterir. journalctl ise bu duruma nasıl gelindiğini anlatır.
Servis yönetmek, komut çalıştırmaktan ibaret değildir. Troubleshooting yapmak da komut ezberlemek değildir.
Asıl mesele sistemin bize ne söylediğini anlayabilmektir. Sistemi doğru yerden dinlemesini bilmek gerekir.