Başlamayan bir systemd servisi, neredeyse hiçbir zaman gizemli değildir. systemctl status <unit> çalıştırın, ardından journalctl -u <unit> -n 50 --no-pager ile o unit’in son 50 journal satırını okuyun — ikisi birlikte, beş sebepten birini genelde açıkça adıyla söyler: hatalı bir yol, eksik binary, yanlış izinler, bir SELinux/AppArmor reddi ya da unit dosyası sözdizimi hatası. Arıza sebebi logdadir; aşağıdaki düzeltmeler, ona karşı desen eşleştirmekten ibarettir.
Bir systemd servisinin neden başarısız olduğunu nasıl görürsünüz?
Önce status, sonra journal:
systemctl status myapp.service
journalctl -u myapp.service -n 50 --no-pager status, durumu verir (inactive (dead), failed (exit-code), activating (auto-restart)) ve son birkaç log satırını. Journal ise bütün hikâyeyi verir: stdout, stderr ve systemd’nin unit’e dair kendi şikâyetleri.
Unit daha önce başarısız olduysa ve o çalıştırmanın kaydını istiyorsanız, bu açılış için -b ya da --since today ekleyin:
journalctl -u myapp.service -b --no-pager Tam araç seti — boot’lar, öncelikler, çıktıyı canlı izleme — için journalctl cheat sheet yazısına bakın. Aynı kas hafızasıdır.
Bilinmeye değer bir çift daha:
systemctl list-units --failed
systemctl reset-failed myapp.service Birincisi, makinedeki kırmızı tüm unit’leri listeler. İkincisi, düzeltmenizden sonra failed durumunu temizler — kozmetiktir ama status sayfalarının sahte alarm çalmasını önler.
En yaygın nedenler nelerdir?
Log belirtiyi adlandırdıktan sonra, neden neredeyse her zaman şu beşinden biridir:
| Log diyor ki | Muhtemel neden | Çözüm |
|---|---|---|
status=203/EXEC | ExecStart= yolu hatalı ya da yorumlayıcı eksik | Mutlak yol, chmod +x, shebang’i kontrol et |
Bir script’te status=203/EXEC | Script CRLF satır sonlarına ya da bozuk bir shebang’e sahip | dos2unix script.sh, ilk satırı düzelt |
status=1/FAILURE, uygulama log’u yok | Çalışma dizini ya da ortam değişkeni eksik | WorkingDirectory= ayarla, Environment= ekle |
Permission denied | Kullanıcı dosyaları okuyamıyor ya da porta bağlanamıyor | Sahipliği düzelt; 1024 altı portlar AmbientCapabilities=CAP_NET_BIND_SERVICE ya da root ister |
Unit is masked | Biri systemctl mask çalıştırmış | systemctl unmask myapp.service |
| Unit dosyası düzenlemesi “bir şey değiştirmiyor” | Daemon reload edilmedi | systemctl daemon-reload |
203/EXEC ailesi ayrıca anılmayı hak eder, çünkü öğle aralarını yiyen odur. Systemd, ExecStart=‘ı başlatmak için shell’inizi kullanmaz. Yani:
# Yanlış — shell yok, ~ hiç açılmaz, PATH araması yok
ExecStart=~/app/run.sh
# Doğru
ExecStart=/opt/app/run.sh Ve scriptin kendisi çalıştırılabilir olmalı, gerçek bir shebang ile başlamalı (#!/bin/bash ya da #!/usr/bin/env bash). Terminalinizden sorunsuz çalışan ama systemd altında 203 ile ölen bir script, neredeyse hep şu dördünden biridir: çalıştırılabilir değil, CRLF satır sonları, hiçbir yere işaret etmeyen bir shebang ya da göreli bir yol.
Neden elle başlıyor ama açılışta başlamıyor?
Klasik sıralama hatası. Log, açılışın hemen ardından gelen başarısızlıkları gösteriyorsa ama unit’i elle systemctl start ile başlattığınızda sorunsuz açılıyorsa, servisiniz bir yarışı kaybediyor demektir — ağa, mount edilmiş diske ya da veritabanına, o şey daha var olmadan uzanıyor.
Çözüm, ummayı bırakıp bağımlılıkları beyan etmektir:
[Unit]
After=network-online.target postgresql.service
Wants=network-online.target
[Service]
ExecStartPre=/usr/bin/test -f /opt/app/config.toml After= başlatmayı sıraya koyar; Wants=, systemd’nin bağımlılığı gerçekten ayağa kaldırmasını sağlar. network-online.target, yalnızca dağıtımınızda ağ-bekleme servisi etkinse çalışır; systemctl is-enabled NetworkManager-wait-online.service kontrol edin (ya da systemd-networkd karşılığını). ExecStartPre= bekçisi, stack trace yerine okunur bir mesajla gürültüyle düşmenin ucuz ve dürüst yoludur.
İkinci varyant: servis açılışta başlıyor ama hemen ölüyor. Etkileşimli ortamınızda olup açılışta olmayan şeyleri arayın — PATH farkları, bir virtualenv, bir HOME. İhtiyacınız olanı açıkça ayarlayın:
[Service]
Environment="PATH=/opt/app/venv/bin:/usr/bin"
User=appuser
WorkingDirectory=/opt/app Servisim neden journal’a log yazmıyor?
journalctl -u hiçbir şey göstermiyorsa üç şeyi sırayla kontrol edin:
- Unit içindeki
StandardOutput=veStandardError=—journal(varsayılan) ya dajournal+consoleolmalılar. Biri onlarınullyapmış olabilir. - Uygulama stdout yerine dosyaya yazıyor. Systemd yalnızca stdout/stderr’i yakalar; dosyaya yazanlar journal’ı bütünüyle atlar. Ya uygulamayı stdout’a yönlendirin ya da dosyayı okuyun.
- Depolama limitleri eski satırları atmış:
journalctl --disk-usage, ve journal tıkanıyorsa/etc/systemd/journald.confiçindeSystemMaxUse=.
Başlangıcın kendisini ayıklamak için, açılış anındaki bağlama bir shell düşürmekten iyisi yoktur:
[Service]
ExecStart=/bin/bash -c 'exec /opt/app/bin/server 2>&1' Ya da gerçekten gizemli vakalar için, ExecStart= komutunun aynısını unit’in kullanıcısı olarak bir shell’de çalıştırın — ortam farklarının çoğu ilk on saniyede su yüzüne çıkar.
Çökme sonrası otomatik yeniden başlamasını nasıl sağlarsınız?
Varsayılan politika Restart=no‘dur: çöken servis ölü kalır ve öğrenmeyi bir kullanıcıya bırakır. Bunu servis başına düzeltin:
[Service]
Restart=on-failure
RestartSec=5 | Ayar | Ne zaman yeniden başlatır |
|---|---|
no (varsayılan) | Asla |
on-failure | Sıfırdan farklı çıkış, sinyal, zaman aşımı |
always | Her çıkışta, temiz bile olsa |
on-watchdog | Yalnızca watchdog zaman aşımı |
Restart=on-failure‘ı bir başlatma hızı korumasıyla eşleştirin ki çöken bir döngü makineyi dövmesin: [Unit] bölümünde StartLimitIntervalSec= ve StartLimitBurst=. Altmış saniyede beş başarısızlık, CPU döndürmek değil, bir insanı çağırmalıdır.
Bunu daemon değil, zamanlanmış bir iş olarak kuruyorsanız önce cron vs systemd timer yazısını tartın — timer’lar journal loglamasını ve bağımlılık sıralamasını bedava verir; bu yazının sürekli eline uzandığı şey tam da budur.
60 saniyelik kontrol listesi
systemctl status <unit>— durumu ve son satırları oku.journalctl -u <unit> -n 50 --no-pager— asıl hatayı bul.203/EXECmi? Yolu, shebang’i, izinleri düzelt.Permission deniedmi? Kullanıcıyı ve dosya sahipliğini düzelt.- Yalnızca açılışta mı düşüyor?
After=/Wants=network-online.targetve birExecStartPre=bekçisi ekle. - Unit dosyasını değiştirdin mi?
systemctl daemon-reload && systemctl restart <unit>. - Sonraki çöküş saklanacağı yerine kendini duyursun diye
Restart=on-failureekle.
“Systemd karmaşıkmış” dedirten anların çoğu, hatanın baştan beri journal’da olmasına indirgenir. Unit dosyasını düzenlemeden önce okuyun; sonrasında değil.
— mrsaynothing
Get the next one by email
One email per post. No spam, no algorithms.
what is this?GGUF kuantizasyonu: hangi seviyeyi kullanmalısınız?
Yazıları beğendiniz mi? Ben geçim için böyle inşa ederim. beni işe al