Systemd zabija usługę natychmiast po uruchomieniu

15

Piszę plik jednostki systemowej dla OSSEC HIDS. Problem polega na tym, że gdy systemd uruchamia usługę, natychmiast je zatrzymuje.

Kiedy używam tej dyrektywy ExecStart, wszystko działa dobrze.

ExecStart=/var/ossec/bin/ossec-control start

Ale kiedy dokonam niewielkiej poprawy, w dziennikach OSSEC jest dobrze, że po uruchomieniu otrzymuje SIG 15.

ExecStart=/bin/sh -c '${DIRECTORY}/bin/ossec-control start'

Jeśli dokonam kolejnej małej zmiany, usługa otrzyma SIG 15 po 20 sekundach.

ExecStart=/bin/sh -c '${DIRECTORY}/bin/ossec-control start && sleep 20'

Sądzę więc, że systemd zabija proces / bin / sh po uruchomieniu usługi, a bin / sh zabija OSSEC.

Jak mogę rozwiązać ten problem?

Daniil Svetlov
źródło
1
Jaki jest rodzaj usługi?
Wieland
@Wieland, próbowałem prostego i rozwidlenia, ale wynik jest nadal taki sam.
Daniil Svetlov

Odpowiedzi:

37

niedopasowanie protokołu gotowości

Jak sugerował Wieland, Typeusługa jest ważna. To ustawienie oznacza, który system protokołu gotowości oczekuje, że usługa będzie mówić. simpleUsługa zakłada się natychmiast gotowy. forkingUsługa zostanie podjęta ma być gotowy po jego początkowy proces rozwidla dziecko i następnie kończy działanie. dbusUsługi uważane jest gotowy, kiedy na pulpicie pojawi Bus serwer. I tak dalej.

Jeśli nie otrzymujesz zadeklarowanego w jednostce usługowej protokołu gotowości zgodnego z tym, co robi usługa, to wszystko idzie nie tak. Niedopasowania protokołu gotowości powodują, że usługi nie uruchamiają się poprawnie lub (częściej) są (błędnie) diagnozowane przez systemd jako awarie. Gdy usługa jest postrzegana jako nieudana, systemd zapewnia, że każdy osierocony dodatkowy proces usługi, który mógł pozostawać uruchomiony jako część awarii (z jego punktu widzenia), zostanie zabity w celu przywrócenia usługi do stanu nieaktywnego stan.

Robisz dokładnie to.

Przede wszystkim proste rzeczy: sh -cnie pasuje Type=simplelub Type=forking.

W simpleprotokole proces początkowy jest traktowany jako proces serwisowy. Ale w rzeczywistości sh -copakowanie uruchamia rzeczywisty program serwisowy jako proces potomny . Więc MAINPIDidzie źle i ExecReloadprzestaje działać, na początek. Podczas korzystania Type=simplenależy przede wszystkim użyć sh -c 'exec …'lub nie sh -c . Ta ostatnia jest częściej prawidłowym kursem, niż niektórzy sądzą.

sh -cteż nie pasuje Type=forking. Protokół gotowości forkingusługi jest dość specyficzny. Początkowy proces musi rozwidlić dziecko, a następnie wyjść. systemd stosuje limit czasu dla tego protokołu. Jeśli początkowy proces nie rozwinie się w wyznaczonym czasie, przygotowanie się nie powiedzie. Jeśli początkowy proces nie zakończy się w wyznaczonym czasie, to również oznacza błąd.

niepotrzebny horror ossec-control

Co prowadzi nas do skomplikowanych rzeczy: tego ossec-controlskryptu.

Okazuje się , że jest to rcskrypt Systemu 5, który uruchamia od 4 do 10 procesów, które same z kolei rozwidlają się i wychodzą. Jest to jeden ze rcskryptów System 5, który próbuje zarządzać całym zestawem procesów serwera w jednym skrypcie, z forpętlami, warunkami wyścigu, arbitralnymi próbami sleepich uniknięcia, trybami awarii, które mogą udusić system w stanie częściowo uruchomionym, i wszystkie inne okropności, które sprawiły, że ludzie wymyślili takie rzeczy, jak AIX System Resource Controller i Daemontools dwie dekady temu. I nie zapominajmy o ukrytym skrypcie powłoki w katalogu binarnym, który przepisuje on w locie, aby zaimplementować idiosynkratyczne enablei disableczasowniki.

Więc kiedy /bin/sh -c '/var/ossec/bin/ossec-control start'to się dzieje, to:

  1. systemd sprawdza, co może być procesem serwisowym.
  2. To skorupa, która się rozwidla ossec-control.
  3. To z kolei rozwidla od 4 do 10 wnuków.
  4. Wnuki wszystkie rozwidlają się i wychodzą z kolei.
  5. Wnuki wszystkie rozwidlają się i wychodzą równolegle.
  6. ossec-control wychodzi.
  7. Pierwszy pocisk wychodzi.
  8. Procesy usługowe były pra-pra- wnuki, ale dlatego, że w ten sposób meczów roboczych ani forking anisimple protokół gotowość, Systemd uważa usługę jako całości nie udało i zamyka go z powrotem w dół.

Żaden z tych horrorów nie jest wcale potrzebny w systemie. Nic z tego.

systemowa jednostka usługowa szablonu

Zamiast tego pisze się bardzo prostą jednostkę szablonu :

[Jednostka]
Opis = Serwer OSSEC HIDS% i
After = network.target 

[Usługa]
Typ = prosty
ExecStartPre = / usr / bin / env / var / ossec / bin /% p-% i -t
ExecStart = / usr / bin / env / var / ossec / bin /% p-% i -f

