Systemd Unit Dosyaları ile Linux Servis Yönetiminde Uzmanlaşma

 · 

Systemd Unit Dosyaları ile Linux Servis Yönetiminde Uzmanlaşma

Systemd Unit Dosyaları ile Linux Servis Yönetiminde Uzmanlaşma

Linux sistemlerde süreçlerin ve servislerin yaşam döngüsünü tutarlı ve güvenilir bir şekilde yönetmek, operasyonel süreklilik için kritik öneme sahiptir. Systemd, modern Linux dağıtımlarında bu yönetimin temelini oluşturan, karmaşık bağımlılıkları, kaynak kısıtlamalarını ve güvenlik politikalarını deklaratif bir yaklaşımla tanımlamamızı sağlayan bir init sistemidir. Bu içerikte, Systemd unit dosyalarının derinliklerine inecek, servis oluşturma, yapılandırma ve yönetme süreçlerini gerçek dünya senaryolarıyla birlikte ele alacağız.

Systemd Unit Dosyasının Anatomisi

Bir Systemd unit dosyası, genellikle .service uzantısına sahip düz metin bir dosyadır ve servis hakkında tüm bilgileri içerir. Bu dosyalar /etc/systemd/system/ veya /usr/lib/systemd/system/ dizinlerinde bulunur ve üç ana bölümden oluşur: [Unit], [Service] ve [Install].

[Unit] Bölümü: Metadata ve Bağımlılıklar

Bu bölüm, servisin genel tanımını, bağımlılıklarını ve sıralama bilgilerini içerir. Servisin ne zaman başlaması veya durması gerektiğini, hangi diğer servis veya hedeflere (targets) bağlı olduğunu belirleriz.

  • Description: Servisin kısa açıklaması.
  • Documentation: Servisle ilgili dokümantasyon linkleri.
  • After: Bu servisin başlamadan önce hangi servislerin veya hedeflerin (targets) başlaması gerektiğini belirtir.
  • Before: Bu servisin başlamasından önce hangi servislerin veya hedeflerin başlaması gerektiğini belirtir.
  • Requires: Bu servisin çalışması için zorunlu olan diğer servisler. Eğer bağımlı servisler başlamazsa veya durursa, bu servis de durdurulur.
  • Wants: Requires kadar katı olmayan bir bağımlılık. Bağımlı servis başlamasa bile bu servis çalışmaya devam edebilir.
[Unit]Description=My Custom Web ApplicationAfter=network-online.targetWants=postgresql.serviceRequires=docker.serviceDocumentation=https://example.com/myapp

Yukarıdaki örnekte, servisimizin ağ bağlantısı kurulduktan sonra başlaması gerektiğini (After=network-online.target), PostgreSQL servisinin başlamasını istediğini (Wants=postgresql.service) ancak zorunlu koşmadığını ve Docker servisinin zorunlu olduğunu (Requires=docker.service) görüyoruz.

[Service] Bölümü: Servis Tanımı

Bu bölüm, servisin nasıl çalıştırılacağını, durdurulacağını ve genel davranışını tanımlar. Birçok farklı direktif içerir ve servisin türüne göre değişiklik gösterebilir.

  • Type: Servisin başlangıç türünü belirler (simple, forking, oneshot, dbus, notify, idle). Çoğu uygulama için simple veya forking kullanılır.
  • ExecStart: Servisi başlatan komut.
  • ExecStop: Servisi durduran komut (opsiyonel).
  • ExecReload: Servisi yeniden yükleyen komut (opsiyonel).
  • Restart: Servisin ne zaman yeniden başlatılacağını belirler (no, on-success, on-failure, on-abnormal, on-watchdog, on-abort, always).
  • RestartSec: Yeniden başlatmalar arasındaki bekleme süresi.
  • WorkingDirectory: Servis komutlarının çalıştırılacağı dizin.
  • User: Servisin hangi kullanıcı altında çalışacağını belirtir.
  • Group: Servisin hangi grup altında çalışacağını belirtir.
  • Environment: Servise özel ortam değişkenleri tanımlar.
  • EnvironmentFile: Ortam değişkenlerini bir dosyadan yükler.
[Service]Type=simpleExecStart=/usr/local/bin/mywebapp --port 8080WorkingDirectory=/opt/mywebappUser=webappGroup=webappRestart=on-failureRestartSec=5sEnvironment="PORT=8080" "ENV=production"

Bu bölümde, mywebapp isimli uygulamanın webapp kullanıcısı altında, /opt/mywebapp dizininde çalıştırıldığı, başarısızlık durumunda 5 saniye bekleyerek yeniden başlatılacağı ve bazı ortam değişkenlerinin tanımlandığı görülmektedir.

[Install] Bölümü: Servis Etkinleştirme

Bu bölüm, systemctl enable komutuyla servisi etkinleştirdiğinizde ne olacağını belirler. Genellikle hangi Systemd hedefinin (target) bu servisi başlatması gerektiğini tanımlar.

  • WantedBy: Bu servisin hangi hedefin (target) bir parçası olduğunu belirtir. Örneğin, multi-user.target, grafik arayüzü olmayan çok kullanıcılı sistemler için standart hedeftir.
  • Alias: Servis için alternatif isimler tanımlar.
