쉘 스크립트 데몬을 생성할 때 시스템 PIDFile의 일부인 PID는 무엇입니까?

쉘 스크립트 데몬을 생성할 때 시스템 PIDFile의 일부인 PID는 무엇입니까?

다음 코드를 기반으로 쉘 스크립트 데몬을 만들었습니다.이 답변. 다음 내용으로 systemd 서비스 파일을 작성했습니다.

[Unit]
Description=My Daemon
After=network.target

[Service]
Type=forking
PIDFile=/run/daemon.pid
ExecStart=/root/bin/daemon.sh
ExecReload=/bin/kill -1 -- $MAINPID
ExecStop=/bin/kill -- $MAINPID
TimeoutStopSec=5
KillMode=process

[Install]
WantedBy=multi-user.target

echo $$ > /run/daemon.pid;while 루프가 시작되기 직전에 PID 파일을 생성합니다(아직 해당 지점 에 도달하지 않았기 때문에 하위 또는 상위 프로세스가 아닌 데몬 프로세스에 의해 생성됨). 전화를 걸면 systemctl status daemon.service다음과 같은 경고가 표시됩니다.

daemon.service: PID file /run/daemon.pid not readable (yet?) after start: No such file or directory

스크립트의 시작 부분 echo $$ > /run/daemon.pid;(자식과 부모에서도 사용됨)에 PID 생성 문을 삽입하면 다음과 같은 경고가 표시됩니다.

daemon.service: PID 30631 read from file /run/daemon.pid does not exist or is a zombie.

systemd로부터 경고 메시지를 받지 않고 PID 파일을 생성하는 가장 좋은 방법은 무엇입니까?

답변1

따라서 여기서 볼 수 있는 문제는 Type=forkingpid 파일을 사용할 때 상위 프로세스가 종료되기 전에(올바른 pid를 사용하여) pid 파일을 생성해야 하기 때문입니다.

하위 프로세스에서 pidfile을 생성하면 상위 프로세스 종료와 경쟁하게 되며 일부(많은?) 경우 첫 번째 오류가 발생합니다.

하위 프로세스를 시작하기 전에 해당 하위 프로세스에 쓰는 pid 파일을 생성하면 $$종료된 상위 프로세스의 pid가 포함되므로 또 다른 오류가 표시됩니다.

이를 올바르게 수행하는 한 가지 방법은 종료하기 전에 상위 파일의 pidfile에 쓰는 것입니다. 이 경우 쓰기 $!(대신 $$)는 백그라운드에서 생성된 마지막 프로세스의 pid를 반환합니다.

예를 들어:

#!/bin/bash

# Run the following code in background:
(
    while keep_running; do
        do_something
    done
) &

# Write pid of the child to the pidfile:
echo "$!" >/run/daemon.pid
exit

이것은 잘 작동할 것입니다...하지만, 이를 달성하는 더 좋은 방법이 있습니다! 계속 읽으세요...


실제로 systemd의 요점은 프로세스를 데몬화하고 백그라운드에서 실행하는 것입니다. 이 작업을 직접 수행하려고 하면 systemd가 해당 작업을 수행하는 것을 방해할 뿐입니다. 이것은 또한 당신의 삶을 더욱 어렵게 만듭니다 ...

을 사용할 필요가 없습니다 Type=forking. 실행할 쉘 스크립트를 작성하기만 하면 됩니다.전경에사용할 서비스를 설정합니다 Type=simple. 그러면 pid 파일이 필요하지 않습니다.

/root/bin/daemon.sh간단히 다음과 같이 업데이트하세요 .

#!/bin/bash

# Run the following code in foreground:
while keep_running; do
    do_something
done

(참고: daemon.sh아마도 이 시점에서 가장 좋은 이름은 아닐 것입니다. 백그라운드에서 실행된다는 의미이기 때문입니다. 실제로 수행하는 작업과 관련하여 더 적절한 이름을 지정할 수도 있습니다.)

.service그런 다음 사용할 파일을 업데이트합니다 Type=simple. (실제로 여기서는 기본으로 사용되므로 생략해도 됩니다.)

[Service]
Type=simple
ExecStart=/root/bin/daemon.sh
ExecReload=/bin/kill -1 -- $MAINPID
ExecStop=/bin/kill -- $MAINPID
TimeoutStopSec=5
KillMode=process

ExecStop=그런데, 신호로 프로세스를 죽이는 것도 기본 동작이기 때문에 아마도 그것을 제거할 수 있을 것입니다 ...

systemd는 Type=forking실제로 이런 방식으로만 작동하는 레거시 프로그램에서만 작동하며 포그라운드에서 작동하도록 쉽게 수정할 수 없습니다... 끔찍하고 비효율적입니다. systemd(및 그 대체품, 이전 버전 중 일부)의 전체 요점은 스스로를 포크하고 데몬화하여 서비스가 필요한 작업에만 관심을 갖도록 하는 것입니다! :-)

이것이 도움이 되기를 바랍니다... 그리고 systemd가 여러분을 위해 무거운 짐을 지게 되기를 진심으로 바랍니다! 이것이 훨씬 더 효율적입니다.

답변2

daemon.service: PID file /run/daemon.pid not readable (yet?) after start: No such file or directory좋습니다. 서비스 파일에 다음 명령문을 추가한 후 오류 메시지가 사라졌습니다.

ExecStartPost=/bin/sleep 2

관련 정보