우분투 시스템 단순(원샷)과 포크의 차이점은 무엇입니까?

우분투 시스템 단순(원샷)과 포크의 차이점은 무엇입니까?
#!/bin/bash
sleep 2
nohup java -jar /home/ubuntu/radius/radius-test.jar >> /home/ubuntu/radius/radius.log &
nohup java -jar /home/ubuntu/radius/radius-test-2.jar >> /home/ubuntu/radius/radius-2.log &

시작 시 자동으로 실행되는 위와 유사한 스크립트 파일이 있습니다.

제가 찾은 많은 방법 중에서 저는 systemd를 사용하기로 결정했고 원하는 동작을 성공적으로 얻었습니다.

그런데 Type 옵션을 지정하는 올바른 방법이 있는지, 아니면 문제가 없는지 알고 싶습니다.

[Unit]
Description=My Shell Script

[Service]
Type=simple or oneshot
RemainAfterExit=yes
ExecStart=/home/ubuntu/radius/radius-start.sh

[Install]
WantedBy=multi-user.target


---

[Unit]
Description=My Shell Script

[Service]
Type=forking
ExecStart=/home/ubuntu/radius/radius-start.sh

[Install]
WantedBy=multi-user.target

두 방법 모두 시작 시 서비스가 실행되고 내 jar 파일도 실행됩니다. 그리고 서비스는 여전히 활성화되어 있으며 jar 프로세스가 유지됩니다. 그런 다음 서비스가 종료되면 모든 jar 프로세스도 종료됩니다.

확인 결과 포크가 백그라운드 메서드에 적합하고 하위 프로세스가 실행된 다음 상위 프로세스가 종료되는 것으로 나타났습니다. (이부분도 이해가 안가네요.) 또한 pid 파일을 지정해야 하거나, fork 방식을 사용하면 안된다고 합니다.

Simple 또는 Oneshot을 사용하려면 프런트엔드 작업이 필요하다고 합니다. 하지만 내 jar 프로세스는 백그라운드에서 실행되어야 합니다.

이 두 가지 방법의 차이점은 무엇입니까? 어떤 옵션을 사용하는 것이 올바른 방법인가요?

답변1

유닛 파일의 두 가지 버전을 살펴보고 제안 사항을 보여드리겠습니다.

simple또는 oneshot서비스

[Service]
Type=oneshot
RemainAfterExit=yes
ExecStart=/home/ubuntu/radius/radius-start.sh

Type=oneshotRemainAfterExit=yes와 함께 사용하기에 더 적합합니다 Type=simple.

평소 처럼 simple달리세요 ExecStart=. 그런 다음 프로세스가 끝나면 모든 것이 정리되고 서비스가 "중지"됩니다. 그러나 radius-start.sh일부 프로세스는 시작되었다가 즉시 중지됩니다. 이는 systemd가 고아 프로세스를 찾아서 정리의 일부로 종료한다는 것을 의미합니다.

그것으로 oneshot, 그것은 정말로 달리고 ExecStart=죽는 것을 의미합니다. 이 장치가 중지될 때 명령을 RemainAfterExit=트리거하거나 관계를 활용하여 다른 장치를 중지하는 데 도움이 되는 유용한 방법을 사용할 수 있습니다 . 그러나 생성한 하위 프로세스의 최신 상태는 제공되지 않습니다.ExecStop=ConsistsOf=

이 기술의 큰 문제는 (고아가 된) 하위 프로세스를 즉시 종료하거나 하위 프로세스가 종료될 때 장치가 중지/실패했다는 사실을 이해하지 못한다는 것입니다.


forking제공하다

[Service]
Type=forking
ExecStart=/home/ubuntu/radius/radius-start.sh

이는 귀하의 서비스에 대한 올바른 버전입니다. forking이(가) 실행되고 ExecStart=곧 종료될 것으로 예상됩니다. 그런 다음 Systemd는 일부 하위 프로세스를 생성할 것으로 예상하고 이러한 하위 프로세스의 상태를 추적합니다. 기본 프로세스가 종료되면 systemd는 서비스가 중지된 것으로 간주합니다.

이 접근 방식을 고집한다면 PIDFile=systemd가 두 프로세스 중 어느 프로세스가 기본 프로세스인지 알 수 있도록 설정하는 것이 좋습니다.