[Install]WantedBy=multi-user.target

WantedBy=multi-user.target ifadesi, sistem çok kullanıcılı moda geçtiğinde bu servisin de otomatik olarak başlatılacağını ifade eder.

Örnek Senaryo: Basit Bir Python Uygulaması İçin Systemd Servisi

Bir sunucuda sürekli çalışması gereken basit bir Python Flask uygulamanız olduğunu varsayalım. Bu uygulama /opt/flask-app/app.py konumunda yer alıyor ve 5000 portunda çalışıyor. İşte bunun için bir Systemd unit dosyası nasıl oluşturulur:

Önce Python uygulaması (/opt/flask-app/app.py):

# /opt/flask-app/app.pyfrom flask import Flaskapp = Flask(__name__)@app.route('/')def hello():    return "Hello from Systemd-managed Flask app!"if __name__ == '__main__':    app.run(host='0.0.0.0', port=5000)

Şimdi /etc/systemd/system/flaskapp.service dosyamızı oluşturalım:

[Unit]Description=Flask Web ApplicationService for my projectAfter=network.target network-online.target[Service]User=flaskuserGroup=flaskuserWorkingDirectory=/opt/flask-app/ExecStart=/usr/bin/python3 app.pyRestart=on-failureRestartSec=10sStandardOutput=syslogStandardError=syslogSyslogIdentifier=flaskapp[Install]WantedBy=multi-user.target

Açıklamalar:

  • User=flaskuser ve Group=flaskuser: Uygulamanın flaskuser adında bir sistem kullanıcısı ve grubu altında çalışmasını sağlar. Bu, güvenlik için iyi bir pratiktir.
  • WorkingDirectory=/opt/flask-app/: Uygulamanın betiklerinin bulunduğu dizini belirtir.
  • ExecStart=/usr/bin/python3 app.py: Servis başlatıldığında Python betiğini çalıştırır. Tam yolu belirtmek önemlidir.
  • Restart=on-failure: Uygulama bir hata nedeniyle durursa, Systemd onu otomatik olarak yeniden başlatmaya çalışır.
  • RestartSec=10s: Yeniden başlatma denemeleri arasında 10 saniye bekler. Bu, hızlı döngülü hatalarda sistem kaynaklarının aşırı tüketilmesini engeller.
  • StandardOutput=syslog ve StandardError=syslog: Uygulamanın standart çıktı ve hata çıktılarını syslog'a yönlendirerek log yönetimi kolaylığı sağlar.
  • SyslogIdentifier=flaskapp: Loglarda bu servis için özel bir tanımlayıcı kullanır.

Servisi etkinleştirme ve yönetme:

sudo adduser --system --no-create-home flaskuser # Kullanıcı oluşturmasudo chown -R flaskuser:flaskuser /opt/flask-app/ # Dizin izinlerinisuperuser@server:~$ sudo systemctl daemon-reload # Systemd'ye yeni dosyayı tanıtsuperuser@server:~$ sudo systemctl start flaskapp.service   # Servisi başlatsuperuser@server:~$ sudo systemctl enable flaskapp.service  # Servisin sistem açılışında başlamasını sağlasuperuser@server:~$ sudo systemctl status flaskapp.service  # Servisin durumunu kontrol etsuperuser@server:~$ sudo systemctl stop flaskapp.service   # Servisi durdur

Gelişmiş Systemd Özellikleri ve Üretim Ortamı İpuçları

Üretim ortamlarında Systemd'nin sağladığı ek özellikler, servislerinizi daha sağlam, güvenli ve performanslı hale getirmenize yardımcı olur.

Kaynak Sınırlamaları (Resource Limits)

Systemd, cgroups (control groups) entegrasyonu sayesinde servisler için CPU, bellek ve G/Ç kaynaklarını sınırlama olanağı sunar. Bu, bir servisin tüm sistem kaynaklarını tüketmesini engelleyebilir.

[Service]MemoryLimit=256MCpuQuota=50%

MemoryLimit=256M ile servisin belleği 256MB ile sınırlanır, CpuQuota=50% ile ise CPU kullanımının %50'yi geçmemesi sağlanır.

Güvenlik Sertleştirmesi (Security Hardening)

Systemd, servisleri izole etmek ve potansiyel güvenlik açıklarını azaltmak için çeşitli direktifler sunar.

  • ProtectSystem=full: Servis için kök dosya sistemini salt okunur yapar.
  • ProtectHome=true: Servisin ana dizinlere erişimini engeller.
  • NoNewPrivileges=true: Servisin yetkilerini artıramamasını sağlar.
  • PrivateTmp=true: Servise özel bir /tmp ve /var/tmp dizini atar, diğer servislerden izole eder.
  • ReadOnlyPaths=/path/to/read/only: Belirtilen yolları salt okunur yapar.
[Service]ProtectSystem=fullProtectHome=trueNoNewPrivileges=truePrivateTmp=trueReadOnlyPaths=/etc/myapp/config.d

