Systemd ฆ่าบริการทันทีหลังจากเริ่มต้น


15

ฉันกำลังเขียนไฟล์ systemd unit สำหรับ OSSEC HIDS ปัญหาคือเมื่อ systemd เริ่มให้บริการมันจะหยุดทันที

เมื่อฉันใช้ ExecStart directive นั้นทำงานได้ดี

ExecStart=/var/ossec/bin/ossec-control start

แต่เมื่อฉันทำการปรับปรุงเล็ก ๆ น้อย ๆ ฉันก็ทำได้ในบันทึก OSSEC มันจะได้รับ SIG 15 หลังจากเริ่มต้น

ExecStart=/bin/sh -c '${DIRECTORY}/bin/ossec-control start'

ถ้าฉันเปลี่ยนบริการเล็ก ๆ น้อย ๆ จะได้รับ SIG 15 หลังจาก 20 วินาที

ExecStart=/bin/sh -c '${DIRECTORY}/bin/ossec-control start && sleep 20'

ดังนั้นฉันเดาว่า systemd จะฆ่ากระบวนการ / bin / sh หลังจากเริ่มให้บริการแล้วและ bin / sh ก็จะฆ่า OSSEC

ฉันจะแก้ปัญหานี้ได้อย่างไร


1
ประเภทของบริการคืออะไร?
Wieland

@ Wieland ฉันพยายามเรียบง่ายและฟอร์ก แต่ผลลัพธ์ยังคงเหมือนเดิม
Daniil Svetlov

คำตอบ:


37

โปรโตคอลความพร้อมไม่ตรงกัน

ตามที่ Wieland บอกไว้Typeการบริการมีความสำคัญ การตั้งค่านั้นหมายถึงสิ่งที่ความพร้อมของโปรโตคอล systemd ต้องการให้บริการพูด simpleบริการจะถือว่ามีความพร้อมทันที forkingบริการจะนำไปเป็นพร้อมหลังจากขั้นตอนการเริ่มต้นของส้อมเด็กและออกแล้ว dbusบริการจะนำไปเป็นพร้อมเมื่อเซิร์ฟเวอร์จะปรากฏขึ้นบนรถประจำทางสก์ท็อป และอื่น ๆ

หากคุณไม่ได้รับโพรโทคอลเตรียมพร้อมในการประกาศในหน่วยบริการให้ตรงกับสิ่งที่บริการทำ โปรโตคอลความพร้อมไม่ตรงกันทำให้บริการไม่สามารถเริ่มทำงานได้อย่างถูกต้องหรือ (โดยปกติ) จะถูกวินิจฉัยโดย systemd ว่าผิดพลาด เมื่อบริการถูกมองว่าล้มเหลวในการเริ่มต้น systemd ทำให้มั่นใจได้ว่าทุกกระบวนการกำพร้าเพิ่มเติมของบริการที่อาจถูกปล่อยให้ทำงานอยู่เป็นส่วนหนึ่งของความล้มเหลว (จากมุมมองของมัน) ถูกฆ่าเพื่อนำบริการกลับมาอย่างไม่เหมาะสม สถานะ.

คุณทำสิ่งนี้

แรกของทุกสิ่งที่ง่าย: sh -cไม่ตรงหรือ Type=simpleType=forking

ในsimpleโปรโตคอลกระบวนการเริ่มต้นจะถูกนำไปใช้เป็นกระบวนการบริการ แต่ในความเป็นจริงsh -cเสื้อคลุมรันโปรแกรมบริการที่เกิดขึ้นจริงเป็นกระบวนการเด็ก ดังนั้นMAINPIDไปผิดและExecReloadหยุดทำงานสำหรับการเริ่ม เมื่อใช้งานType=simpleคุณจะต้องใช้งานsh -c 'exec …'หรือไม่ใช้งาน sh -cตั้งแต่แรก หลังมักจะเป็นวิธีที่ถูกต้องมากกว่าที่บางคนคิดว่า

sh -cไม่Type=forkingเหมือนกัน โปรโตคอลความพร้อมใช้งานสำหรับforkingบริการนั้นค่อนข้างเฉพาะ กระบวนการเริ่มต้นต้องแยกลูกแล้วออกจาก systemd ใช้การหมดเวลากับโปรโตคอลนี้ หากกระบวนการเริ่มต้นไม่แยกกันภายในเวลาที่กำหนดนั่นเป็นความล้มเหลวที่จะพร้อม หากกระบวนการเริ่มต้นไม่ออกภายในเวลาที่กำหนดนั่นก็เป็นความล้มเหลวเช่นกัน

ความสยองขวัญที่ไม่จำเป็นนั่นคือ ossec-control

ซึ่งนำเราไปสู่สิ่งที่ซับซ้อน: ossec-controlสคริปต์นั้น

