Linux Systemd Detayları ve Sunucuda Servis Yazmak

Linux Systemd Detayları ve Sunucuda Servis Yazmak

Ağ & Sistemİsmet BALAT • 👁 1135 Okunma • Favorilerinize Ekleyin

Linux sunucunuzda sıfırdan bir servis yazmak veya elinizdeki bir scripti servise çevirmek için systemd ana processini kullanacağız. Böylece systemctl ve service komutlarıyla kendi servisinizi özgürce kontrol edebilir, başlangıçta otomatik çalışan programlar hazırlayabilir ve dilediğinizde programınızı açıp kapatabilirsiniz. Bu yazımızda RHEL, Centos 7 kullanarak örnekleri anlatacağız.


Önyüklemede işlemleri yönetme ve başlatma mekanizması değiştirildi. RHEL / CentOS 6.x'e kadar, /etc/init.d/ içinde bir betik oluşturup chkconfig yardımıyla etkinleştirmiş olurdunuz, ancak RHEL / CentOS 7'de işler farklılaşıyor. Artık init.d yerine systemd ana processini kullanmamız gerekiyor ve systemd ana Linux dağıtımlarında default process manager olduğu için daha faydalı ve verimli bir kullanıma geçmiş oluyoruz.

1. Systemd Nedir?

Systemd programı, Linux ailesinde bulunur ve amacı; bilgisayardaki sistem ve servislerin çalışmasını organize etmektir. Bu yönetimi, systemctl, journalctl, notify, analyze, cgls, cgtop, loginctl ve nspawn olarak adlandırılan araçlar sayesinde gerçekleştirir.

Linux'taki her süreç şeffaf bir şekilde görünür olduğundan, systemd'nin nerede gizlendiğini görerek başlayalım. Sistemimde ps -ef | grep systemd komutuyla aşağıdakileri alıyorum:

~$ ps -ef | grep systemd
root         1     0  0 15:29 ?        00:01:02 /lib/systemd/systemd --system --deserialize 22
message+   768     1  0 15:29 ?        00:05:46 /usr/bin/dbus-daemon --system --address=systemd: --nofork --nopidfile --systemd-activation --syslog-only
root       805     1  0 15:29 ?        00:10:22 /lib/systemd/systemd-logind
ankush    1132     1  0 15:29 ?        00:00:00 /lib/systemd/systemd --user
ankush    1176  1132  0 15:29 ?        00:04:50 /usr/bin/dbus-daemon --session --address=systemd: --nofork --nopidfile --systemd-activation --syslog-only
ankush    9772 20029  0 21:11 pts/6    00:00:00 grep --color=auto systemd
systemd+ 17298     1  0 15:29 ?        00:00:12 /lib/systemd/systemd-resolved
systemd+ 17303     1  0 15:29 ?        00:00:00 /lib/systemd/systemd-timesyncd
root     17307     1  0 15:29 ?        00:00:02 /lib/systemd/systemd-journald
root     18182     1  0 15:29 ?        00:00:00 /lib/systemd/systemd-udevd

Sizinde farkettiğinizi gibi listedeki ilk işlem root olarak başlatıldı ve pid 1'e sahip. Bu, sistemin önyükleme (boot) sırasında başlattığı ilk işlemdi. Systemd'ye merhaba deyin :)

Dolayısıyla, oldukça basit bir şekilde systemd, sistemdeki diğer işlemleri başlatan, yöneten ve sonlandıran, günlükler, dosya sistemi durumları vb. hakkında bilgi sağlamanın yanı sıra özetle "ana" işlemdir.

Systemd binary’si /usr/lib/systemd/systemd dosyası olarak sistemde bulunmakta ve systemd rpm paketi tarafından kurulmaktadır. Systemd binary’si eski yapıdaki /sbin/init programının yerini alır. Şu an için RHEL 7 ‘de zaten /sbin/init tam manasıyla /usr/lib/systemd/systemd dosyasına bir linktir.

1.1 Systemd Önemli Dizinler

Systemd ile çalışırken aşağıdaki dizin adreslerini bilmek işimizi kolaylaştıracaktır.

Dizin Açıklama
/usr/lib/systemd/system/ RPM paketleri systemd servislerinin yapılandırma dosyasını buraya kurmaktadır.
/run/systemd/system/ Runtime dediğimiz işletim sistemi çalışırken bu dizin kullanılır.
/etc/systemd/system/ Systemd servisleri enable veya disable edildiğinde /usr/lib/systemd/system dizinindeki dosyalar buraya linklenir.

1.2 Unit

Systemd, unit adı verdiğimiz bileşen ve bunların kendi arasındaki ilişkilerinden oluşmaktadır. Bu yapılandırma dosyaları sadece servisler için değil runlevel’ların yerini alan target'lar, mount edilecek bileşenleri içeren kısımlar ve birçok bileşenden oluşabilmektedir. Bu dosyalar /usr/lib/systemd/system dizini altında şu uzantılarla yer alabilmektedir.

