Jak automatycznie zrestartować proces w tle Linuksa, jeśli się nie powiedzie?

30

Mam proces wykonywany przez skrypt init.d w tle. Na przykład:

case "$1" in 
    start)
       /bin/myprocess &
    stop)
       killall myprocess
    restart)
       killall myprocess
       /bin/myprocess &
esac

W pewnych warunkach mój proces może zakończyć się niepowodzeniem i powrócić. Czy jest jakiś (standardowy) sposób na wykrycie awarii i ponowne uruchomienie automatyczne?

Honza
źródło
Jasne, ale różni się w zależności od dystrybucji. Prawie wszystkie z nich stanowią pewnego rodzaju menedżera usług.
David Schwartz,
Nie ma standardowej dystrybucji, ale buildroot. Więc muszę to zrobić ręcznie ...
Honza,

Odpowiedzi:

14

Najprostszym sposobem byłoby dodanie go do pliku / etc / inittab , który został zaprojektowany do tego typu czynności:

respawn Jeśli proces nie istnieje, uruchom go. Nie czekaj na jego zakończenie (kontynuuj skanowanie pliku / etc / inittab). Uruchom ponownie proces po jego śmierci. Jeśli proces istnieje, nie rób nic i kontynuuj skanowanie pliku / etc / inittab.

Na przykład możesz to zrobić:

# Run my stuff
myprocess:2345:respawn:/bin/myprocess
Alan Shutko
źródło
Zauważ, że /etc/inittabdziała (lub nawet istnieje) tylko wtedy, gdy masz system inicjujący oparty na sysvinit. Z upstart i z systemd tak nie jest. Musisz zainstalować busyboksa (bardzo prymitywną powłokę powodującą, że sysadm odzyskuje zadania bolesne, ale może zastąpić initd kompatybilny z sysvinit) lub sysvinit (jest to skamielina). W pojemniku dokowanym tylko pierwszy nie jest bolesny.
peterh
26

Buildroot ma trzy możliwe systemy inicjujące, więc można to zrobić na trzy sposoby:

BusyBox init

Dzięki temu dodaje się wpis do /etc/inittab.

::respawn:/bin/myprocess

Zauważ, że BusyBox initma idiosynkratyczny /etc/inittabformat. Drugie pole jest bez znaczenia, a pierwsze pole nie jest identyfikatorem, ale nazwą urządzenia.

Linux „System V” init

Ponownie dodaje się wpis do /etc/inittab.

myprocess:2345:respawn:/bin/myprocess

systemd

Jeden zapisuje plik jednostkowy, powiedzmy /etc/systemd/system/myprocess.service:

[Unit]
Description=My Process

[Service]
ExecStart=/bin/myprocess
Restart=always

[Install]
WantedBy=multi-user.target

Włącz tę opcję, aby automatycznie uruchamiać się podczas uruchamiania za pomocą:

systemctl enable myprocess.service

Uruchom ręcznie za pomocą:

systemctl start myprocess.service

Dalsza lektura

JdeBP
źródło
ale kiedy zastosujesz to podejście inittab, twój proces nie będzie już dostępny przez interfejs „serwisowy”, prawda? tzn. nie możesz już iść ... service mything startczy service mything stopjest sposób, aby mieć to, co najlepsze? tzn. niezniszczalna usługa sysvinit, ale czy można ją również wykorzystać za pomocą „usługi”?
horseyguy
23

A co z tworzeniem podpowłoki z pętlą, która wywołuje ciągle ten sam proces?

Jeśli się skończy, następna iteracja pętli rozpocznie się i rozpocznie ją ponownie.

(while true; do 
    /bin/myprocess
done) &

Jeśli podpowłoka umrze, to jednak koniec. Jedyną możliwością w tym przypadku byłoby stworzenie innego procesu (nazywam to nekromantą), który sprawdza, czy twój proces żyje, uruchom go, jeśli tak nie jest, i uruchom tego nekromanty za pomocą crona, abyś mógł to regularnie sprawdzać.

Następnym krokiem byłoby zastanowienie się, co by się stało, gdyby umarł cron, ale w pewnym momencie powinieneś czuć się bezpiecznie i przestać się martwić.

Trylks
źródło
3

Możesz skorzystać z Monit . Jest naprawdę łatwy w użyciu i dość elastyczny. Zobacz na przykład tę konfigurację dotyczącą ponownego uruchamiania procesu Tomcat po awarii.

check process tomcat with pidfile /var/run/tomcat.pid
   start program = "/etc/init.d/tomcat start"
   stop  program = "/etc/init.d/tomcat stop"
   if failed port 8080 type tcp then restart

Zawiera również wiele przykładów konfiguracji dla wielu przypadków użycia.

Clyde D'Cruz
źródło
1

Jeśli nie jesteś superużytkownikiem lub rootem, a jeśli w systemie Linux jest zainstalowany Docker, możesz utworzyć obraz dokera swojego procesu, używając go do zrestartowania procesu, jeśli system zostanie zrestartowany.

Plik: docker-compose.yml

version: "3"
services:
  lserver:
    image: your_docker_image:latest
    ports:
    - 8080:8080   # just use 8080 as an example
    restart: always  # this is where your process can be guaranteed to restart

Aby uruchomić kontener dokerów,

docker-compose up -d

Uważam, że łatwo jest obsługiwać mój własny proces z automatycznym ponownym uruchomieniem, jeśli nie jestem super użytkownikiem systemu.

Oto przykład szybkiego tworzenia obrazu dokera:

Plik: Plik Docker

FROM alpine:3.5

RUN apk update && apk upgrade && rm -rf /var/cache/apk/*
WORKDIR /app
COPY my-process-server /app
RUN ln -s /app/my-process-server /usr/local/bin/my-process-server

EXPOSE 8080

CMD ["my-process-server"]
Michael Qin
źródło
0

W moim przypadku jako szybką poprawkę zmodyfikowałem i użyłem rozwiązania @Trylks, aby owinąć uruchamiany program. Chciałem, żeby zakończyło się to dopiero przy czystym wyjściu.

Powinien działać w większości powłok:

#!/bin/sh

echo ""
echo "Use: $0 ./program"
echo ""

#eg="/usr/bin/apt update"

echo "Executing $1 ..."

EXIT_CODE=1
(while [ $EXIT_CODE -gt 0 ]; do
    $1
    # loops on error code: greater-than 0
    EXIT_CODE=$?
done) &
użytkownik9869932
źródło
0

Możesz użyć restarter

start)
   restarter -c /bin/myprocess &
stop)
   pkill -f myprocess

W nowszych systemach użyj systemd, który rozwiązuje wszystkie te trywialne problemy

sivann
źródło