Debian’da Servis Yönetimi: systemd ve SysVinit Rehberi

Debian sunucularında servis yönetimi, bir sistem yöneticisinin günlük hayatının tam ortasında yer alır. Web sunucunuz çöktü mü? Veritabanı servisi yanıt vermiyor mu? Yeni kurduğunuz uygulama her yeniden başlatmada kendiliğinden çalışmıyor mu? Tüm bu sorunların çözümü, servis yönetimini iyi anlamaktan geçiyor. Debian’da bu işi yaparken karşınıza iki farklı init sistemi çıkıyor: modern sistemlerde systemd, eski veya minimalist kurulumlarda ise SysVinit. Her ikisini de bilmek, özellikle karma ortamlarda çalışıyorsanız hayat kurtarıcı olabiliyor.

systemd Nedir ve Neden Önemli?

systemd, 2011 yılında Fedora ile hayatımıza girdi ve ardından Debian Jessie (8.0) sürümüyle birlikte Debian’ın varsayılan init sistemi haline geldi. Sadece bir init sistemi değil; servis yönetimi, günlük kaydı (journald), ağ yapılandırması ve daha pek çok şeyi tek çatı altında toplayan bir sistem ve servis yöneticisi.

Eski okul sysadmin’ler “her şeyi tek bir araçla yapmak Unix felsefesine aykırı” diye itiraz edebilir ve bu tartışma hâlâ canlı. Ama pratikte systemd, özellikle bağımlılık yönetimi ve paralel servis başlatma konularında SysVinit’e kıyasla gerçek avantajlar sunuyor. Sunucunuzun boot süresinin yarıya düşmesi küçük bir şey değil.

systemctl: Günlük Kullanımın Temeli

systemd ortamında işinizin %90’ını systemctl komutuyla halledeceksiniz. Temel kullanımı şöyle:

# Servis durumunu kontrol etmek
sudo systemctl status nginx

# Servisi başlatmak
sudo systemctl start nginx

# Servisi durdurmak
sudo systemctl stop nginx

# Servisi yeniden başlatmak
sudo systemctl restart nginx

# Konfigürasyonu yeniden yüklemek (servisi durdurmadan)
sudo systemctl reload nginx

# Servisin sistem açılışında otomatik başlamasını sağlamak
sudo systemctl enable nginx

# Otomatik başlamayı devre dışı bırakmak
sudo systemctl disable nginx

Burada dikkat edilmesi gereken önemli bir nokta: start ve enable farklı şeyler yapıyor. start sadece şu an için servisi çalıştırır, sunucu yeniden başladığında servis otomatik çalışmaz. enable ise boot sırasında otomatik başlaması için symlink oluşturur ama hemen başlatmaz. İkisini birlikte kullanmak istiyorsanız:

sudo systemctl enable --now nginx

Bu tek komut hem enable yapar hem de hemen başlatır. Pratik bir kısayol.

Servis Durumu Okumayı Öğrenmek

systemctl status çıktısını doğru okumak, sorun giderme sürecini dramatik biçimde hızlandırır:

sudo systemctl status postgresql

Bu komutun çıktısında şunlara bakıyoruz:

  • Active: active (running): Servis çalışıyor, mutlu.
  • Active: failed: Bir şeyler ters gitti, hemen araştır.
  • Active: inactive (dead): Servis çalışmıyor, normal veya beklenen bir durum olabilir.
  • Loaded: loaded (/lib/systemd/system/postgresql.service; enabled): Servis dosyası yüklenmiş ve boot’ta etkin.

Son birkaç log satırı da bu çıktıda görünüyor. Sorun varsa genellikle buradan ilk ipucunu alırsınız.

journald ile Log Yönetimi

systemd’nin güçlü yanlarından biri de entegre log sistemi olan journald. /var/log/ altında dağınık dosyalar aramak yerine tek bir araçla tüm sistem loglarına ulaşabilirsiniz:

# Belirli bir servisin tüm loglarını görmek
sudo journalctl -u nginx

# Son 100 satırı görmek
sudo journalctl -u nginx -n 100

# Canlı log takibi (tail -f gibi)
sudo journalctl -u nginx -f

# Son 1 saatin logları
sudo journalctl -u nginx --since "1 hour ago"

# Belirli zaman aralığı
sudo journalctl -u postgresql --since "2024-01-15 10:00:00" --until "2024-01-15 11:00:00"

# Sadece hata seviyesindeki loglar
sudo journalctl -u nginx -p err

