쉘 스크립트를 가리킬 때 node.js 애플리케이션의 시스템 서비스 파일이 작동하지 않습니다.

쉘 스크립트를 가리킬 때 node.js 애플리케이션의 시스템 서비스 파일이 작동하지 않습니다.

제 질문을 언급하기 전에 시스템 관련 질문을 대부분 확인했지만 설득력 있는 답변을 찾지 못했습니다. 저는 서버를 실행하는 Nodejs 애플리케이션을 작성했습니다.

const express = require('express');
const app     = express(),
      port    = process.env.PORT || 5000;

    app.get('/' , ( req , res ) => {
        res.send('Hello World')
    })

    app.listen( port , () => {
        console.log(`The server listens on port ${port}`)
    })

처음에는 server.js를 실행하는 서비스를 만들었고 매우 원활하게 작동했습니다.

[Unit]
Description=Hello World
After=network.target

[Service]
ExecStart=/usr/bin/node /home/msimou/Desktop/helloWorld/server.js
User=msimou
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target

그러나 서비스를 시작하거나 중지하는 .sh 파일을 생성하여 동일한 작업을 시도하고 단위 파일에 포함을 시도했지만 알 수 없는 이유로 서버가 작동하지 않았습니다. 업데이트된 유닛 파일은 다음과 같습니다:

[Unit]
Description=Hello World
After=network.target

[Service]
ExecStart=/bin/bash /home/msimou/Desktop/helloWorld/init/startHelloWorld.sh
ExecStop=/bin/bash /home/msimou/Desktop/helloWorld/init/stopHelloWorld.sh
User=msimou
Restart=always
RestartSec=5

[Install]
WantedBy=multi-user.target

로그 파일을 확인하고 오류가 /var/log/syslog발생했지만 journalctl, 내가 볼 수 있는 유일한 것은 시스템이 5초 동안 지속적으로 서비스를 시작하고 중지하는 것뿐이었습니다. 를 이용해서 확인해 보니 systemctl status helloWorld.service서비스 성공 상태라고 나오는데 Nodejs 애플리케이션과 관련된 프로세스를 찾을 수 없습니다.

답변1

서비스 유형을 지정하지 않았으므로 systemd기본 서비스 유형이 사용됩니다 Type=simple.

따라서 명령이 실제 서비스 프로세스를 시작한다고 systemd가정합니다 . ExecStart자체 제어 그룹(cgroup)에서 프로세스를 시작하고 모니터링합니다. 이 프로세스의 모든 하위 프로세스는 ExecStart동일한 제어 그룹의 구성원이 됩니다.

ExecStart프로세스가 종료 되면 systemd는 이것이 서비스가 종료되었음을 의미한다고 가정합니다. 이제 실제 서비스를 시작하기 위해 스크립트를 사용하고 있으므로 이 가정은 올바르지 않습니다. 이 시점에서 서비스를 정리하기 위해 제어 그룹의 나머지 프로세스를 모두 종료합니다(실제 서비스 프로세스를 효과적으로 종료). 그런 다음 서비스를 다시 시작하려고 시도하고 루프가 반복됩니다...

스크립트를 통해 간접적으로 서비스를 시작하면 서비스를 알리지 않고도 유형별 simple로 서비스를 효과적으로 변경할 수 있습니다 . 그러나 이 장르에는 이와 관련된 추가적인 레거시 수하물도 있습니다. 또한 서비스 프로세스를 모니터링하기가 더 어려워지므로 꼭 필요한 경우가 아니면 사용하지 않는 것이 좋습니다.forkingsystemdforkingsystemd

이상적으로는 실제 서비스 프로세스의 시작 위치를 그대로 두고 ExecStart=옵션이 포함된 실제 파일이나 옵션이 참조하는 별도의 파일에 환경 변수를 지정해야 합니다. 추가 시작 명령은 및/또는 옵션이 될 수 있습니다. 이렇게 하면 해당 명령이 제공하는 기본값과 자동 프로세스 모니터링을 계속 유지할 수 있습니다. 원하는 경우 계속 서비스를 사용할 수 있습니다..serviceEnvironment=EnvironmentFile=ExecStartPre=ExecStartPost=Type=simpleExecStop=Type=simple


를 사용하면 Type=forkingsystemd는 여전히 제어 그룹을 통해 서비스를 추적합니다. 서비스가 다른 프로세스를 생성하는 경우 그 중 어느 프로세스가 서비스의 기본 프로세스인지 알 수 없으므로 적어도 PIDFile=서비스를 중지할 때 시스템에서 기본 서비스 프로세스를 먼저 종료하는 데 도움이 되는 옵션이나 다음과 같은 경우에 적합한 옵션을 제공해야 합니다. ExecStop=단순히 서비스를 맹목적으로 종료하는 것 이상의 일을 하는 것입니다.

서비스의 제어 그룹에 프로세스가 없으면 systemd서비스는 여전히 실패한 것으로 감지됩니다. 하지만 사용하거나 Type=forking사용하지 않을 경우 PIDFile=서비스의 메인 프로세스가 종료될 수 있으며, 하위 프로세스가 하나 이상 존재하는 한 장애를 감지하지 못할 수 있습니다.

프로세스가 완료되었을 때 ExecStop=서비스의 프로세스 그룹에 프로세스가 남아 있는 경우 이는 어떤 이유로 인해 정상적인 종료가 실패했음을 의미한다고 가정하며 , 그렇지 않은 경우 즉시 제어 그룹의 나머지 프로세스를 정리하는 systemd데 사용됩니다 . SIGKILL지정된 매뉴얼 페이지에 나열된 다양한 옵션을 사용합니다 systemd.kill(5).

따라서 를 사용하면 Type=simplea가 필요하지 않으며 PIDFile=서비스나 전체 시스템이 충돌하여 오래된 PID 파일이 남더라도 걱정할 필요가 없습니다.

귀하가 사용하고 귀하의 서비스가 여러 프로세스를 사용하는 경우 모니터링 목적과 필요한 경우 종료를 위해 서비스의 기본 프로세스를 올바르게 식별하는 프로세스 를 Type=forking사용해야 합니다 .PIDFile=systemd

SIGTERM서비스에 " 기본/유일한 프로세스로 보내기"보다 더 복잡한 종료 프로세스가 필요한 경우 ExecStop=무엇이든 Type=옵션을 사용하십시오. 그러나 필요한 대기/시간 초과도 처리해야 합니다. 서비스가 닫혔습니까?충분히프로세스가 ExecStop=끝나면. 이후 서비스의 제어 그룹에 남은 프로세스가 있으면 안전하게 종료할 수 있다고 가정하고 즉시 정리 systemd하는 데 사용됩니다 .SIGKILL

관련 정보