[Service]
...
PIDFile=/run/myservice.pid
...
#!/bin/bash
sleep 2
nohup java -jar /home/ubuntu/radius/radius-test.jar >> /home/ubuntu/radius/radius.log &
echo $! > /run/myservice.pid
nohup java -jar /home/ubuntu/radius/radius-test-2.jar >> /home/ubuntu/radius/radius-2.log &

그러나 systemd의 문서에는 다음과 같이 명확하게 명시되어 있습니다.

최신 프로젝트에서는 PID 파일을 피해야 합니다. 서비스의 주요 프로세스를 결정하고 불필요한 포크를 피하기 위해 PID 파일을 사용할 필요가 없도록 가능하면 Type=notify 또는 Type=simple을 사용하십시오.

bash수행하려는 모든 작업이 이미 systemd에서 기본적으로 제공되므로 프로세스를 실행하기 위해 여기를 호출할 필요가 없습니다 .


말 그대로의 조언Type=simple

귀하의 서비스를 그대로 구현하려면 두 가지 서비스를 사용하여 구현하겠습니다.

# radius-test.service
[Service]
Type=simple
ExecStartPre=/bin/sleep 2
ExecStart=/usr/bin/java -jar /home/ubuntu/radius/radius-test.jar
StandardOutput=append:/home/ubuntu/radius/radius.log
# radius-test2.service
[Unit]
After=radius-test.service

[Service]
Type=simple
ExecStart=/usr/bin/java -jar /home/ubuntu/radius/radius-test-2.jar
StandardOutput=append:/home/ubuntu/radius/radius-2.log

이제 서비스 중 하나가 실패하면 어떤 서비스가 실패했는지 감지하고 복원할 수 있습니다. 이러한 서비스에 특정 관계가 필요한 경우 정의할 수 있습니다. 예를 들어, 순서 지정은 를 사용하여 구현할 수 있습니다 After=. 다른 하나가 실패할 경우 그 중 하나가 완전히 중지되도록 하려면 BindsTo=.


솔루션 개선

  • ExecStartPre=/bin/sleep 2: 이는 일반적으로 해커 공격입니다. 지연으로 인해 좋은 날에는 불필요한 지연이 발생하고 나쁜 날에는 불충분한 지연이 발생할 수 있습니다. 잠을 자야 하는 이유를 이해하는 것이 가장 좋습니다. 예를 들어, 서비스를 실행하기 전에 네트워크를 사용할 수 있도록 해야 한다면 대신 를 사용하세요 After=network.target.
  • Type=simple: 실제로는 이것이 기본값입니다. 따라서 이 줄을 제거할 수 있습니다.
  • radius-test가 시작될 때 항상 radius-test2를 실행하려면 관계를 사용하십시오(또는 Wants=' 섹션에 지정).WantedBy=radius-testradius-test2[Install]
  • 정지 중에 멈추고 싶다면 radius-test2관계를 사용하십시오.radius-testPartOf=
  • StandardOutput=append:...: 자신의 파일에 기록하는 데는 문제가 없지만 내장된 로그를 사용하는 것이 편리할 수 있습니다. 이 줄을 제거하면 로그를 얻을 수 있습니다 journalctl -u myservice.service. journalctl로그 회전, 크기 제한, 필터링 등 다양한 추가 기능을 제공합니다. 나는 종종 다음과 같은 일을 합니다.

journalctl -u myservice --since "5 hours ago" --until "4 hours ago"

개선된 버전은 다음과 같습니다.

# /etc/systemd/system/radius-test.service
[Unit]
Description=Radius Test 1
After=network.target
Before=radius-test-2
Wants=radius-test-2

[Service]
ExecStart=/usr/bin/java -jar /home/ubuntu/radius/radius-test.jar

[Install]
WantedBy=multi-user-target

# /etc/systemd/system/radius-test2.service
[Unit]
Description=Radius Test 2
PartOf=radius-test

[Service]
ExecStart=/usr/bin/java -jar /home/ubuntu/radius/radius-test-2.jar

궁극의 간단한 솔루션

StandardOutput=그러나 이제 로그를 제거 하고 사용했으므로 이를 단일 단위로 병합할 수도 있습니다. 더 간단한 해결책은 다음과 같습니다 ExecStartPost=.

# /etc/systemd/system/radius-test.service
[Unit]
Description=Radius Test
After=network.target

[Service]
ExecStart=/usr/bin/java -jar /home/ubuntu/radius/radius-test.jar
ExecStartPost=/usr/bin/java -jar /home/ubuntu/radius/radius-test-2.jar

[Install]
WantedBy=multi-user-target

관련 정보