종속성이 실패하면 systemd 서비스를 다시 시작하십시오.

종속성이 실패하면 systemd 서비스를 다시 시작하십시오.

종속성 중 하나가 시작 시 실패하지만 재시도 후에 성공하는 경우 서비스 다시 시작을 처리하는 올바른 방법은 무엇입니까?

이는 문제를 더 명확하게 하기 위해 고안된 재현입니다.

서비스(시뮬레이션은 첫 번째 시도에서 실패하고 두 번째 시도에서 성공합니다.)

[Unit]
Description=A

[Service]
ExecStartPre=/bin/sh -x -c "[ -f /tmp/success ] || (touch /tmp/success && sleep 10)"
ExecStart=/bin/true
TimeoutStartSec=5
Restart=on-failure
RestartSec=5
RemainAfterExit=yes

b.서비스(A가 시작된 후 성공)

[Unit]
Description=B
After=a.service
Requires=a.service

[Service]
ExecStart=/bin/true
RemainAfterExit=yes
Restart=on-failure
RestartSec=5

b부터 시작해보자:

# systemctl start b
A dependency job for b.service failed. See 'journalctl -xe' for details.

통나무:

Jun 30 21:34:54 debug systemd[1]: Starting A...
Jun 30 21:34:54 debug sh[1308]: + '[' -f /tmp/success ']'
Jun 30 21:34:54 debug sh[1308]: + touch /tmp/success
Jun 30 21:34:54 debug sh[1308]: + sleep 10
Jun 30 21:34:59 debug systemd[1]: a.service start-pre operation timed out. Terminating.
Jun 30 21:34:59 debug systemd[1]: Failed to start A.
Jun 30 21:34:59 debug systemd[1]: Dependency failed for B.
Jun 30 21:34:59 debug systemd[1]: Job b.service/start failed with result 'dependency'.
Jun 30 21:34:59 debug systemd[1]: Unit a.service entered failed state.
Jun 30 21:34:59 debug systemd[1]: a.service failed.
Jun 30 21:35:04 debug systemd[1]: a.service holdoff time over, scheduling restart.
Jun 30 21:35:04 debug systemd[1]: Starting A...
Jun 30 21:35:04 debug systemd[1]: Started A.
Jun 30 21:35:04 debug sh[1314]: + '[' -f /tmp/success ']'

A는 성공적으로 시작되지만 B는 실패 상태이므로 재시도하지 않습니다.

편집하다

두 서비스 모두에 다음을 추가했으며 이제 A가 시작되면 B가 성공적으로 시작되지만 이유를 설명할 수 없습니다.

[Install]
WantedBy=multi-user.target

이것이 A와 B의 관계에 영향을 미치는 이유는 무엇입니까?

편집 2

위의 "수정"은 systemd 220에서는 작동하지 않습니다.

systemd 219 디버그 로그