Zamanlayıcı Birimleri (Timer Units)

Systemd, geleneksel cron yerine kullanılabilecek, daha esnek ve Systemd ekosistemiyle entegre .timer unit'leri sunar. Bu, belirli zamanlarda bir servisi çalıştırmak için kullanılır.

# /etc/systemd/system/myscript.timer[Unit]Description=Run my daily backup script[Timer]OnCalendar=dailyPersistent=true[Install]WantedBy=timers.target# /etc/systemd/system/myscript.service[Unit]Description=My Daily Backup Script[Service]Type=oneshotExecStart=/usr/local/bin/backup_script.sh

OnCalendar=daily ile betik her gün çalışır, Persistent=true ile ise sistem kapalıyken kaçırılan çalıştırmalar açılışta telafi edilir.

Gerçek Dünya Üretim Senaryosu: Mikroservis Dağıtımı ve Sağlık Kontrolü

AWS EC2 üzerinde çalışan ve bir Go mikroservisinin birden fazla örneğini barındıran bir sunucunuz olduğunu düşünün. Her örnek farklı bir portta dinliyor ve Systemd ile yönetiliyor. Amacımız, her bir servisin sağlıklı çalıştığından emin olmak ve başarısızlık durumunda otomatik müdahale sağlamak.

Senaryo Detayı:

  1. İki Go mikroservis örneği: myapi-8080.service ve myapi-8081.service.
  2. Her servisin kendi yapılandırma dosyası (/etc/myapi/config-8080.env).
  3. Servis başlamadan önce bir sağlık kontrolü veya yapılandırma doğrulama adımı.
  4. Servisin sürekli çalışır durumda kalmasını sağlamak.

/etc/systemd/system/myapi@.service (Şablon Unit Dosyası):

[Unit]Description=My API Microservice Instance %iAfter=network-online.targetRequires=network-online.target[Service]Type=execUser=apiuserGroup=apiuserWorkingDirectory=/opt/myapi/EnvironmentFile=/etc/myapi/config-%i.envExecStartPre=/opt/myapi/scripts/validate_config.sh %i # Servis başlamadan önce doğrulamaExecStart=/opt/myapi/bin/myapi-server --port ${PORT}Restart=on-failureRestartSec=15s # Yeniden başlatma öncesi 15 saniye bekleKalırım TimeoutStartSec=30 # Başlangıç için maksimum 30 saniyeCanNotStop=false # Servisin systemctl stop ile durdurulabileceğini belirtPrivateTmp=true # Her instance için izole /tmpDirectoryMode=0755 # Çalışma dizini izinleriProtectSystem=full # Kök dosya sistemini salt okunur yap[Install]WantedBy=multi-user.target

Açıklamalar:

  • myapi@.service: Bu bir şablon unit dosyasıdır. @ karakteri, bu servisten birden fazla örnek oluşturulabileceğini belirtir. %i placeholder'ı, systemctl start myapi@8080.service komutundaki 8080 gibi değeri temsil eder.
  • EnvironmentFile=/etc/myapi/config-%i.env: Her servis örneği için ayrı bir yapılandırma dosyasından ortam değişkenlerini yükler. Örneğin, myapi@8080.service için /etc/myapi/config-8080.env yüklenir. Bu dosya PORT=8080 gibi değişkenleri içerebilir.
  • ExecStartPre=/opt/myapi/scripts/validate_config.sh %i: Servis ana komutu çalışmadan önce bu betiği çalıştırır. Eğer betik sıfır olmayan bir çıkış kodu döndürürse, servis başlatılmaz. Bu, yapılandırma hatalarını erken aşamada yakalamak için idealdir.
  • RestartSec=15s: Servisin sürekli çöküp kalkmasını (flapping) önlemek için yeniden başlatmalar arasında bir bekleme süresi tanımlarız.
  • TimeoutStartSec=30: Eğer servis 30 saniye içinde başarıyla başlamazsa, Systemd servisi başarısız kabul eder.
  • CanNotStop=false: Varsayılan olarak false'dur, ancak belirtmek servis durdurma işleminin beklenen şekilde çalışmasını vurgular.
  • PrivateTmp=true: Her servis örneği için ayrı bir geçici dizin sağlayarak izolasyonu artırır.

Bu şablonu kullanarak servisleri başlatmak:

sudo systemctl enable myapi@8080.service myapi@8081.servicesudo systemctl start myapi@8080.service myapi@8081.service

Systemd, servislerinizi yönetmek için güçlü ve esnek bir araçtır. Unit dosyalarını doğru bir şekilde anlayıp yapılandırarak, Linux tabanlı sistemlerinizde uygulamalarınızın güvenilirliğini, performansını ve güvenliğini önemli ölçüde artırabilirsiniz. Güvenlik ve kaynak yönetimi direktiflerini kullanarak servislerinizi izole etmek ve kararlı hale getirmek, üretim ortamlarında beklenmedik sorunları önlemenin anahtarıdır.

← Blog Listesine Dön