ปรากฎว่าเป็นrcสคริปต์ระบบ 5 ที่แยกกระบวนการระหว่าง 4 และ 10 ซึ่งตัวเองอยู่ในตาเทิร์นฟอร์กและออกเช่นกัน เป็นหนึ่งในrcสคริปต์ของ System 5 ที่พยายามจัดการกระบวนการเซิร์ฟเวอร์ทั้งชุดในหนึ่งสคริปต์โดยมีforลูปเงื่อนไขการแข่งขันกฎเกณฑ์sleepเพื่อพยายามหลีกเลี่ยงโหมดความล้มเหลวที่สามารถทำให้ระบบอยู่ในสถานะเริ่มครึ่ง และความน่ากลัวอื่น ๆ ทั้งหมดที่ทำให้ผู้คนคิดค้นสิ่งต่าง ๆ เช่น AIX System Resource Controller และ daemontools เมื่อสองทศวรรษก่อน และอย่าลืมสคริปต์เชลล์ที่ซ่อนอยู่ในไดเรกทอรีไบนารีที่มันเขียนซ้ำได้ทันทีเพื่อใช้คำที่มีลักษณะเฉพาะenableและdisableคำกริยา

ดังนั้นเมื่อคุณ/bin/sh -c '/var/ossec/bin/ossec-control start'เกิดอะไรขึ้นก็คือ:

  1. systemd ส้อมสิ่งที่คาดว่าจะเป็นกระบวนการบริการ
  2. ossec-controlนั่นคือเปลือกซึ่งส้อม
  3. ในทางกลับกันส้อมระหว่าง 4 และ 10 ลูกหลาน
  4. หลานทุกคนแยกและออกในทางกลับกัน
  5. ลูกหลานที่ดีทุกคนแยกและออกจากกัน
  6. ossec-control ทางออก
  7. เชลล์แรกออก
  8. กระบวนการบริการเป็นดีลำดับของทวดหลาน แต่เป็นเพราะวิธีการทำงานของการแข่งขันนี้ค่าforking มิได้simpleโปรโตคอลพร้อม systemd พิจารณาบริการโดยรวมจะมีการล้มเหลวและปิดมันกลับลงมา

ไม่มีเรื่องสยองขวัญใด ๆ ที่เป็นสิ่งจำเป็นภายใต้ systemd เลย ไม่มีเลย

หน่วยบริการแม่แบบ systemd

แต่หนึ่งหน่วยเขียนแม่แบบที่ง่ายมาก:

[Unit]
คำอธิบาย = เซิร์ฟเวอร์ OSSEC HIDS% i
หลังจาก = network.target 

[บริการ]
type = ง่าย
ExecStartPre = / usr / bin / env / var / ossec / bin /% p-% i -t
ExecStart = / usr / bin / env / var / ossec / bin /% p-% i -f

[ติดตั้ง]
WantedBy = multi-user.target

/etc/systemd/system/ossec@.serviceบันทึกนี้นี้เป็น

บริการจริงต่าง ๆ เป็นอินสแตนซ์ของแม่แบบนี้ซึ่งมีชื่อว่า

  • ossec@dbd.service
  • ossec@agentlessd.service
  • ossec@csyslogd.service
  • ossec@execd.service
  • ossec@agentd.service
  • ossec@logcollector.service
  • ossec@syscheckd.service
  • ossec@maild.service
  • ossec@analysisd.service
  • ossec@remoted.service
  • ossec@monitord.service

จากนั้นเปิดใช้งานและปิดการใช้งานฟังก์ชั่นมาตรงจากระบบการจัดการบริการ (ด้วยRedHat bug 752774คงที่) โดยไม่จำเป็นต้องใช้เชลล์สคริปต์ที่ซ่อนอยู่

 systemctl เปิดใช้งาน ossec @ dbd ossec @ agentlessd ossec @ csyslogd ossec @ maild ossec @ execd ossec @ การวิเคราะห์ ossec @ logcollector ossec @ remote ossec @ syscheckd ossec @ monitord

ยิ่งไปกว่านั้น systemd ได้รับรู้และติดตามแต่ละบริการจริงโดยตรง journalctl -uมันสามารถกรองบันทึกของพวกเขาด้วย สามารถทราบได้เมื่อบริการส่วนบุคคลล้มเหลว มันรู้ว่าควรจะเปิดใช้งานและบริการใด

โดยวิธีการ: Type=simpleและ-fตัวเลือกอยู่ที่นี่เช่นเดียวกับในกรณีอื่น ๆ บริการน้อยมากในป่าจริงสัญญาณของพวกเขาพร้อมโดยอาศัยexitและสิ่งเหล่านี้ที่นี่ไม่ได้เช่นกัน แต่นั่นคือสิ่งที่forkingประเภทหมายถึง บริการในป่าในทางแยกและออกเพียงเพราะความผิดพลาดบางอย่างที่ได้รับความคิดภูมิปัญญาว่านั่นคือสิ่งที่dæmonsควรทำ ที่จริงแล้วมันไม่ใช่ มันไม่ได้เป็นมาตั้งแต่ปี 1990 ได้เวลาทันแล้ว

อ่านเพิ่มเติม

  • Jonathan de Boyne Pollard (2015) ปัญหาโปรโตคอลการเตรียมพร้อมกับdæmonsยูนิกซ์ คำตอบที่ได้รับบ่อย