[Zainstalować]
WantedBy = multi-user.target

Zapisz to jako /etc/systemd/system/[email protected].

Różne rzeczywiste usługi to instancje tego szablonu o nazwie:

Następnie funkcja włączania i wyłączania pochodzi bezpośrednio z systemu zarządzania usługami (z naprawionym błędem RedHat 752774 ), bez potrzeby ukrytych skryptów powłoki.

 systemctl enable ossec @ dbd ossec @ agentlessd ossec @ csyslogd ossec @ maild ossec @ execd ossec @ Analysisd ossec @ logcollector ossec @ zdalny ossec @ syscheckd ossec @ monitord

Ponadto systemd poznaje i śledzi bezpośrednio każdą rzeczywistą usługę. Może filtrować ich logi journalctl -u. Może wiedzieć, kiedy dana usługa uległa awarii. Wie, jakie usługi powinny być włączone i uruchomione.

Nawiasem mówiąc: Type=simplei -fopcje są tutaj tak samo, jak w wielu innych przypadkach. Bardzo niewiele usług na wolności faktycznie sygnalizuje ich gotowość dzięki exit, a te również nie są takimi przypadkami. Ale to właśnie forkingoznacza ten typ. Usługi na wolności w głównym rozwidleniu i wyjściu z powodu jakiegoś pomyłki otrzymały pogląd mądrości, że to właśnie powinni zrobić demony. W rzeczywistości tak nie jest. Nie było tego od lat 90. Czas nadrobić zaległości.

Dalsza lektura

JdeBP
źródło
2
Bardzo szczegółowa odpowiedź! Sugeruję również utworzenie celu „grupowania”, powiedzmy ossec.target, który Requires=wszystkie potrzebne instancje PartOf=ossec.targetustawią w ossec @ .service. Umożliwi to uruchomienie i zatrzymanie ossec poprzez uruchomienie i zatrzymanie ossec.target.
intelfx
@JdeBP, wow! Bardzo dziękuję za tak szczegółową odpowiedź. Mam nadzieję, że zrobię tę jednostkę i napiszę tutaj o wynikach. Pomyślałem, że będę łatwiej. Ale masz rację, ossec-control to piekło dla inicjujących.
Daniil Svetlov
1
Jaki jest powód używania / usr / bin / env jako opakowania?
Marius Gedminas
1

Zachowaj Type = rozwidlaj i podaj lokalizację pliku pid, jeśli usługa startowa / aplikacja utrzymuje jakiś pid.

[Jednostka]
Opis = „Uruchom aplikację podczas rozruchu”
Po = network.target syslog.target auditd.service

[Usługa]
Typ = rozwidlanie
PIDFile = / var / run / apache2 / apache2.pid
ExecStart = / etc / init.d / apache2 start
ExecStop = / etc / init.d / apache2 stop
StandardOutput = syslog
StandardError = syslog
Restart = awaria
SyslogIdentifier = webappslog

[Zainstaluj]
WantedBy = multi-user.target
Alias ​​= webapps

Raushan
źródło
0

W pewnym sensie miałem usługę systemową, która wydawała się, że systemd „zabije” ją po 30 latach.

systemctl status service-namepokaże się main process exited, code=exited, status=1/FAILUREpo upływie 30 lat.

Działałoby dobrze „w izolacji” (jak ręcznie w terminalu z tym samym środowiskiem ).

Okazuje się, że tak było

Type=forking
...
Environment=ABC="TRUE"
ExecStart=/path/to/my_script_to_spawn_process.sh

w ciągu my_script_to_spawn_process.shto robi

/bin/something > /dev/null 2>&1 &

który działa, ale odrzucał informacje z dziennika wyjściowego (zwykle trafia do pliku lub, jeśli nie to, być może journalctl).

Zmieniając go, by logował się w innym miejscu /bin/something > /tmp/my_file

następnie śledzenie /tmp/my_fileujawnionej rzeczywistej przyczyny. Który był (stycznie), że nie możesz używać składni Environment=ABC="true"tak, jak możesz to zrobić w bashu, to musi to być brak cudzysłowów lub wartość klucza we wszystkich cudzysłowach, Environment="ABC=true"co spowodowało, że mój proces zakończył się „w fazie konfiguracji” po około 30s.

rogerdpack
źródło
-4

Zauważ, że model demona systemd jest uproszczony i niekompatybilny z wieloma istniejącymi demonami, które wykonują wielokrotne rozwidlanie, wykonywanie i konfigurowanie. Najczęściej są to demony, które uruchamiają się jako root, aby skonfigurować ustawienia, a następnie przełączają się na mniej uprzywilejowany identyfikator UID do rutynowej operacji. np. inicjalizacja pliku Pid to jedna rzecz, która kończy się niepowodzeniem w systemie z powodu problemów z uprawnieniami. Istnieją obejścia (nie poprawki), ale są źle udokumentowane.

Wyjaśnienie JdeBP jest mile widziane, ale niekompletne, a jego twierdzenie, że to wszystko wina ossec-control, jest po prostu nieprawdziwe. Nawet dość trywialne rzeczy są problematyczne, np. Uzyskiwanie nieskróconych wierszy dziennika w celu debugowania problemów lub znaczących komunikatów o błędach od samego systemd, gdy zabija procesy.

Jan
źródło
1
Do czego w ogóle służą pliki PID? Jeśli taki istnieje dla danej usługi, może istnieć rzeczywisty proces z tym PID, a gdy istnieje proces z odpowiednim PID, może to być oczekiwana usługa.
JoostM,