systemd init 스크립트는 작업 디렉토리를 생성합니다

systemd init 스크립트는 작업 디렉토리를 생성합니다

요청 시 프로그램을 실행하기 위한 시스템 스크립트를 만들고 있습니다. 실행하면 작업 디렉토리가 존재하지 않을 수 있습니다. 따라서 이 디렉터리를 스크립트의 일부로 만들고 싶습니다. 그러나 지정된 작업 디렉터리가 존재하지 않기 때문에 오류가 발생합니다.

[Service]
User=Inplant
Group=Inplant
ExecStartPre=/bin/mkdir -p /home/inplant/IPSdevice/JAI1
WorkingDirectory=~/IPSdevice/JAI1
ExecStart=~/IPSdevice JAI1 

시스템 스크립트의 일부로 작업 디렉토리를 생성하는 방법이 있습니까? 다음과 같은 프로그램을 실행하고 싶습니다.

mkdir ~/IPSdevice/JAI1; cd ~/IPSdevice/JAI1; ~/IPSdevice JAI1

물결표를 경로로 변경하여 첫 번째 문제를 해결할 수 있었습니다. 이제 다른 문제가 생겼습니다.

    Aug 06 09:48:53 ubuntu systemd[1]: Started JAI Device Service.
-- Subject: Unit app-ips-jai1.service has finished start-up
-- Defined-By: systemd
-- Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
-- 
-- Unit app-ips-jai1.service has finished starting up.
-- 
-- The start-up result is done.
Aug 06 09:48:53 ubuntu systemd[103782]: app-ips-jai1.service: Failed at step CHDIR spawning /home/inplant/IPSdevice/IPSdevice: No such file or directory
-- Subject: Process /home/inplant/IPSdevice/IPSdevice could not be executed
-- Defined-By: systemd
-- Support: http://lists.freedesktop.org/mailman/listinfo/systemd-devel
-- 
-- The process /home/inplant/IPSdevice/IPSdevice could not be executed and failed.
-- 
-- The error number returned by this process is 2.

시스템 스크립트는 다음과 같습니다.

[Unit]
Description=JAI Device Service
# When systemd stops or restarts the app.service, the action is propagated to this unit
PartOf=app.service
# Start this unit after the app.service start
After=app-ips.service

[Service]
# Pretend that the component is running
RuntimeDirectory=IPS-JAI1
User=inplant
Group=inplant
ExecStartPre=mkdir -p /home/inplant/IPSdevice/JAI1
WorkingDirectory=/home/inplant/IPSdevice/JAI1
#ExecStart=/home/inplant/IPSdevice JAI1 > /dev/nul 2>&1 & echo $! > /var/run/jai1.pid
ExecStart=/home/inplant/IPSdevice/IPSdevice JAI1
# Restart the service on non-zero exit code when terminated by a signal other than SIGHUP, SIGINT, SIGTERM or SIGPIPE
#Restart=on-failure

[Install]
# This unit should start when app.service is starting
WantedBy=app-ips.service

일반적으로 "inplant" 사용자로 로그인하고 다음 명령을 실행하여 서비스를 시작합니다.

cd ~/IPSdevice
mkdir -p JAI
cd JAI
../IPSdevice JAI

답변1

문제의 일부는 ~확장되지 않는 systemd를 사용하고 ~있으므로 ~user명령에 전체 경로를 지정해야 한다는 것입니다.

또한 systemd가 명령을 실행하기 전에 확인 하기 때문에 실제로 디렉터리를 만든 ExecStartPre=다음 사용할 수 없습니다 . (실제로 모든 명령은 동일한 디렉터리에서 실행됩니다.)WorkingDirectory=WorkingDirectory=ExecStartPre=

이를 달성하려면 쉘 스크립트를 사용하여 ExecStart=환경과 exec데몬을 준비하십시오.

예를 들어 다음을 하나 생성합니다 /home/inplant/start_inplant.sh.

#!/bin/sh
set -eu
mkdir -p /home/inplant/IPSdevice/"$1"
cd /home/inplant/IPSdevice/"$1"
exec /home/inplant/IPSdevice/IPSdevice "$1"

유닛 파일에서 다음을 사용하십시오.

[제공하다]
런타임 디렉터리=IPS-JAI1
사용자=생체 내
그룹=임플란트
환경=LD_LIBRARY_PATH=/opt/pleora/ebus_sdk/Ubuntu-x86_64/lib:/opt/pleora/ebus_sdk/Ubuntu-x86_64/lib/genicam/bin/Linux64_x64:/opt/xview2_64/lib/:/opt/GO_SDK/lib /linux_x64
환경=GENICAM_ROOT_V3_0=/opt/pleora/ebus_sdk/Ubuntu-x86_64/lib/genicam
ExecStart=/home/inplant/start_inplant.sh JAI1
# SIGHUP, SIGINT, SIGTERM 또는 SIGPIPE 이외의 신호에 의해 종료되면 0이 아닌 종료 코드로 서비스를 다시 시작합니다.
다시 시작 = 실패 시

필요하지 않거나 WorkingDirectory=단위 ExecStartPre=파일에 없습니다. 쉘 스크립트 자체에서 환경 변수를 내보내도록 결정할 수도 있으며, 둘 중 하나를 선호하는지 여부는 사용자에게 달려 있습니다.