2
คำตอบที่ละเอียดมาก! ฉันยังแนะนำให้สร้างเป้าหมาย "การจัดกลุ่ม" พูด ossec.target ซึ่งRequires=อินสแตนซ์ที่จำเป็นทั้งหมดแล้วตั้งค่าPartOf=ossec.targetใน ossec @ .service สิ่งนี้จะอนุญาตให้เริ่มและหยุด ossec โดยเริ่มต้นและหยุด ossec.target
intelfx

@JdeBP ว้าว! ขอบคุณมากสำหรับคำตอบอย่างละเอียด หวังว่าฉันจะทำหน่วยนี้และเขียนที่นี่เกี่ยวกับผลลัพธ์ ฉันว่าฉันจะง่ายขึ้น แต่คุณถูกต้อง ossec-controll เป็นนรกเริ่มต้น
Daniil Svetlov

1
เหตุผลที่ใช้ / usr / bin / env เป็น wrapper คืออะไร
Marius Gedminas

1

ให้ Type = forking และระบุตำแหน่งไฟล์ pid หาก start service / app กำลังดูแล pid ใด ๆ

[หน่วย]
คำอธิบาย = "เรียกใช้แอปขณะบู๊ต"
หลังจาก = network.target syslog.target auditd.service

[บริการ]
Type = ฟอร์ก
PIDFile = / var / run / apache2 / apache2. apid2
ExecStart = / etc / init.d / apache2 เริ่ม
ExecStop = / etc / init.d / apache2 หยุด
StandardOutput = syslog
StandardError = syslog
เริ่มต้นใหม่ = บน - ล้มเหลว
SyslogIdentifier = webappslog

[ติดตั้ง]
WantedBy = multi-user.target
Alias ​​= webapps


0

ค่อนข้างเกี่ยวข้องกับฉันฉันมีบริการ systemd ซึ่งปรากฏว่า systemd จะ "ฆ่า" หลังจาก 30s

systemctl status service-nameจะแสดงmain process exited, code=exited, status=1/FAILUREหลังจาก 30 วินาทีผ่านไป

มันจะทำงานได้ดี "ในการแยก" (เช่นใน terminal ด้วยตนเองด้วยสภาพแวดล้อมเดียวกัน )

ปรากฎว่ามันเป็น

Type=forking
...
Environment=ABC="TRUE"
ExecStart=/path/to/my_script_to_spawn_process.sh

ภายในmy_script_to_spawn_process.shมันทำ

/bin/something > /dev/null 2>&1 &

ซึ่งใช้งานได้ แต่ถูกทิ้งข้อมูลบันทึกผลลัพธ์ (โดยปกติจะเป็นไฟล์หรือถ้าไม่เช่นนั้นอาจเป็นไปได้journalctl)

เปลี่ยนเป็นล็อคอินที่อื่นเช่น /bin/something > /tmp/my_file

จากนั้นจึงปรับการ/tmp/my_fileเปิดเผยสาเหตุที่แท้จริง สิ่งใด (แทนเจนต์) ที่คุณไม่สามารถใช้ไวยากรณ์Environment=ABC="true"อย่างที่คุณสามารถทำได้ในการทุบตีมันจะต้องไม่มีเครื่องหมายอัญประกาศหรือค่าคีย์ทั้งหมดภายในเครื่องหมายคำพูดEnvironment="ABC=true"ซึ่งทำให้กระบวนการของฉันออกจาก "ในระยะการติดตั้ง" หลังจากผ่านไปประมาณ 30 วินาที


-4

โปรดทราบว่าโมเดล daemon ของ systemd นั้นง่ายและเข้ากันไม่ได้กับ daemons ที่มีอยู่จำนวนมากซึ่งทำการฟอร์กหลายตัวดำเนินการและดำเนินการ setuid'ing ที่พบบ่อยที่สุดคือ daemons ซึ่งเริ่มต้นเป็นรูทเพื่อตั้งค่าต่างๆจากนั้นสลับเป็น UID ที่มีสิทธิ์น้อยกว่าสำหรับการดำเนินการตามปกติ เช่นการเริ่มต้นไฟล์ Pid เป็นสิ่งหนึ่งที่ล้มเหลวภายใต้ systemd เนื่องจากปัญหาสิทธิ์ มีวิธีแก้ไขปัญหา (ไม่แก้ไข) แต่เอกสารไม่ดี

คำอธิบายของ JdeBP นั้นยินดีต้อนรับ แต่ก็ไม่สมบูรณ์และการเรียกร้องของเขาว่ามันเป็นความผิดทั้งหมดของ ossec-control นั้นไม่เป็นความจริง แม้กระทั่งสิ่งที่ไม่สำคัญคือปัญหาเช่นการได้รับสายบันทึกที่ไม่ได้รับการแก้ไขเพื่อแก้ปัญหาหรือข้อความแสดงข้อผิดพลาดที่มีความหมายจาก systemd เองเมื่อมันฆ่ากระบวนการ


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