systemd219 systemd[1]: Trying to enqueue job b.service/start/replace
systemd219 systemd[1]: Installed new job b.service/start as 3454
systemd219 systemd[1]: Installed new job a.service/start as 3455
systemd219 systemd[1]: Enqueued job b.service/start as 3454
systemd219 systemd[1]: About to execute: /bin/sh -x -c '[ -f /tmp/success ] || (touch oldcoreos
systemd219 systemd[1]: Forked /bin/sh as 1502
systemd219 systemd[1]: a.service changed dead -> start-pre
systemd219 systemd[1]: Starting A...
systemd219 systemd[1502]: Executing: /bin/sh -x -c '[ -f /tmp/success ] || (touch /tmpoldcoreos
systemd219 sh[1502]: + '[' -f /tmp/success ']'
systemd219 sh[1502]: + touch /tmp/success
systemd219 sh[1502]: + sleep 10
systemd219 systemd[1]: a.service start-pre operation timed out. Terminating.
systemd219 systemd[1]: a.service changed start-pre -> final-sigterm
systemd219 systemd[1]: Child 1502 belongs to a.service
systemd219 systemd[1]: a.service: control process exited, code=killed status=15
systemd219 systemd[1]: a.service got final SIGCHLD for state final-sigterm
systemd219 systemd[1]: a.service changed final-sigterm -> failed
systemd219 systemd[1]: Job a.service/start finished, result=failed
systemd219 systemd[1]: Failed to start A.
systemd219 systemd[1]: Job b.service/start finished, result=dependency
systemd219 systemd[1]: Dependency failed for B.
systemd219 systemd[1]: Job b.service/start failed with result 'dependency'.
systemd219 systemd[1]: Unit a.service entered failed state.
systemd219 systemd[1]: a.service failed.
systemd219 systemd[1]: a.service changed failed -> auto-restart
systemd219 systemd[1]: a.service: cgroup is empty
systemd219 systemd[1]: a.service: cgroup is empty
systemd219 systemd[1]: a.service holdoff time over, scheduling restart.
systemd219 systemd[1]: Trying to enqueue job a.service/restart/fail
systemd219 systemd[1]: Installed new job a.service/restart as 3718
systemd219 systemd[1]: Installed new job b.service/restart as 3803
systemd219 systemd[1]: Enqueued job a.service/restart as 3718
systemd219 systemd[1]: a.service scheduled restart job.
systemd219 systemd[1]: Job b.service/restart finished, result=done
systemd219 systemd[1]: Converting job b.service/restart -> b.service/start
systemd219 systemd[1]: a.service changed auto-restart -> dead
systemd219 systemd[1]: Job a.service/restart finished, result=done
systemd219 systemd[1]: Converting job a.service/restart -> a.service/start
systemd219 systemd[1]: About to execute: /bin/sh -x -c '[ -f /tmp/success ] || (touch oldcoreos
systemd219 systemd[1]: Forked /bin/sh as 1558
systemd219 systemd[1]: a.service changed dead -> start-pre
systemd219 systemd[1]: Starting A...
systemd219 systemd[1]: Child 1558 belongs to a.service
systemd219 systemd[1]: a.service: control process exited, code=exited status=0
systemd219 systemd[1]: a.service got final SIGCHLD for state start-pre
systemd219 systemd[1]: About to execute: /bin/true
systemd219 systemd[1]: Forked /bin/true as 1561
systemd219 systemd[1]: a.service changed start-pre -> running
systemd219 systemd[1]: Job a.service/start finished, result=done
systemd219 systemd[1]: Started A.
systemd219 systemd[1]: Child 1561 belongs to a.service
systemd219 systemd[1]: a.service: main process exited, code=exited, status=0/SUCCESS
systemd219 systemd[1]: a.service changed running -> exited
systemd219 systemd[1]: a.service: cgroup is empty
systemd219 systemd[1]: About to execute: /bin/true
systemd219 systemd[1]: Forked /bin/true as 1563
systemd219 systemd[1]: b.service changed dead -> running
systemd219 systemd[1]: Job b.service/start finished, result=done
systemd219 systemd[1]: Started B.
systemd219 systemd[1]: Starting B...
systemd219 systemd[1]: Child 1563 belongs to b.service
systemd219 systemd[1]: b.service: main process exited, code=exited, status=0/SUCCESS
systemd219 systemd[1]: b.service changed running -> exited
systemd219 systemd[1]: b.service: cgroup is empty
systemd219 sh[1558]: + '[' -f /tmp/success ']'

systemd 220 디버그 로그