중요한 부분은 사용하는 것입니다exec쉘 스크립트에서. 이로 인해 쉘은 자신을 실행 프로그램으로 대체하여 프로그램은 쉘이 시작될 때와 동일한 PID에서 실행됩니다. 이는 systemd가 해당 PID를 사용하여 데몬을 제어하므로(예: 서비스 중지 시 데몬 종료) 쉘 스크립트가 아닌 데몬이 되기를 원하기 때문에 중요합니다. 또한 아무런 이유 없이 공간만 차지하는 추가 셸 프로세스가 실행되는 것을 원하지 않습니다.

참고로 당신은 실제로할 수 있는~쉘 스크립트 에서 사용하십시오 start_inplant.sh. 이는 쉘 스크립트이기 때문에 쉘이 일반적으로 수행하는 모든 확장을 허용하고 수행합니다.


이 질문에 대한 다른 답변을 참고해 주세요.

이것은 실제로 작동하지 않습니다.

ExecStartPre=cd /home/inplant/IPSdevice/JAI1

systemd는 실제로 쉘 명령을 실행하지 않습니다(그리고 cd내장 쉘입니다.) 이것은 /bin/cd또는 /usr/bin/cd바이너리가 있는 경우에만 작동하지만 그런 것은 없습니다(디렉토리 변경은 현재 프로세스에만 영향을 미치므로 외부 바이너리는 그렇지 않습니다) 그 자체에만 영향을 미치고 종료되므로 그 효과를 볼 수 없기 때문에 의미가 있습니다.)

셸을 사용하여 명시적으로 명령을 실행하는 경우에도 다음과 같습니다.

ExecStartPre=/bin/sh -c "cd /home/inplant/IPSdevice/JAI1"

이것은 현재 쉘에만 영향을 미치고 디렉토리 변경의 효과는 다른 명령, 특히 이 ExecStart=명령에 전파되지 않기 때문에 작동하지 않습니다.

무슨 일인지 모르겠어요업무 문서ExecStartPre=왜냐하면 명령이 실패하면 systemd는 실제로 단위 파일을 실행하지 않기 때문입니다 .할 수 있다systemd는 구문이 올바르지 않다고 생각하기 때문에(최신 버전까지 systemd 버전에서는 실행하는 명령에 대한 전체 경로가 필요함) 이 줄을 무시하고 기록하며 해당 줄을 건너뛰고 다음 줄로 이동합니다.

만약 그렇다면, 당신의 데몬은 실행 중이고 /home/inplant/IPSdevice/그렇지 않은 것입니다. /home/inplant/IPSdevice/JAI1/아마도 그곳에서는 잘 작동할 것입니다. 데몬(특히 잘 작성된 데몬)은 자신이 시작하는 디렉토리의 어떤 데몬에 관심이 없기 때문에 놀라지 않을 것입니다. 따라서 아마도 이 요구 사항이 있을 것입니다. 애초에 존재하지 않습니다.

또한 이 명령은 다음과 같습니다.

ExecStartPre=/bin/chown inplant.inplant /home/inplant/IPSdevice/JAI1

기본적으로 명령은 ExecStartPre=지정된 자격 증명으로 실행되므로 해당 사용자로 이미 디렉터리를 생성했기 때문에 불필요해야 합니다(특히 이는 사용자에게 디렉터리를 생성할 수 있는 권한이 필요함을 의미함). 소유권 변경 . 이는 이미 생성된 디렉터리의 소유권이어야 하기 때문입니다.User=Group=mkdirinplant

답변2

물결표는 셸별 확장이지만 단위 파일에 지정된 지침은 셸에서 실행되지 않습니다. ~디렉터리의 절대 경로로 바꿔야 합니다 . Systemd는 이라는 작업 디렉터리를 찾고 있습니다 ~/IPSDevice/JAI1.

답변3

ExecStartPre가 작업 디렉터리를 생성하더라도 존재하지 않는 디렉터리로 설정할 수 없다는 사실을 발견했습니다. 디렉터리를 생성한 후 해당 디렉터리로 변경하려면 ExecStartPre 지시문에서 cd를 사용해야 합니다. 작업 문서는 다음과 같습니다.

[Unit]
Description=JAI Device Service
# When systemd stops or restarts the app.service, the action is propagated to this unit
PartOf=app.service
# Start this unit after the app.service start
After=app-ips.service

[Service]
RuntimeDirectory=IPS-JAI1
User=inplant
Group=inplant
Environment=LD_LIBRARY_PATH=/opt/pleora/ebus_sdk/Ubuntu-x86_64/lib:/opt/pleora/ebus_sdk/Ubuntu-x86_64/lib/genicam/bin/Linux64_x64:/opt/xview2_64/lib/:/opt/GO_SDK/lib/linux_x64
Environment=GENICAM_ROOT_V3_0=/opt/pleora/ebus_sdk/Ubuntu-x86_64/lib/genicam
ExecStartPre=/bin/mkdir -p /home/inplant/IPSdevice/JAI1
ExecStartPre=/bin/chown inplant.inplant /home/inplant/IPSdevice/JAI1
ExecStartPre=cd /home/inplant/IPSdevice/JAI1
ExecStartPre=/bin/ls -al /home/inplant/IPSdevice/JAI1
WorkingDirectory=/home/inplant/IPSdevice/
ExecStart=/home/inplant/IPSdevice/IPSdevice JAI1
# Restart the service on non-zero exit code when terminated by a signal other than SIGHUP, SIGINT, SIGTERM or SIGPIPE
Restart=on-failure

[Install]
# This unit should start when app.service is starting
WantedBy=app-ips.service
```

관련 정보