Systemd membunuh layanan segera setelah memulai


14

Saya sedang menulis file unit systemd untuk OSSEC HIDS. Masalahnya adalah bahwa ketika systemd memulai layanan segera menghentikan mereka.

Ketika saya menggunakan petunjuk ExecStart itu semua berfungsi dengan baik.

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

Tetapi ketika saya melakukan perbaikan kecil saya baik-baik saja di log OSSEC, bahwa ia menerima SIG 15 setelah memulai.

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

Jika saya membuat layanan perubahan kecil lainnya akan menerima SIG 15 setelah 20 detik.

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

Jadi, saya kira, systemd itu membunuh proses / bin / sh setelah layanan dimulai, dan bin / sh kemudian membunuh OSSEC.

Bagaimana saya bisa menyelesaikan masalah ini?


1
Apa jenis layanannya?
Wieland

@Wieland, saya mencoba yang sederhana dan forking, tetapi hasilnya masih sama.
Daniil Svetlov

Jawaban:


36

protokol kesiapan tidak cocok

Seperti yang ditunjukkan Wieland, Typelayanan ini penting. Pengaturan itu menunjukkan apa protokol sistem kesiapan dan mengharapkan layanan untuk berbicara. Suatu simplelayanan diasumsikan segera siap. Sebuah forkinglayanan diambil untuk siap setelah proses awal garpu anak dan kemudian keluar. Sebuah dbuslayanan diambil untuk siap ketika server muncul di Desktop Bus. Dan seterusnya.

Jika Anda tidak mendapatkan protokol kesiapan yang dinyatakan dalam unit layanan untuk cocok dengan apa yang dilakukan layanan, maka semuanya akan serba salah. Ketidakcocokan protokol kesiapan menyebabkan layanan tidak dimulai dengan benar, atau (lebih sering) didiagnosis oleh sistemd sebagai gagal. Ketika suatu layanan dianggap gagal untuk memulai systemd memastikan bahwa setiap proses tambahan yatim piatu dari layanan yang mungkin dibiarkan berjalan sebagai bagian dari kegagalan (dari sudut pandangnya) terbunuh untuk membawa layanan dengan benar kembali ke yang tidak aktif. negara.

Anda melakukan ini dengan tepat.

Pertama-tama, hal-hal sederhana: sh -ctidak cocok Type=simpleatau Type=forking.

Dalam simpleprotokol, proses awal diambil sebagai proses layanan. Tetapi pada kenyataannya sh -cpembungkus menjalankan program layanan yang sebenarnya sebagai proses anak . Jadi MAINPIDsalah dan ExecReloadberhenti bekerja, untuk pemula. Saat menggunakan Type=simple, seseorang harus menggunakan sh -c 'exec …'atau tidak menggunakan sh -c di tempat pertama. Yang terakhir lebih sering merupakan jalan yang benar daripada yang dipikirkan beberapa orang.

sh -cjuga tidak cocok Type=forking. Protokol kesiapan untuk suatu forkinglayanan cukup spesifik. Proses awal harus memotong seorang anak, dan kemudian keluar. systemd menerapkan batas waktu untuk protokol ini. Jika proses awal tidak bercabang dalam waktu yang ditentukan, itu gagal untuk siap. Jika proses awal tidak keluar dalam waktu yang ditentukan, itu juga merupakan kegagalan.

horor yang tidak perlu itu ossec-control

Yang membawa kita ke hal-hal kompleks: ossec-controlnaskah itu.

Ternyata itu adalah rcskrip System 5 yang memotong antara 4 dan 10 proses, yang pada gilirannya mereka garpu dan keluar juga. Ini adalah salah satu rcskrip System 5 yang berupaya mengelola seluruh rangkaian proses server dalam satu skrip tunggal, dengan forloop, kondisi balapan, arbitrary sleepuntuk mencoba menghindarinya, mode kegagalan yang dapat mencekik sistem dalam keadaan setengah-mulai, dan semua kengerian lain yang membuat orang menemukan hal-hal seperti AIX System Resource Controller dan daemontools dua dekade lalu. Dan jangan lupa skrip shell tersembunyi dalam direktori biner yang ditulis ulang dengan cepat, untuk mengimplementasikan idiosyncratic enabledan disablekata kerja.

Jadi ketika Anda /bin/sh -c '/var/ossec/bin/ossec-control start'yang terjadi adalah:

  1. systemd melakukan apa yang diharapkan sebagai proses layanan.
  2. Itu shell, yang bercabang ossec-control.
  3. Itu pada gilirannya bercabang antara 4 dan 10 cucu.
  4. Cucu-cucu semuanya bercabang dan keluar secara bergantian.
  5. Cicit buyut semuanya bercabang dan keluar secara paralel.
  6. ossec-control keluar.
  7. Shell pertama keluar.
  8. Proses layanan adalah besar-besar- cucu, tetapi karena cara ini pertandingan bekerja baik dalam forking maupun para simpleprotokol kesiapan, systemd menganggap layanan secara keseluruhan telah gagal dan menutup ke mundur.

Tak satu pun dari kengerian ini benar-benar diperlukan di bawah systemd sama sekali. Tidak satu pun.

unit layanan template systemd

Sebagai gantinya, seseorang menulis unit template yang sangat sederhana :

[Satuan]
Deskripsi = Server OSSEC HIDS% i
Setelah = network.target 

[Layanan]
Ketik = sederhana
ExecStartPre = / usr / bin / env / var / ossec / bin /% p-% i -t
ExecStart = / usr / bin / env / var / ossec / bin /% p-% i -f