systemd220 systemd[1]: b.service: Trying to enqueue job b.service/start/replace
systemd220 systemd[1]: a.service: Installed new job a.service/start as 4846
systemd220 systemd[1]: b.service: Installed new job b.service/start as 4761
systemd220 systemd[1]: b.service: Enqueued job b.service/start as 4761
systemd220 systemd[1]: a.service: About to execute: /bin/sh -x -c '[ -f /tmp/success ] || (touch /tmp/success && sleep 10)'
systemd220 systemd[1]: a.service: Forked /bin/sh as 2032
systemd220 systemd[1]: a.service: Changed dead -> start-pre
systemd220 systemd[1]: Starting A...
systemd220 systemd[2032]: a.service: Executing: /bin/sh -x -c '[ -f /tmp/success ] || (touch /tmp/success && sleep 10)'
systemd220 sh[2032]: + '[' -f /tmp/success ']'
systemd220 sh[2032]: + touch /tmp/success
systemd220 sh[2032]: + sleep 10
systemd220 systemd[1]: a.service: Start-pre operation timed out. Terminating.
systemd220 systemd[1]: a.service: Changed start-pre -> final-sigterm
systemd220 systemd[1]: a.service: Child 2032 belongs to a.service
systemd220 systemd[1]: a.service: Control process exited, code=killed status=15
systemd220 systemd[1]: a.service: Got final SIGCHLD for state final-sigterm.
systemd220 systemd[1]: a.service: Changed final-sigterm -> failed
systemd220 systemd[1]: a.service: Job a.service/start finished, result=failed
systemd220 systemd[1]: Failed to start A.
systemd220 systemd[1]: b.service: Job b.service/start finished, result=dependency
systemd220 systemd[1]: Dependency failed for B.
systemd220 systemd[1]: b.service: Job b.service/start failed with result 'dependency'.
systemd220 systemd[1]: a.service: Unit entered failed state.
systemd220 systemd[1]: a.service: Failed with result 'timeout'.
systemd220 systemd[1]: a.service: Changed failed -> auto-restart
systemd220 systemd[1]: a.service: cgroup is empty
systemd220 systemd[1]: a.service: Failed to send unit change signal for a.service: Transport endpoint is not connected
systemd220 systemd[1]: a.service: Service hold-off time over, scheduling restart.
systemd220 systemd[1]: a.service: Trying to enqueue job a.service/restart/fail
systemd220 systemd[1]: a.service: Installed new job a.service/restart as 5190
systemd220 systemd[1]: a.service: Enqueued job a.service/restart as 5190
systemd220 systemd[1]: a.service: Scheduled restart job.
systemd220 systemd[1]: a.service: Changed auto-restart -> dead
systemd220 systemd[1]: a.service: Job a.service/restart finished, result=done
systemd220 systemd[1]: a.service: Converting job a.service/restart -> a.service/start
systemd220 systemd[1]: a.service: About to execute: /bin/sh -x -c '[ -f /tmp/success ] || (touch /tmp/success && sleep 10)'
systemd220 systemd[1]: a.service: Forked /bin/sh as 2132
systemd220 systemd[1]: a.service: Changed dead -> start-pre
systemd220 systemd[1]: Starting A...
systemd220 systemd[1]: a.service: Child 2132 belongs to a.service
systemd220 systemd[1]: a.service: Control process exited, code=exited status=0
systemd220 systemd[1]: a.service: Got final SIGCHLD for state start-pre.
systemd220 systemd[1]: a.service: About to execute: /bin/true
systemd220 systemd[1]: a.service: Forked /bin/true as 2136
systemd220 systemd[1]: a.service: Changed start-pre -> running
systemd220 systemd[1]: a.service: Job a.service/start finished, result=done
systemd220 systemd[1]: Started A.
systemd220 systemd[1]: a.service: Child 2136 belongs to a.service
systemd220 systemd[1]: a.service: Main process exited, code=exited, status=0/SUCCESS
systemd220 systemd[1]: a.service: Changed running -> exited
systemd220 systemd[1]: a.service: cgroup is empty
systemd220 systemd[1]: a.service: cgroup is empty
systemd220 systemd[1]: a.service: cgroup is empty
systemd220 systemd[1]: a.service: cgroup is empty
systemd220 sh[2132]: + '[' -f /tmp/success ']'

답변1

이 주제에 대한 정보가 거의 없기 때문에 다른 사람이 이 문제에 직면할 경우를 대비하여 이 문제에 대한 제가 찾은 내용을 요약하려고 합니다.

  • Restart=on-failure프로세스 실패에만 적용 (종속성 실패로 인한 실패에는 적용되지 않음)
  • 종속성이 성공적으로 다시 시작되면 특정 조건에서 실패한 종속성이 있는 장치가 다시 시작되었습니다. systemd <220의 버그: http://lists.freedesktop.org/archives/systemd-devel/2015-July/033513.html
  • 시작 시 종속성이 실패할 가능성이 적고 복원력이 중요하다면 Before/를 사용하지 말고 After대신 종속성에 의해 생성된 일부 아티팩트를 확인하세요.

예를 들어

ExecStartPre=/usr/bin/test -f /some/thing
Restart=on-failure
RestartSec=5s