Unit Tipi Dosya Uzantısı Açıklaması
Service unit .service Sistem servisi
Target unit .target Systemd unit grubu (eski runlevel’lar)
Automount unit .automount Automount edilecekler
Device unit .device Kernel’ın tanıdığı cihaz dosyaları.
Mount unit .mount Mount edilecek dosya sistemleri
Path unit .path Dosya sistemindeki dosya veya dizinler
Scope unit .scope Sonradan çalıştırılan harici programlar.
Slice unit .slice Sistem süreçlerini yöneten belirli bir hiyerarşideki unit dosyaları.
Snapshot unit .snapshot Systemd’nin snapshotları (kendimizin oluşturuduğu runlevel’lar denebilir)
Socket unit .socket IPC için kullanılan dosyaları oluşturan unit dosyaları
Swap unit .swap Swap dosyası veya swapleri aktive eden unit dosysaları
Timer unit .timer Systemd timer

1.3 Target

Systemd ile birlikte anmamız ve es geçmemiz bir konuda Target'lardır. Yani eski isimleriyle runlevel'lar. Sunucularımızın, sunduğu hizmetleri yerine getirilebilmesi için, bu hizmetlerin sunucu önyükleme işlemi sırasında çağırılması ve farklı seviyelere ulaşması gerekir. Bazı hizmetler, bilgisayar örneğin kurtarma düzeyine (run level 0) ulaştığında ve bazıları da multi-user (çok kullanıcı) düzeyine (run level 3) ulaştığında çalıştırılmak üzere çağırılır. Bu seviyeleri, targets (hedefler) olarak düşünebilirsiniz.

Farklı servislerin birleşmesi ile oluşan runlevel'lara artık target ismi verilmektedir. Bu runlevel'ların geriye dönük isimlendirilmeler korunsa da uzun vadede bu takma adlar (aliaslar) kaldırılacaktır. Eskiden 0-6 arası runlevel’lar varken yeni yapıdaki target’lar şu şekildedir.

Runlevel Target Unit Açıklama
0 runlevel0.target, poweroff.target Poweroff target
1 runlevel1.target, rescue.target Rescue yani kurtarma target’ı
2 runlevel2.target, multi-user.target Çoklu kullanıcı target’ı (runlevel 2,runlevel 3 ve 4 aynı)
3 runlevel3.target, multi-user.target Çoklu kullanıcı target’ı (runlevel 2,runlevel 3 ve 4 aynı)
4 runlevel4.target, multi-user.target Çoklu kullanıcı target’ı (runlevel 2,runlevel 3 ve 4 aynı)
5 runlevel5.target, graphical.target Grafik ekranın başlatıldığı target
6 runlevel6.target, reboot.target Reboot target

Sisteminizin o an hangi target ile çalıştığını görmek için systemctl get-default komutunu kullanabilirsiniz.

2. Neden RHEL Systemd Kullanmaya Başladı?

Yukarıdaki başlıkta gördüğünüz gibi, systemd bir sistem ve süreç yöneticisidir ve RHEL 7'de UpStart (init.d) programının yerini almaktadır. RHEL bu kararı neden aldı? Bunun için çok iyi nedenler var, o yüzden hızlıca bir göz atalım.

2.1 Paralel hizmet başlatma

SysV init programından farklı olarak systemd hizmetleri paralel olarak başlatma yeteneğine sahiptir. Init programını hizmetleri birer birer başlatırken systemd onları eş zamanlı olarak başlatır. Mobil cihazların bile çok çekirdekli CPU'lara sahip olduğu bir çağda, paralel başlatmanın olmaması init.d açısından büyük bir sorun.

2.2 Dinamik (hot) servis yönetimi

USB sürücülerin Ubuntu ve benzeri dağıtımlarda otomatik olarak açılırken önceki Fedora sistemlerinde mount edilmesi gerektiğini fark ettiyseniz, bunun nedeni systemd'dir. Donanımdaki canlı değişiklikleri algılayabilir ve sonlandırabilir.

2.3 Ertelenmiş hizmet başlatma

Systemd, hizmetin başlamasını gerçekten ihtiyaç duyulduğu zamana erteleyebildiği için önyükleme sürelerini kısaltır. Basit bir örnek olarak ağ dosya sistemi ile ilgili hizmetleri verebiliriz. Kullanılabilir ağa bağlı disk yoksa, çalışır durumda bir hizmetin olması mantıklı değildir.

2.4 Daha hızlı süreç iletişimi

Systemd'nin paralel yetenekleri süreçler arası iletişime geçer. Systemd, soketlere ve sistem veriyoluna paralel erişim sunarak iletişim kaynakları için işlem bekleme sürelerini önemli ölçüde azaltır.

2.5 Otomatik yeniden başlatma

Bir hizmet çökerse, systemd bunu algılayabilir ve yeniden başlatmayı deneyebilir. Çoğu zaman, daha temel sorunlar olmadıkça, bir uygulamanın yeniden çalışmaya başlaması için gereken tek şey basit bir yeniden başlatma işlemidir.

