İçeriğe geç

Systemd Nedir ve Service Nasıl Oluşturulur?

Güncellendi: saat 08:30Düzeltme öner

Systemd, Linux sistemlerinde servisleri ve diğer sistem kaynaklarını “unit” adı verilen tanımlarla yöneten init ve servis yöneticisidir. Bir uygulamayı .service unit’i olarak tanımladığınızda systemd uygulamayı başlatabilir, durumunu izleyebilir, başarısız olduğunda yeniden çalıştırabilir ve günlüklerini journal üzerinden sunabilir.

Systemd kullanan yaygın dağıtımlarda sistem yöneticisi PID 1 olarak çalışır. Servis yönetimi bunun yalnızca bir bölümüdür; unit türleri arasında şunlar bulunur:

Bu rehberde /home/my-app altında bir Python uygulamasını my-app.service adıyla çalıştıracağız.

Unit dosyasındaki bölümler

Bir servis unit’i genellikle [Unit], [Service] ve [Install] bölümlerinden oluşur. Direktiflerin hangi bölüme ait olduğu önemlidir.

[Unit]

systemd.unit kılavuzunda tanımlanan genel unit ilişkileri burada yer alır:

Önemli ayrım şudur: bağımlılık ve sıralama birbirinden ayrıdır. After=postgresql.service, PostgreSQL’i işlem kapsamına eklemez; yalnızca iki unit de başlatılacaksa bu servisin PostgreSQL’den sonra başlamasını söyler. PostgreSQL’in de etkinleştirilmesi gerekiyorsa Wants= veya gerçekten zorunluysa Requires= ilişkisi ayrıca yazılır.

Benzer biçimde Before=test.service, mevcut unit’in test.service’den önce çalışmasını ister; test.service’i önce başlatmak anlamına gelmez.

[Service]

Servise özgü çalışma ayarları systemd.service kılavuzunda tanımlanır:

User=, Group= ve ExecStart= genel [Unit] ayarları değildir; [Service] bölümüne yazılmalıdır.

[Install]

Bu bölüm, systemctl enable çalıştırıldığında unit’in hangi hedefe bağlanacağını belirtir. Uzun süre çalışan sistem servisleri için sıklıkla WantedBy=multi-user.target kullanılır.

Çalışan bir service örneği

Aşağıdaki unit, sanal ortam içindeki Python yorumlayıcısını doğrudan çalıştırır:

[Unit]
Description=My application service
Documentation=https://www.aliyilmaz.co/
Wants=network-online.target
After=network-online.target

[Service]
Type=exec
User=my-app
Group=my-app
WorkingDirectory=/home/my-app
ExecStart=/home/my-app/venv/bin/python -u /home/my-app/app.py
EnvironmentFile=/etc/my-app.env
Restart=on-failure
RestartSec=5s
TimeoutStopSec=30s

[Install]
WantedBy=multi-user.target

Bu örnek için my-app kullanıcısı, dizinler, sanal ortam ve /etc/my-app.env dosyası önceden oluşturulmuş olmalıdır. Uygulamanın ağ tamamen hazır olmadan da başlayabilmesi durumunda network-online.target ilişkisine ihtiyacınız olmayabilir; gereksiz bağımlılıkları eklemeyin.

Type=exec, uzun çalışan basit servislerde systemd’nin kullanıcı veya yürütülebilir dosya gibi başlangıç hatalarını çağırana yansıtmasını sağlar. Kullanılan systemd sürümünde veya uygulamanın çalışma modelinde farklı bir Type= gerekebilir; özellikle fork eden daemon’lar ve hazır olma bildirimi yapan servisler için ilgili kılavuzu izleyin.

Systemd varsayılan durdurma davranışında ana sürece SIGTERM gönderip tanımlı süreyi bekleyebildiği için bu örnekte yapay bir ExecStop=/bin/kill ... satırına gerek yoktur. Ayrıca varsayılan cgroup davranışını KillMode=process ile daraltmak çocuk süreçleri geride bırakabileceğinden genel bir şablon olarak kullanılmamalıdır.

Unit dosyasını güvenli biçimde oluşturma

Sabit ve açık bir dosya adıyla düzenleyiciyi açın:

sudoedit /etc/systemd/system/my-app.service

Unit içeriğini kaydettikten sonra sözdizimini kontrol edebilirsiniz:

sudo systemd-analyze verify /etc/systemd/system/my-app.service

Ardından systemd yöneticisinin dosyaları yeniden okumasını sağlayın ve servisi hem açılışa ekleyip hem de hemen başlatın:

sudo systemctl daemon-reload
sudo systemctl enable --now my-app.service

enable tek başına servisi hemen başlatmaz; yalnızca bir sonraki uygun açılış/target işlemi için bağlantıları oluşturur. systemctl üzerindeki --now seçeneği enable işlemiyle birlikte başlatmayı da ister.

Durum ve günlükleri inceleme

Servisin güncel durumunu görüntüleyin:

systemctl status my-app.service

Son 100 journal kaydını alın:

journalctl -u my-app.service -n 100 --no-pager

Yeni kayıtları canlı izlemek için:

journalctl -u my-app.service -f

journalctl filtresindeki -u, seçilen unit ve systemd tarafından o unit ile ilişkilendirilen iletileri gösterir. Yetki yapılandırmasına göre sistem günlüğünü okumak için sudo gerekebilir.

Unit dosyasını daha sonra değiştirirseniz yeni tanımı yüklemek ve çalışan servise uygulamak için:

sudo systemctl daemon-reload
sudo systemctl restart my-app.service

Önce systemctl status, ardından journalctl -u çıktısını kontrol ederek yeni sürecin sağlıklı başladığını doğrulayın.

Wrapper script ne zaman gerekir?

Uygulamayı ExecStart= ile doğrudan çalıştırmak genellikle daha iyidir. Böylece systemd gerçek uygulama sürecini ana PID olarak takip eder; çıkış kodu ve sinyal davranışı araya gereksiz bir shell girmeden görünür.

Başlangıç öncesinde shell’e özgü hazırlık adımları gerçekten gerekiyorsa bir wrapper script kullanılabilir. Script’in son komutunda exec kullanmak, shell sürecini uygulamayla değiştirerek sinyallerin ve çıkış kodunun doğru sürece ulaşmasını kolaylaştırır:

#!/usr/bin/env bash
set -euo pipefail

# Yalnızca uygulamaya özgü zorunlu hazırlık adımları burada yapılır.
exec /home/my-app/venv/bin/python -u /home/my-app/app.py

Sanal ortamı source ile etkinleştirmek zorunlu değildir; sanal ortamın Python yürütülebilir dosyasını doğrudan çağırmak daha sade ve tekrarlanabilir bir unit üretir. Uygulama standart çıktıya ve standart hataya yazdığında systemd bunları varsayılan olarak journal’a aktarabilir.

Birincil kaynaklar


Önceki Yazı
MySQL ONLY_FULL_GROUP_BY Hatası: Hızlı Çözüm
Sonraki Yazı
Text-to-Speech (TTS): Metni Sese Dönüştürme Sanatı