รีสตาร์ทเซอร์วิส systemd เมื่อการพึ่งพาล้มเหลว


26

มีวิธีการที่เหมาะสมในการจัดการการเริ่มบริการในกรณีที่การอ้างอิงอย่างใดอย่างหนึ่งล้มเหลวเมื่อเริ่มต้น (แต่สำเร็จหลังจากลองใหม่)

นี่คือข้อผิดพลาดที่ประดิษฐ์ขึ้นเพื่อทำให้ปัญหาชัดเจนขึ้น

a.service (จำลองความล้มเหลวในการลองครั้งแรกและประสบความสำเร็จในการลองครั้งที่สอง)

[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.service (สำเร็จเล็กน้อยหลังจากเริ่ม 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 อยู่ในสถานะล้มเหลวและจะไม่ลองอีกครั้ง

แก้ไข

ฉันได้เพิ่มสิ่งต่อไปนี้ในบริการทั้งสองและตอนนี้ B ก็เริ่มต้นได้สำเร็จเมื่อ A เริ่มต้น แต่ฉันไม่สามารถอธิบายได้ว่าทำไม

[Install]
WantedBy=multi-user.target

ทำไมสิ่งนี้จะส่งผลกระทบต่อความสัมพันธ์ระหว่าง A และ B?

EDIT2

ด้านบน "แก้ไข" ไม่ทำงานใน 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
มีปัญหาอัปสตรีม systemd ติดตามสิ่งนี้: github.com/systemd/systemd/issues/1312
JKnight

คำตอบ:


31

ฉันจะพยายามสรุปสิ่งที่ค้นพบของฉันสำหรับปัญหานี้ในกรณีที่มีคนเจอเรื่องนี้เนื่องจากข้อมูลในหัวข้อนี้ขาดแคลน

  • 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


ใช่ไม่ต้องพูดถึงไม่ต้องลองใหม่สำหรับจุดเมานต์ที่กวีของลีโอนาร์ไม่ต้องการนำไปใช้: github.com/systemd/systemd/issues/4468
Hvisage

0

ดูเหมือนว่าสิ่งที่สามารถเขียนสคริปต์และใส่ลงใน cronjob ได้อย่างง่ายดาย ตรรกะพื้นฐานจะเป็นอะไรแบบนี้

  1. ตรวจสอบเพื่อดูว่าทั้งบริการ a และ b เช่นเดียวกับการพึ่งพากำลังทำงาน / ในสถานะที่ถูกต้อง คุณจะรู้วิธีที่ดีที่สุดในการตรวจสอบว่าทุกอย่างทำงานอย่างถูกต้อง
  2. หากทุกอย่างทำงานถูกต้องไม่ทำอะไรเลยหรือบันทึกว่าทุกอย่างทำงานได้ดี การบันทึกมีข้อดีคือช่วยให้คุณสามารถค้นหารายการบันทึกก่อนหน้า
  3. หากมีบางอย่างที่ไม่ถูกต้องให้เริ่มบริการใหม่และข้ามกลับไปที่จุดเริ่มต้นของสคริปต์ที่มีการตรวจสอบสถานะบริการและการพึ่งพาเกิดขึ้น การกระโดดจะเกิดขึ้นได้ก็ต่อเมื่อคุณมั่นใจในการเริ่มต้นบริการใหม่และการพึ่งพาจะมีความเป็นไปได้สูงที่จะทำงานมิฉะนั้นอาจมีโอกาสเกิดวนซ้ำ
  4. ให้ cron เรียกใช้สคริปต์อีกครั้งในอีกสักครู่

เมื่อสคริปต์ถูกตั้งค่า cron เป็นสถานที่ที่ดีในการทดสอบถ้า cron ไม่มีประสิทธิภาพสคริปต์จะเป็นจุดเริ่มต้นที่ดีสำหรับการพยายามเขียนบริการระบบระดับต่ำที่สามารถตรวจสอบสถานะของบริการอื่น ๆ และเริ่มใหม่ตามความจำเป็น ขึ้นอยู่กับจำนวนของความพยายามที่คุณต้องการลงทุนสคริปต์อาจจะตั้งค่าให้ส่งอีเมลถึงคุณตามผลลัพธ์ (เว้นแต่แน่นอนว่าบริการในคำถามคือบริการเครือข่าย)


cronjob ของสิ่งนี้ควรจะทำมากกว่าในการจัดการกระบวนการ / บริการมิฉะนั้นคุณจะไปกลับไปที่วิธีการ SVR4 ซึ่ง systemd ความพยายามที่จะไม่ทำ ...
Hvisage

0

AfterและBeforeตั้งค่าเฉพาะคำสั่งที่จะเริ่มให้บริการไฟล์บริการของคุณจะพูดว่า "ถ้า A และ B จะเริ่มขึ้น A จะต้องเริ่มต้นก่อน B"

Requires หมายความว่าหากบริการนี้จะต้องเริ่มบริการนั้นจะต้องเริ่มก่อนในตัวอย่างของคุณ "ถ้า B เริ่มทำงานแล้วและ A ไม่ทำงานให้เริ่ม A"

เมื่อคุณเพิ่มWantedBy=multi-user.targetคุณจะบอกระบบว่าบริการจะต้องเริ่มต้นเมื่อระบบเริ่มต้นmulti-user.targetสันนิษฐานว่านี้หมายความว่าเมื่อคุณเพิ่มมันคุณได้ให้ระบบเริ่มบริการแทนการเริ่มด้วยตนเอง?

ฉันไม่แน่ใจว่าทำไมมันใช้งานไม่ได้ในเวอร์ชัน 220 มันอาจจะคุ้มค่าที่จะลอง 222 ฉันจะขุด VM และลองใช้บริการของคุณเมื่อฉันมีโอกาส


1
ฉันถาม systemd-devel ความจริงที่ว่ามันทำงานใน 219 เป็นข้อผิดพลาด พฤติกรรมที่ต้องการคือไม่สามารถเริ่มต้นการพึ่งพาได้ใหม่
Vadim

0

ฉันใช้เวลาหลายวันในการพยายามทำให้มันเป็นไปตามวิธี "systemd" แต่ยอมแพ้ด้วยความหงุดหงิดและเขียนสคริปต์ตัวคลุมเพื่อจัดการการพึ่งพาและความล้มเหลว บริการลูกแต่ละบริการเป็นบริการ systemd ปกติโดยไม่มี "ต้อง" หรือ "PartOf" หรือ hooks ใด ๆ กับบริการอื่น ๆ

ไฟล์บริการระดับสูงสุดของฉันมีลักษณะเช่นนี้:

[Service]
Type=simple
Environment=REQUIRES=foo.service bar.service
ExecStartPre=/usr/bin/systemctl start $REQUIRES
ExecStart=@PREFIX@/bin/top-service.sh $REQUIRES
ExecStop=/usr/bin/systemctl      stop $REQUIRES

จนถึงตอนนี้ดีมาก top.serviceควบคุมไฟล์และfoo.service bar.serviceเริ่มต้นtopเริ่มต้นfooและbarและหยุดtopหยุดและfoo barส่วนประกอบสุดท้ายคือtop-service.shสคริปต์ของฉันที่ตรวจสอบบริการสำหรับความล้มเหลว

#!/bin/bash

# This monitors REQUIRES services. If any service stops, all of the services are stopped and this script ends.

REQUIRES="$@"

if [ "$REQUIRES" == "" ]
then
  echo "ERROR: no services listed"
  exit 1
fi

echo "INFO: watching services: ${REQUIRES}"

end=0
while [[ $end == 0 ]]
do
  s=$(systemctl is-active ${REQUIRES} )
  if echo $s | egrep '^(active ?)+$' > /dev/null
  then
    # $s has embedded newlines, but echo $s seems to get rid of them, while echo "$s" keeps them.
    # echo INFO: All active, $s
    end=0
  else
    echo "WARN: ${REQUIRES}"
    echo WARN: $s
  fi

  if [[ $s == *"failed"* ]] || [[ $s == *"unknown"* ]]
  then
    echo "WARN: At least one service is failed or unknown, ending service"
    end=1
  else
    sleep 1
  fi
done

echo "INFO: done watching services, stopping: ${REQUIRES}"
systemctl stop ${REQUIRES}
echo "INFO: stopped: ${REQUIRES}"
exit 1

REQUIRES="$@"เป็นรหัสรถบั๊กที่เกิดขึ้นภายใน - คุณกำลังยุบอาร์เรย์ลงในสตริงโดยละทิ้งขอบเขตดั้งเดิมระหว่างไอเท็มดังนั้นอาร์กิวเมนต์ที่สร้างโดยเช่น กลายเป็นไปเหมือนกันset -- "argument one" "argument two" จะเก็บข้อมูลต้นฉบับจึงสามารถขยายได้อย่างปลอดภัยดังนี้ set -- "argument" "one" "argument" "two"requires=( "$@" )systemctl is-active "${requires[@]}"
Charles Duffy

-1

ไม่ตอบคำถามนี้ แต่บางคนอาจต้องการสิ่งนี้ (เพราะหน้านี้ปรากฏขึ้นในการค้นหา):

ควรจะเป็น

[Service]
 Restart=always
 RestartSec=3

https://jonarcher.info/2015/08/ensure-systemd-services-restart-on-failure/


โปรดอ่านคำถามให้ละเอียดยิ่งขึ้น สิ่งนี้ไม่เกี่ยวกับการรีสตาร์ทบริการที่ไม่แข็งแรงเพียงอย่างเดียว แต่เกี่ยวกับการที่ systemd ทำงานเมื่อบริการของจำเลยล้มเหลว
Vadim
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.