Gerçek hayatta bu komutları en çok şu senaryoda kullanıyorsunuz: Gece 2’de telefon geliyor, uygulama çökmüş. journalctl -u uygulama-adi -n 200 ile son 200 satırı bakıp “OOMKiller tarafından öldürülmüş, RAM dolmuş” diyip sorunu tespit ediyorsunuz. Eski yöntemle /var/log/ altında hangi dosyaya bakacağınızı bulmaya çalışmak yerine…

Kendi systemd Servis Dosyanızı Yazmak

Özel bir uygulama çalıştırıyorsanız, onu systemd servisi haline getirmeniz gerekiyor. Örneğin, Python ile yazdığınız bir Flask API’si var ve bunu sistem servisi olarak yönetmek istiyorsunuz.

Servis dosyaları /etc/systemd/system/ altında .service uzantısıyla oluşturulur:

sudo nano /etc/systemd/system/flask-api.service
[Unit]
Description=Flask API Servisi
After=network.target postgresql.service
Requires=postgresql.service

[Service]
Type=simple
User=appuser
Group=appuser
WorkingDirectory=/opt/flask-api
Environment="FLASK_ENV=production"
Environment="DATABASE_URL=postgresql://localhost/mydb"
ExecStart=/opt/flask-api/venv/bin/python app.py
ExecReload=/bin/kill -HUP $MAINPID
Restart=on-failure
RestartSec=5
StandardOutput=journal
StandardError=journal

[Install]
WantedBy=multi-user.target

Dosyayı kaydettikten sonra systemd’ye yeni servisi tanıtmanız gerekiyor:

sudo systemctl daemon-reload
sudo systemctl enable --now flask-api
sudo systemctl status flask-api

Servis dosyasındaki önemli direktifler şunlar:

  • After: Hangi servislerden sonra başlayacağını belirtir, bağımlılık sırası.
  • Requires: Bu servis olmadan başlamayacak, sert bağımlılık.
  • Wants: Bu servis olsa iyi olur ama olmasa da çalışır, yumuşak bağımlılık.
  • Restart=on-failure: Servis beklenmedik şekilde kapanırsa otomatik yeniden başlat.
  • RestartSec: Yeniden başlatmadan önce beklenecek süre.
  • WantedBy=multi-user.target: Normal çok kullanıcılı sistem modunda çalışsın.

systemd Timer: Cron’un Modern Alternatifi

Çoğu sysadmin hâlâ cron kullanıyor ve bu tamamen geçerli. Ama systemd timer’ları, özellikle bağımlılık yönetimi ve log entegrasyonu açısından bazı avantajlar sunuyor.

Örneğin, her gece veritabanı yedeği alan bir timer oluşturalım:

# Önce servis dosyasını oluştur
sudo nano /etc/systemd/system/db-backup.service
[Unit]
Description=Veritabanı Yedekleme Servisi

[Service]
Type=oneshot
User=backup
ExecStart=/usr/local/bin/backup-db.sh
StandardOutput=journal
StandardError=journal
# Sonra timer dosyasını oluştur
sudo nano /etc/systemd/system/db-backup.timer
[Unit]
Description=Gece Veritabanı Yedekleme Timer

[Timer]
OnCalendar=*-*-* 02:30:00
Persistent=true

[Install]
WantedBy=timers.target
sudo systemctl daemon-reload
sudo systemctl enable --now db-backup.timer

# Timer durumunu kontrol et
sudo systemctl list-timers

Persistent=true çok önemli bir özellik: Eğer sunucu o saatte kapalıysa, açıldığında timer’ın çalışmamış olduğunu fark edip hemen çalıştırır. Cron’da bu özelliği elde etmek için anacron kurmanız gerekirdi.

SysVinit: Eski Dostumuz

Debian’ın eski sürümlerinde veya bazı gömülü/minimal sistemlerde SysVinit ile karşılaşabilirsiniz. systemd’nin sunmadığı bazı senaryolarda veya çok kısıtlı kaynaklara sahip sistemlerde SysVinit hâlâ kullanılıyor.

SysVinit’te servisler /etc/init.d/ altındaki script’lerle yönetilir:

# Servis başlatmak
sudo /etc/init.d/apache2 start

# veya service komutuyla
sudo service apache2 start
sudo service apache2 stop
sudo service apache2 restart
sudo service apache2 status

# Runlevel sorgulamak
runlevel

# Servisi belirli runlevel'lara eklemek
sudo update-rc.d apache2 defaults

# Servisi devre dışı bırakmak
sudo update-rc.d apache2 disable

SysVinit’te runlevel kavramı merkezi önem taşır:

  • 0: Sistem kapatma
  • 1: Single user mode, bakım modu
  • 2: Multi-user, networking ile (Debian’ın varsayılanı)
  • 3: Multi-user with networking (bazı dağıtımlarda)
  • 5: Grafik arayüz ile (bazı dağıtımlarda)
  • 6: Yeniden başlatma

Debian özelinde 2, 3, 4 ve 5 genellikle aynı davranışı gösterir, bu da kafa karışıklığı yaratabilir. systemd ise bu kavramı “target” ile değiştirdi: multi-user.target, graphical.target gibi.

SysVinit Script Yapısı

Eski sistemlerde kendi init script’inizi yazmanız gerekebilir. Temel yapı şöyle:

#!/bin/bash
### BEGIN INIT INFO
# Provides:          myapp
# Required-Start:    $network $remote_fs
# Required-Stop:     $network $remote_fs
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: My Custom Application
### END INIT INFO

APP_NAME="myapp"
APP_PATH="/opt/myapp/myapp"
PID_FILE="/var/run/myapp.pid"

case "$1" in
    start)
        echo "Starting $APP_NAME..."
        start-stop-daemon --start --pidfile $PID_FILE 
            --make-pidfile --background 
            --exec $APP_PATH
        ;;
    stop)
        echo "Stopping $APP_NAME..."
        start-stop-daemon --stop --pidfile $PID_FILE
        ;;
    restart)
        $0 stop
        sleep 2
        $0 start
        ;;
    status)
        if [ -f "$PID_FILE" ]; then
            PID=$(cat $PID_FILE)
            if kill -0 $PID 2>/dev/null; then
                echo "$APP_NAME is running (PID: $PID)"
            else
                echo "$APP_NAME is not running (stale PID file)"
            fi
        else
            echo "$APP_NAME is not running"
        fi
        ;;
    *)
        echo "Usage: $0 {start|stop|restart|status}"
        exit 1
        ;;
esac
sudo chmod +x /etc/init.d/myapp
sudo update-rc.d myapp defaults
sudo service myapp start

Bu yapı biraz verbose ve hata yapmaya müsait, bu yüzden modern sistemlerde systemd unit dosyaları çok daha temiz bir çözüm sunuyor.

Hybrid Ortamlar: systemd Üzerinden SysVinit Scriptleri

Debian’da güzel bir uyumluluk katmanı var: systemd, /etc/init.d/ altındaki eski SysVinit script’lerini otomatik olarak tanıyıp yönetebiliyor. Bu sayede service komutu hem eski hem yeni sistemlerde çalışıyor.

# Bu komut hem SysVinit hem systemd sistemlerde çalışır
sudo service nginx status

# systemd varsa yukarıdaki komut aslında şunu çalıştırır
sudo systemctl status nginx

Eski bir uygulama hâlâ /etc/init.d/ script’iyle kuruluyorsa endişelenmenize gerek yok; systemd onu otomatik wrap eder. Ama uzun vadede o servisi native systemd unit dosyasıyla yönetmek daha iyi bir pratik.

Gerçek Dünya Senaryo: Nginx Çöktü, Ne Yapıyoruz?

Saat 14:30, monitoring sisteminden alert geldi: website erişilemez. SSH ile bağlanıp hızlıca durumu değerlendiriyoruz:

# İlk kontrol
sudo systemctl status nginx

# Çıktı: Active: failed (Result: exit-code)
# Son log satırları görünüyor ama yeterli değil, daha fazlasına bakalım

sudo journalctl -u nginx -n 50 --no-pager

# Log'da görüyoruz: "address already in use"
# Demek ki 80 portunu başka bir şey kullanıyor

sudo ss -tlnp | grep :80

# Eski bir nginx process'i hâlâ ayakta!
# PID'i öldürüp tekrar başlatıyoruz

sudo kill -9 <PID>
sudo systemctl start nginx
sudo systemctl status nginx

# Active: active (running) - Çözüldü!

# Neden böyle oldu? Muhtemelen nginx düzgün kapanmadı
# Bunu önlemek için Restart policy ayarlayalım

Bu senaryo çok sık yaşanıyor. Monitoring + journalctl kombinasyonu ile 5 dakikada sorunu tespit edip çözdünüz. Eski yöntemle önce hangi log dosyasına bakacağınızı bulmak, sonra grep ile içinde gezmek derken belki 20 dakika harcardınız.

Performans: Boot Süresini Analiz Etmek

systemd’nin güzel özelliklerinden biri boot performansını analiz edebilmek:

# Toplam boot süresini görmek
systemd-analyze

# Her servisin boot süresine katkısını görmek
systemd-analyze blame

# Boot sürecini grafiksel olarak SVG'ye aktarmak
systemd-analyze plot > boot-timeline.svg

# Kritik yol analizi
systemd-analyze critical-chain