를 사용할 수도 있습니다 systemctl is-active <dependecy>.

매우 해키지만 아직 더 나은 옵션을 찾지 못했습니다.

제 생각에는 종속성 오류를 처리할 수 있는 방법이 없는 것은 systemd의 결함입니다.

답변2

이는 쉽게 스크립트를 작성하여 cronjob에 넣을 수 있는 것처럼 보입니다. 기본적인 논리는 이렇습니다

  1. 서비스 a와 b 및 종속성이 실행 중이거나 유효한 상태인지 확인하세요. 모든 것이 제대로 작동하는지 확인하는 가장 좋은 방법을 알게 될 것입니다.
  2. 모든 것이 정상이면 아무것도 하지 않거나 모든 것이 정상임을 기록하십시오. 로깅의 장점은 이전 로그 항목을 찾을 수 있다는 것입니다.
  3. 문제가 발생하면 서비스를 다시 시작하고 서비스 및 종속성 상태 확인을 수행하는 스크립트의 시작 부분으로 돌아갑니다. 점프는 서비스를 다시 시작하고 종속성이 작동할 가능성이 높다고 확신하는 경우에만 발생해야 합니다. 그렇지 않으면 루프가 발생할 수 있습니다.
  4. cron이 나중에 스크립트를 다시 실행하도록 하세요.

스크립트가 설정되면 cron은 이를 테스트하기에 좋은 장소이며, cron이 비효율적이라면 스크립트는 다른 서비스의 상태를 확인할 수 있는 낮은 수준의 시스템 서비스를 작성하기 위한 좋은 시작점이 될 것입니다. 필요에 따라 서비스를 다시 시작합니다. 얼마나 많은 노력을 기울이고 싶은지에 따라 결과에 따라 이메일을 보내도록 스크립트를 설정할 수도 있습니다(물론 해당 서비스가 웹 서비스인 경우는 제외).

답변3

After그리고 Before서비스가 시작되는 순서를 설정하면 서비스 파일에 "A와 B가 시작하려면 A가 B보다 먼저 시작해야 합니다"라고 표시됩니다.

Requires이 서비스를 시작하려면 먼저 시작해야 함을 의미합니다. 예에서 "B가 시작되고 A가 실행되고 있지 않으면 A를 시작합니다"

이를 추가하면 WantedBy=multi-user.target이제 시스템이 초기화될 때 서비스를 시작해야 한다고 시스템에 알리는 것입니다. multi-user.target아마도 서비스를 추가하면 수동으로 시작하는 대신 시스템이 서비스를 시작하도록 허용한다는 의미일까요?

왜 이것이 버전 220에서 작동하지 않는지 잘 모르겠습니다. 222를 시도해 볼 가치가 있을 것입니다. 기회가 되면 가상 머신을 파헤쳐 서비스를 시도해 보겠습니다.

답변4

https://github.com/systemd/systemd/issues/1312#issuecomment-1139234399

관심이 없지만 Upholds=커밋에 새로운 것이 도입됩니까?0bc488cPR #19322의 내용이 여기에 도움이 됩니까?

특히 b.service구성에 Wants=a.serviceAfter=a.service및 이 있다고 가정합니다 Restart=on-failure. 그런 다음 a.service시작 시 시간 초과가 발생하여 b.service실패하고 표시됩니다 b.service/start failed with result 'dependency'. 다음으로 a.service재부팅은 성공하지만 b.service시작되지 않습니다. 분명히 종속성 실패는 스키마에 의한 트리거로 간주되지 않기 때문입니다 Restart=on-failure.

(이미 연결된 Stack Exchange에 보고된 내용이 바로 이것입니다.질문답변 의견 중 하나도 이 질문으로 다시 연결됩니다. )

이 오랜 문제가 발생한 후 이 지시문이 ? 로 지정되고 구성 Upholds=되면 영향을 미치는지 궁금합니다. 이것이 마침내 출시되면 출시로 이어질까요 ?a.serviceUpholds=b.serviceb.servicea.service

systemd를 다음으로 업그레이드할 수 있는 경우v254반품시험해 보세요 RestartMode=direct:https://www.freedesktop.org/software/systemd/man/latest/systemd.service.html#RestartMode=

관련 정보