กำหนดค่าบริการ buggy systemd เพื่อยกเลิกผ่าน SIGKILL


20

พื้นหลัง

ฉันถูกขอให้สร้างsystemdสคริปต์สำหรับบริการใหม่foo_daemonซึ่งบางครั้งอาจเข้าสู่ "สถานะไม่ดี" และจะไม่ตายSIGTERM(อาจเกิดจากตัวจัดการสัญญาณที่กำหนดเอง) นี่เป็นปัญหาสำหรับนักพัฒนาเนื่องจากได้รับคำแนะนำให้เริ่ม / หยุด / เริ่มบริการใหม่ผ่าน:

  • systemctl start foo_daemon.service
  • systemctl stop foo_daemon.service
  • systemctl restart foo_daemon.service

ปัญหา

บางครั้งเนื่องจากfoo_daemonการเข้าสู่สถานะที่ไม่ดีเราต้องบังคับให้ฆ่าผ่าน:

  • systemctl kill -s KILL foo_daemon.service

คำถาม

ฉันจะตั้งค่าsystemdสคริปต์ของฉันอย่างไรfoo_daemonเพื่อที่เมื่อใดก็ตามที่ผู้ใช้พยายามหยุด / เริ่มบริการใหม่systemdจะ:

  • พยายามปิดสง่างามของผ่านfoo_daemonSIGTERM
  • ให้มากถึง 2 วินาทีเพื่อให้การปิด / การสิ้นสุดของfoo_daemonเสร็จสมบูรณ์
  • พยายามปิดการบังคับfoo_daemonผ่านSIGKILLถ้ากระบวนการยังมีชีวิตอยู่ (ดังนั้นเราจึงไม่มีความเสี่ยงที่จะมีการรีไซเคิล PID และsystemdปัญหาSIGKILLต่อ PID ที่ไม่ถูกต้อง) อุปกรณ์ที่เรากำลังทดสอบวางไข่ / แยกกระบวนการจำนวนมากอย่างรวดเร็วดังนั้นจึงมีข้อกังวลที่หายาก แต่แท้จริงเกี่ยวกับการรีไซเคิล PID ที่ก่อให้เกิดปัญหา
  • หากในทางปฏิบัติฉันแค่หวาดระแวงเกี่ยวกับการรีไซเคิล PID ฉันก็โอเคกับสคริปต์ที่ออกมาSIGKILLต่อต้านกระบวนการ 'PID โดยไม่ต้องกังวลว่าจะฆ่า PID ที่รีไซเคิลแล้ว


2
แม้ว่าคุณจะวางไข่ดำเนินการอย่างรวดเร็วพอที่จะเกลือกกลิ้ง PID มากกว่า 4 ล้านตัวภายในสองวินาที systemd ไม่ได้นั่งอยู่ในการตรวจสอบลูป "คือ pid นี้ยังมีชีวิตอยู่หรือไม่? เพราะมันไม่จำเป็นต้อง ; มีการแจ้งให้ทราบแล้วว่ากระบวนการของเด็กทันทีนั้นยังมีชีวิตอยู่หรือไม่ (ผ่าน SIGCHLD ธรรมดาและ waitpid ()) ดังนั้นหากเห็นว่ากระบวนการออกจาก SIGTERM ก็จะทำเครื่องหมายบริการเป็น 'ไม่ใช้งาน' ณ จุดนั้น - มันจะไม่รบกวนการตรวจสอบรอและส่ง SIGKILL เลย
grawity

คำตอบ:


26

systemd แล้วสนับสนุนออกจากกล่องนี้และจะมีการเปิดใช้งานโดยค่าเริ่มต้น

TimeoutStopSec=สิ่งเดียวที่คุณอาจต้องการที่จะปรับแต่งเป็นหมดเวลาที่คุณสามารถทำอะไรกับ ตัวอย่างเช่น:

[Service]
TimeoutStopSec=2

ตอนนี้ systemd จะส่ง SIGTERM รอสองวินาทีเพื่อให้บริการออกและถ้าไม่ทำก็จะส่ง SIGKILL

ถ้าบริการของคุณไม่ได้ systemd ตระหนักถึงคุณอาจจำเป็นต้องให้เส้นทางไปยังแฟ้ม PID PIDFile=ด้วย

ในที่สุดคุณพูดถึงว่าภูตของคุณเกิดกระบวนการหลายอย่าง ในกรณีนี้คุณอาจต้องการตั้งค่าKillMode=control-groupและ systemd จะส่งสัญญาณไปยังกระบวนการทั้งหมดในกลุ่ม cg


ขอขอบคุณ. คำถามสุดท้ายหนึ่งข้อสมมติว่าบริการไม่ได้เป็นระบบ ฉันสามารถเพิ่มอะไรในสคริปต์ systemd สำหรับบริการนี้เพื่อให้ systemd สร้าง / จัดการไฟล์ PID นอกจากนี้บริการสามารถเป็นหลายอินสแตนซ์ผ่านหน่วยเทมเพลตดังนั้นโดยทั่วไปเราจะเปิดบริการผ่าน `systemctl start foo_dameon@1.service" ดังนั้นจะส่งผลกระทบต่อตรรกะไฟล์ PID ในสคริปต์หรือไม่
Cloud

4
@DevNull systemd ไม่ได้สร้างหรือจัดการไฟล์ PID ไม่มีเหตุผลที่จะทำเช่นนั้น หากบริการของคุณไม่ได้สร้างไฟล์ PID ของตัวเองถ้าเป็นไปได้ให้กำหนดค่าให้รันในเบื้องหน้า (แทนที่จะเป็น daemonizing) และตั้งค่าType=simpleใน systemd unit
Michael Hampton

1
หากบริการมีผู้อยู่ในอุปการะType=forkingมีข้อได้เปรียบของ (ถ้าบริการถูกเขียนอย่างเหมาะสม) แจ้ง systemd เมื่อมันพร้อม 'สมบูรณ์' ซึ่ง Type = simple ไม่สามารถทำได้ การกำจัด Daemonizing ไม่ใช่ปัญหาแม้ไม่มีไฟล์ PID - systemd จะติดตามกระบวนการหลักต่อไป
grawity

1
@grawity จริงเพียงพอ ... ถึงแม้ว่ามันจะเป็นประสบการณ์ของฉันที่บริการให้ความรู้ก่อนที่พวกเขาจะพร้อมที่จะเริ่มให้บริการ เซอร์วิส systemd-aware ที่ใช้Type=notifyดีที่สุดสำหรับ systemd และเซอร์วิสทั่วไปจำนวนมากทำสิ่งนี้แล้ว แต่อาจไม่ใช่บริการรุ่นเก่านี้ ในกรณีของ OP เขามีบริการที่วางไข่หลายกระบวนการ เอกสาร systemd เตือนเกี่ยวกับกรณีนี้
Michael Hampton

1

เนื่องจากไม่มีใครพูดถึงความต้องการType=oneshotนี่เป็นตัวอย่างที่สมบูรณ์ซึ่งออกเนื่องจากความล้มเหลวหมดเวลา

[Unit]
Description=timeout test

[Service]
Type=oneshot
TimeoutStartSec=2
ExecStart=/bin/sleep 10
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.