systemd-analyze blame çıktısında en uzun süren servisler listelenir. 30 saniye süren bir servis görürseniz ve o servisin gerçekten önemli olmadığını düşünüyorsanız, disable edip boot sürenizi ciddi ölçüde kısaltabilirsiniz. Production sunucularda bu analizi yapmak, özellikle auto-scaling ortamlarında instance başlatma sürelerini optimize etmek için değerli.

Servis Güvenliği: Sandboxing

systemd, servis güvenliğini artırmak için güçlü sandboxing özellikleri sunuyor. Kritik servislerin ne kadar ayrıcalığa sahip olduğunu sınırlayabilirsiniz:

[Service]
# Root olmayan kullanıcıyla çalış
User=www-data
Group=www-data

# Dosya sistemi erişimini kısıtla
ProtectSystem=strict
ProtectHome=true
ReadWritePaths=/var/www/html /var/log/myapp

# Ağ erişimini kısıtla (sadece belirli protokoller)
RestrictAddressFamilies=AF_INET AF_INET6

# Gereksiz yetenekleri kaldır
CapabilityBoundingSet=CAP_NET_BIND_SERVICE
NoNewPrivileges=true

# /tmp'yi izole et
PrivateTmp=true

Bu özellikler, bir güvenlik açığından yararlanılsa bile saldırganın sistem üzerindeki hasar alanını sınırlar. Production’da özellikle internet’e açık servisler için bu direktifleri değerlendirmenizi tavsiye ederim.

Sık Yapılan Hatalar ve Çözümleri

daemon-reload yapmayı unutmak: Servis dosyasını değiştirip restart yaptığınızda değişiklikler geçmez, çünkü systemd eski yapılandırmayı bellekte tutuyor. Her .service dosyası değişikliğinden sonra sudo systemctl daemon-reload şart.

enable ile start karışıklığı: Yukarıda bahsettim ama tekrar vurgulamak gerekiyor. Sunucu reboot’tan sonra “neden servisim çalışmıyor?” sorusunun cevabı genellikle enable yapmamak.

SysVinit scriptini systemd ile karıştırmak: Hybrid sistemde /etc/init.d/ script’ini düzenlediğinizde sudo systemctl daemon-reload yapmanız gerekiyor ki systemd yeni versiyonu tanısın.

Yanlış target: Servisi WantedBy=graphical.target ile kurduğunuzda ve sunucu headless boot yapıyorsa servis çalışmaz. Server’lar için multi-user.target doğru seçim.

Pratik Referans: Günlük Kullanım Komutları

Servis yönetiminde en sık kullandığım komutları derleyeyim:

# Tüm çalışan servisleri listele
sudo systemctl list-units --type=service --state=running

# Başarısız servisleri listele
sudo systemctl --failed

# Bir servisin bağımlılıklarını göster
sudo systemctl list-dependencies nginx

# Bir servisin nerede tanımlandığını bul
sudo systemctl cat nginx

# Servis dosyasını düzenle (daemon-reload otomatik yapılır)
sudo systemctl edit --full nginx

# Override ekle (orijinal dosyayı değiştirmeden)
sudo systemctl edit nginx

# Tüm timer'ları listele
sudo systemctl list-timers --all

systemctl edit komutu özellikle önemli. Paket güncellemesi geldiğinde orijinal servis dosyası overwrite edilir ama edit ile oluşturduğunuz override (/etc/systemd/system/nginx.service.d/override.conf) kalır. Production’da upstream servis dosyalarını doğrudan değiştirmek yerine override kullanmak çok daha sağlıklı bir pratik.

Sonuç

Debian’da servis yönetimi, systemd ile birlikte ciddi bir güç kazandı. journald entegrasyonu, otomatik restart, sandboxing, timer sistemi ve dependency yönetimi gibi özellikler, günlük operasyonel yükü gerçekten azaltıyor. SysVinit’i bilmek ise hâlâ değerli; eski sistemlere müdahale etmek durumunda kalabilirsiniz ve bazı kavramları anlamak için tarihsel bağlamı bilmek yardımcı oluyor.

Pratikte tavsiyem şu: Yeni kurduğunuz her servisi düzgün bir systemd unit dosyasıyla yönetin, sandboxing direktiflerini ihmal etmeyin ve monitoring sistemlerinizi journald ile entegre edin. Bir şeyler ters gittiğinde “neye bakacağım?” sorusunun cevabını önceden bilmek, gece yarısı kriz anlarında saatler kurtarıyor.

systemd hakkında tartışmalar devam ediyor ve edecek. Ama bir sistem yöneticisi olarak araçları tartışmak yerine iyi kullanmayı öğrenmek daha verimli. systemd’yi iyi öğrendiğinizde elinizdeki gücü fark edeceksiniz.

Yorum yapın