[Install]
WantedBy = multi-user.target

Simpan ini sebagai /etc/systemd/system/ossec@.service.

Berbagai layanan aktual adalah contoh dari template ini, dinamai:

  • 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

Kemudian aktifkan dan nonaktifkan fungsi datang langsung dari sistem manajemen layanan (dengan RedHat bug 752774 diperbaiki), tanpa perlu skrip shell tersembunyi.

 systemctl mengaktifkan ossec @ dbd ossec @ agentlessd ossec @ csyslogd ossec @ maild ossec @ execd ossec @ analysisd ossec @ logcollector ossec @ dibuat-buat ossec @ syscheckd ossec @ monitord

Selain itu, systemd mengetahui, dan melacak, setiap layanan aktual secara langsung. Itu dapat menyaring log mereka dengan journalctl -u. Ia dapat mengetahui kapan suatu layanan individual gagal. Ia tahu layanan apa yang seharusnya diaktifkan dan dijalankan.

Omong-omong: Type=simpledan -fpilihannya ada di sini seperti halnya dalam banyak kasus lainnya. Sangat sedikit layanan di alam yang benar - benar memberi sinyal kesiapan mereka karena exit, dan ini di sini juga tidak seperti itu. Tapi itulah yang dimaksud dengan forkingtipenya. Layanan di alam liar hanya bercabang-cabang dan keluar karena beberapa anggapan yang salah diterima bahwa itulah yang seharusnya dilakukan para demon. Sebenarnya tidak. Belum sejak tahun 1990-an. Sudah waktunya untuk mengejar ketinggalan.

Bacaan lebih lanjut


2
Jawaban yang sangat rinci! Saya juga menyarankan untuk membuat target "pengelompokan", katakanlah, ossec.target, yang Requires=merupakan semua instance yang diperlukan, dan kemudian atur PartOf=ossec.targetdi ossec @ .service. Ini akan memungkinkan untuk memulai dan menghentikan ossec dengan memulai dan menghentikan ossec.target.
intelfx

@ JdeBP, wow! Terima kasih banyak atas jawaban terperinci semacam itu. Berharap saya akan membuat unit ini dan menulis di sini tentang hasil. Namun, saya akan lebih mudah. Tapi Anda benar, kontrol ossec adalah neraka.
Daniil Svetlov

1
Apa alasan menggunakan / usr / bin / env sebagai pembungkus?
Marius Gedminas

1

Simpan Type = forking dan berikan lokasi file pid jika layanan awal / aplikasi mempertahankan pid apa pun.

[Unit]
Deskripsi = "Jalankan aplikasi saat boot"
Setelah = network.target syslog.target auditd.service

[Layanan]
Jenis = forking
PIDFile = / var / run / apache2 / apache2.pid
ExecStart = / etc / init.d / apache2 start
ExecStop = / etc / init.d / apache2 berhenti
StandardOutput = syslog
StandardError = syslog
Restart = on-failure
SyslogIdentifier = webappslog

[Instal]
WantedBy = multi-user.target
Alias ​​= webapps


0

Agak terkait, saya memiliki layanan systemd yang tampaknya systemd akan "membunuhnya" setelah 30-an.

systemctl status service-nameakan ditampilkan main process exited, code=exited, status=1/FAILUREsetelah 30-an telah berlalu.

Ini akan berjalan dengan baik "dalam isolasi" (seperti secara manual di terminal dengan lingkungan yang sama ).

Ternyata itu tadi

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

di my_script_to_spawn_process.shdalamnya sedang melakukan

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

yang berfungsi tetapi membuang informasi log keluaran (biasanya ia pergi ke file, atau, jika tidak, mungkin journalctl).

Mengubahnya untuk masuk ke tempat lain seperti /bin/something > /tmp/my_file

kemudian membuntuti /tmp/my_filemengungkapkan penyebab sebenarnya. Yang mana (secara tangensial) bahwa Anda tidak dapat menggunakan sintaksis Environment=ABC="true"seperti yang Anda dapat dalam bash, itu harus ada tanda kutip atau nilai kunci semua dalam tanda kutip seperti Environment="ABC=true"yang menyebabkan proses saya untuk keluar "dalam tahap setup" setelah sekitar 30-an.


-4

Perhatikan bahwa model daemon systemd sederhana dan tidak kompatibel dengan banyak daemon yang ada yang melakukan banyak forking, exec'ing dan setuid'ing. Paling umum adalah daemon yang dimulai sebagai root untuk mengatur segalanya dan kemudian beralih ke UID yang kurang istimewa untuk operasi rutin. misalnya inisialisasi file Pid adalah satu hal yang gagal di bawah systemd karena masalah hak istimewa. Ada beberapa solusi (bukan perbaikan) tetapi didokumentasikan dengan buruk.

Penjelasan JdeBP disambut baik tetapi tidak lengkap dan klaimnya bahwa semua kesalahan kontrol ossec sama sekali tidak benar. Bahkan hal-hal sepele cukup bermasalah misalnya mendapatkan baris log yang tidak terputus untuk debug masalah atau pesan kesalahan yang bermakna dari systemd sendiri ketika itu membunuh proses.


1
Apa gunanya file PID? Jika seseorang ada untuk layanan yang diberikan, mungkin ada atau mungkin tidak ada proses aktual dengan PID itu, dan ketika proses dengan PID yang tepat ada, itu mungkin atau mungkin tidak benar-benar menjadi layanan yang diharapkan.
JoostM
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.