Khởi động lại dịch vụ systemd khi thất bại phụ thuộc


26

Cách tiếp cận phù hợp để xử lý khởi động lại dịch vụ trong trường hợp một trong những phụ thuộc của nó không khởi động được (nhưng thành công sau khi thử lại).

Đây là một repro có ý định để làm cho vấn đề rõ ràng hơn.

a.service (mô phỏng thất bại ở lần thử đầu tiên và thành công ở lần thử thứ hai)

[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 (thành công không đáng kể sau khi A bắt đầu)

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

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

Hãy bắt đầu b:

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

Nhật ký:

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 đã được bắt đầu thành công nhưng B bị bỏ lại trong trạng thái thất bại và sẽ không thử lại.

CHỈNH SỬA

Tôi đã thêm các dịch vụ sau vào cả hai dịch vụ và bây giờ B khởi động thành công khi A bắt đầu, nhưng tôi không thể giải thích tại sao.

[Install]
WantedBy=multi-user.target

Tại sao điều này sẽ ảnh hưởng đến mối quan hệ giữa A và B?

EDIT2

Trên "sửa chữa" không hoạt động trong systemd 220.

Nhật ký gỡ lỗi 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 ']'

Nhật ký gỡ lỗi 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
Có một vấn đề hệ thống ngược dòng theo dõi này: github.com/systemd/systemd/issues/1312
JKnight

Câu trả lời:


31

Tôi sẽ cố gắng tóm tắt những phát hiện của tôi về vấn đề này trong trường hợp ai đó gặp phải vấn đề này vì thông tin về chủ đề này rất ít.

  • Restart=on-failure chỉ áp dụng cho các thất bại của quá trình (không áp dụng cho các thất bại do các lỗi phụ thuộc)
  • Thực tế là các đơn vị thất bại phụ thuộc được khởi động lại trong một số điều kiện nhất định khi khởi động lại phụ thuộc thành công là một lỗi trong systemd <220: http://lists.freedesktop.org/archives/systemd-devel/2015-July/033513.html
  • Nếu thậm chí có một cơ hội nhỏ rằng một người phụ thuộc có thể thất bại khi bắt đầu và bạn quan tâm đến khả năng phục hồi, đừng sử dụng Before/ Aftervà thay vào đó thực hiện kiểm tra một số vật phẩm mà sự phụ thuộc tạo ra

ví dụ

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

Bạn thậm chí có thể sử dụng systemctl is-active <dependecy>.

Rất hack, nhưng tôi không tìm thấy bất kỳ lựa chọn tốt hơn.

Theo tôi, không có cách nào để xử lý các thất bại phụ thuộc là một lỗ hổng trong systemd.


Có, chưa kể đến việc không thử lại các điểm gắn kết mà Leonard poetring không muốn thực hiện: github.com/systemd/systemd/issues/4468
Hvisage

0

Có vẻ như đó là thứ có thể được viết kịch bản và đưa vào một cronjob khá dễ dàng. Logic cơ bản sẽ diễn ra như thế này

  1. kiểm tra xem cả dịch vụ a và b cũng như các phụ thuộc đang chạy / ở trạng thái hợp lệ. Bạn sẽ biết cách tốt nhất để kiểm tra xem mọi thứ có hoạt động chính xác không
  2. Nếu mọi thứ đang hoạt động chính xác, không làm gì hoặc đăng nhập rằng mọi thứ đang hoạt động. Ghi nhật ký có lợi thế là cho phép bạn tìm kiếm mục nhật ký trước đó.
  3. Nếu một cái gì đó bị hỏng, khởi động lại các dịch vụ và quay trở lại phần đầu của tập lệnh nơi xảy ra kiểm tra trạng thái dịch vụ và phụ thuộc. Nhảy chỉ nên xảy ra nếu bạn tự tin vào việc khởi động lại dịch vụ và các phụ thuộc sẽ có khả năng làm việc cao, nếu không thì có khả năng xảy ra vòng lặp.
  4. Để cron chạy lại đoạn script một lát nữa

Khi tập lệnh được đặt, cron là một nơi tốt để kiểm tra nó, nếu cron không hiệu quả, tập lệnh sẽ là nơi khởi đầu tốt để thử viết một dịch vụ hệ thống cấp thấp có thể kiểm tra trạng thái của một số dịch vụ khác và khởi động lại chúng khi cần thiết. Tùy thuộc vào số lượng nỗ lực bạn muốn đầu tư tập lệnh thậm chí có thể được thiết lập để gửi email cho bạn dựa trên kết quả (trừ khi tất nhiên các dịch vụ trong câu hỏi là dịch vụ mạng).


Công cụ cronjob này nên được thực hiện trong trình quản lý quy trình / dịch vụ, nếu không bạn sẽ quay lại các phương thức SVR4, điều mà systemd cố gắng không làm ...
Hvisage

0

AfterBeforechỉ đặt thứ tự các dịch vụ sẽ được bắt đầu, các tệp dịch vụ của bạn cho biết "Nếu A và B sẽ được bắt đầu thì A phải được bắt đầu trước B".

Requires nghĩa là nếu dịch vụ này được bắt đầu, dịch vụ đó phải được bắt đầu trước, trong ví dụ của bạn "Nếu B được khởi động và A không chạy, hãy bắt đầu A"

Khi bạn thêm, WantedBy=multi-user.targetbạn hiện đang nói với hệ thống rằng các dịch vụ phải được khởi động khi hệ thống khởi tạo multi-user.target, có lẽ điều này có nghĩa là một khi bạn đã thêm nó, bạn có để hệ thống khởi động dịch vụ thay vì khởi động chúng một cách thủ công không?

Tôi không chắc tại sao điều này không hoạt động trong phiên bản 220, nó có thể đáng để thử 222. Tôi sẽ khai thác VM và thử các dịch vụ của bạn khi tôi có cơ hội.


1
Tôi đã hỏi trên systemd-devel, thực tế là nó hoạt động vào năm 219 là một lỗi. Hành vi dự định là phụ thuộc thất bại KHÔNG được khởi động lại.
Vadim

0

Tôi đã dành nhiều ngày cho việc này, cố gắng làm cho nó hoạt động theo cách "systemd", nhưng đã từ bỏ trong thất vọng và viết một kịch bản trình bao bọc để quản lý các phụ thuộc và thất bại. Mỗi dịch vụ con là một dịch vụ systemd bình thường, không có "Yêu cầu" hoặc "PartOf" hoặc bất kỳ móc nối nào với các dịch vụ khác.

Tệp dịch vụ cấp cao nhất của tôi trông như thế này:

[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

Càng xa càng tốt. Các top.serviceđiều khiển tập tin foo.servicebar.service. Bắt topđầu bắt đầu foobar, dừng lại topdừng foobar. Thành phần cuối cùng là top-service.shkịch bản của tôi theo dõi các dịch vụ cho sự thất bại:

#!/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="$@"là mã lỗi bẩm sinh - bạn đang thu gọn một mảng thành một chuỗi, loại bỏ các ranh giới ban đầu giữa các mục, do đó, đối số được tạo bởi, tức là. set -- "argument one" "argument two"trở nên giống hệt với set -- "argument" "one" "argument" "two". requires=( "$@" )sẽ giữ dữ liệu gốc, do đó có thể mở rộng một cách an toàn như systemctl is-active "${requires[@]}".
Charles Duffy

-1

Không trả lời cho điều này. Nhưng ai đó có thể cần điều này (vì trang này xuất hiện trong tìm kiếm):

nên là

[Service]
 Restart=always
 RestartSec=3

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


Xin vui lòng đọc câu hỏi cẩn thận hơn. Đây không phải là về việc khởi động lại một dịch vụ không lành mạnh, mà là về cách hệ thống hành xử khi dịch vụ bị đơn thất bại.
Vadim
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.