Kısa bir özetle daha kıyaslama yapacak olursak;

  1. SysV init script’leri ile tam uyumludur. Init.d altındaki scriptleri de çalıştırabilir.
  2. Servislerin parallel olarak başlatılabilmesi (dolayısıyla daha hızlı sistem açılışı ve kapanışı)
  3. Servislerin on-deamon aktivasyonu. Yani bir servisi başlatırken onun ihtiyacı olan diğer servislerin de otomatik başlatılması
  4. Sistem servislerinin snapshot’ının alınabilmesi (Yani basitçe ifade ile kendi runlevel’larınızı oluşturabilme diyebiliriz buna)
  5. Servis bir şekilde ölürse bunun tesbiti ve ilgili servisin tekrar başlatılması

3. Servis Nasıl Yazılır?

Systemd hakkında detaylı iki başlıktan sonra artık servisimizi yazmak için kolları sıvayalım. Bunun için ilk olarak root kullanıcısına geçiniz ve /etc/systemd/system/ dizinine giderek servis adımızla yeni bir dosyayı nano veya vim sayesinde oluşturarak açanız. Ardından aşağıdaki örnek şablon üzerinden kullanılabilecek parametrelerin neler oldukları konusunda detay verelim.

[Unit]
Description=Live
After=network.target
Requires=syslog.target

[Install]
WantedBy=multi-user.target
Alias=hello_kerteriz.service

[Service]
Type=simple
User=root
Group=wheel
Restart=always
RestartSec=1
ExecStart=/usr/bin/sh /home/kerteriz/sayhello.sh
ExecStop=/bin/kill  ${MAINPID}

# Execute pre and post scripts as root
PermissionsStartOnly=true
  • Description: Servis açıklaması
  • After: Hangi servisten sonra çalışması gerektiğini söyler. Bu örnekte network servisi başlatıldıktan sonra servisimiz başlar.
  • Requires: Servisimizin çalışabilmesi için hangi servisin çalışıyor olması gerektiğini belirleyebiliriz.
  • WantedBy: Servisimizin hangi seviyede çalışacağını gösterir. Dolayısıyla, hizmetimizi etkinleştirirsek, multi-user.target.wants klasöründe, bu hizmete sembolik bir bağlantı oluşturulacaktır. Disable edildiğinde de silinir.
  • Alias: Servisin ismi
  • Type: simple ile herhangi bir zamanda yalnızca bir instance çalışacaktır.
  • User=root: Hangi kullanıcıda çalışacağı
  • Group=wheel: Hangi grupta çalışacağı
  • Restart: Servis bir şekilde kapanırsa ne zaman restart edileceği. Biz her clean veya unclean signal bulunduğunda restart etmesi için (always) kullanıyoruz. Tabi bunun yanında; unclean exit code veya signal bulunduğunda restart eden on-failure, unclean signal, watchdog veya timeout olduğunda restart eden on-abnormal ve yalnızca clean bir signal veya return code ile durdurulduğunda restart eden on-success parametreleri de mevcuttur.
  • RestartSec: Eğer yazılmazsa, sistem default 100ms sonra yeniden başlatmayı dener, biz 1 saniye sonra başlat dedik
  • ExecStart: Çalıştırmak istediğimiz binary (sh) ve dosya adı (sayhello.sh)
  • ExecStop: Servisi stop ettiğimizde çalışacak komut. Burada kill ediyoruz.
  • StartLimitIntervalSec=10: Servis kapanırsa, ve yeniden başlattığında başarılı olamıyorsa, systemde 10 saniyelik bir süre ile 5 defa yeniden dener, başlatamazsa bir daha denemez.

Bu bilgiler ışığında oldukça basit ve minimum gereksinimlerle bir service dosyası oluşturalım:

cd /etc/systemd/system/
vim hello_kerteriz.service
[Unit]
Description=Say Hello Program
After=network.target

[Service]
Type=simple
User=root
Restart=always
ExecStart=/usr/bin/sh /home/kerteriz/sayhello.sh
ExecStop=/bin/kill  ${MAINPID}

[Install]
WantedBy=multi-user.target

839x335

Ardından servis daemonunu yeniden başlatarak yaptığımız değişikliği algılamasını sağlayalım.

systemctl daemon-reload

Şimdi ise hem servisimizin başlangıçta çalışması (enable) hemde şu anda çalışmaya başlaması (start) için aşağıdaki komutla servisimizi başlatalım.

systemctl enable --now hello_kerteriz

Servisimizin çalışıp çalışmadığını görmek için status çıktısına bakabiliriz.

systemctl status hello_kerteriz

837x442

Yazdığım basit /home/kerteriz/sayhello.sh dosyasının içeriği şu şekildeydi ve 3 sn de bir çıktı dosyasına belirttiğim yazıyı yazıyordu;

echo "Merhaba Kerteriz Blog" >> /home/dataserver/say_out.txt
sleep 3

Bu shell komutlarınında çalışıp çalışmadığına bakalım;

837x289

Böylece yazdığımız scripti, programı vs. servise çevirerek tam kontrolü ele almış olduk. Takıldığınız yerleri sormak için aşağıdaki yorum kutusunu kullanabilirsiniz.

Bunlar da ilginizi çekebilir!

Rastgele bir yazıya git
Lütfen en az 3 harf yazınız 5 adet sonuç bulundu: