Bagaimana cara membuat layanan systemd virtual untuk menghentikan / memulai beberapa instance bersamaan?

12

Saya berencana meng-host beberapa contoh aplikasi web yang sama untuk pelanggan yang menggunakan systemd. Saya ingin dapat stopdan startsetiap instance pelanggan menggunakan systemd, serta memperlakukan seluruh koleksi instance pelanggan sebagai layanan tunggal yang dapat dihentikan dan dimulai bersama.

systemdtampaknya memberikan blok bangunan yang perlu saya gunakan PartOf, dan templat file unit, tetapi pergi saya menghentikan layanan induk, layanan pelanggan anak tidak berhenti. Bagaimana saya bisa membuat ini bekerja dengan systemd? Inilah yang saya miliki sejauh ini.

Induk berkas Unit, app.service:

[Unit]
Description=App Web Service

[Service]
# Don't run as a deamon (because we've got nothing to do directly)
Type=oneshot
# Just print something, because ExecStart is required
ExecStart=/bin/echo "App Service exists only to collectively start and stop App instances"
# Keep running after Exit start finished, because we want the instances that depend on this to keep running
RemainAfterExit=yes
StandardOutput=journal

File template unit bernama [email protected], digunakan untuk membuat instance pelanggan:

[Unit]
Description=%I Instance of App Web Service

[Service]
PartOf=app.service
ExecStart=/home/mark/bin/app-poc.sh %i
StandardOutput=journal

app-poc.shSkrip saya (Bukti konsep yang hanya mencetak untuk mencatat file dalam satu lingkaran):

#!/bin/bash
# Just a temporary code to fake a full daemon.
while :
do
  echo "The App PoC loop for $@"
  sleep 2;
done

Untuk bukti dari konsep, saya punya file Unit systemd di ~/.config/systemd/user.

Saya kemudian memulai induk dan turunannya berdasarkan templat (setelah systemctl --user daemon-reload):

systemctl --user start app
systemctl --user start [email protected]

Dari menggunakan journalctl -fsaya dapat melihat bahwa keduanya mulai dan bahwa instance pelanggan terus berjalan. Sekarang saya-saya berharap mematikan orang tua akan menghentikan anak (karena saya menggunakan PartOf), tetapi tidak. Juga, memulai orang tua juga tidak memulai anak seperti yang diharapkan.

systemctl --user stop app

Terima kasih!

(Saya menggunakan Ubuntu 16.04 dengan systemd 229).

Mark Stosberg
sumber
1
"PartOf = Mengkonfigurasi dependensi yang mirip dengan Membutuhkan =, tetapi terbatas pada menghentikan dan memulai kembali unit." Jika Anda ingin mulai bekerja, bukankah Anda harus menggunakannya Requires=?
sourcejedi

Jawaban:

10

Anda harus memindahkan garis

PartOf=app.service

dari [Service]dan ke [Unit]bagian, dan menambah [Unit]dari app.servicedaftar pelanggan untuk memulai, misalnya

[email protected] [email protected]

atau seperti yang dikatakan sourcejedi dalam komentar, Requires=hal yang sama. Anda dapat menjaga PartOfagar layanan berhenti Anda mulai dengan tangan yang tidak ada dalam daftar di atas, seperti systemctl --user start [email protected].

meuh
sumber
Saya mengkonfirmasi Anda benar tentang PartOf. Terima kasih. Saya akan menangani "Mau" melalui symlink, yang menjadi tindakan tunggal yang perlu saya ambil untuk mengaktifkan pelanggan baru dengan systemd. Untuk kasus pengujian saya: `ln -s /home/mark/.config/systemd/user/[email protected] / home / mark / .config / systemd / user / app.service.wants / unity @ foo.service`
Mark Stosberg
13

Saya belajar bahwa ini untuk apa Systemd "Target Unit". Dengan menggunakan Unit Target, saya mendapatkan manfaat yang saya inginkan tanpa perlu membuat bagian palsu yang [Service]saya miliki di atas. Contoh "Unit Target" yang berfungsi terlihat seperti ini:

# named like app.target
[Unit]
Description=App Web Service

# This collection of apps should be started at boot time.
[Install]
WantedBy=multi-user.target

Maka setiap instance pelanggan harus termasuk PartOfdalam [Unit]bagian (seperti yang ditunjukkan oleh @meuh), dan juga harus memiliki [Install]bagian sehingga enabledan disableakan bekerja pada layanan spesifik:

# In a file name like [email protected]
[Unit]
Description=%I Instance of App Web Service
PartOf=app.target

[Service]
ExecStart=/home/mark/bin/app-poc.sh %i
Restart=on-failure
StandardOutput=journal

# When the service runs globally, make it run as a particular user for added security
#User=myapp
#Group=myapp

# When systemctl enable is used, make this start when the App service starts
[Install]
WantedBy=app.target

Untuk memunculkan instance pelanggan dan memulainya saat target dimulai, perintah aktifkan satu kali ini digunakan:

 systemctl enable app

Sekarang pada titik ini saya dapat menggunakan stopdan startpada app@customeruntuk untuk contoh spesifik, atau bisa saya gunakan start appdan stop appuntuk menghentikan semua aplikasi bersama-sama.

Mark Stosberg
sumber
Bagaimana dengan status? Saya tidak dapat menemukan cara sederhana untuk mendapatkan status semua layanan yang diinginkan App. Saya tahu bagaimana saya bisa skrip itu, tapi ...
Tommi Kyntola
1
Maksud saya suka mendapatkan status aplikasi di grup target itu tanpa mendaftar semua yang merupakan bagian darinya, wild card atau tidak, lebih disukai menggunakan nama grup itu dan bahkan tidak peduli dari apa itu dibuat.
Tommi Kyntola
2
Tidak sesederhana itu. Ke paket mana skrip itu berasal? Itu harus dimodifikasi setiap kali komponen baru ditambahkan. Lupakan itu dan penyebaran / pemeliharaan menjadi berantakan. Yang saya jelas ingin adalah hanya menambahkan paket baru dengan pengaturan partOf menunjukkan keberadaannya dalam kelompok itu dan tidak kemudian memodifikasi beberapa skrip yang tersisa. Dan kemudian berhenti dan mulai dari target itu bekerja seperti sebelumnya. Ini berfungsi, tetapi statusnya tampaknya keluar dari cakupan itu. Saya bahkan tidak dapat menemukan cara untuk mendapatkan daftar unit yang runtime hadir dalam target. Kasus penggunaan ini tidak dicakup oleh systemd.
Tommi Kyntola
2
@TommiKyntola Ini adalah bash one-liner yang tidak perlu Anda perbarui saat dependensi target berubah:systemctl status $(systemctl list-dependencies --plain otp.target)
Mark Stosberg
2
@TommiKyntola Saya setuju yang systemddapat meningkatkan kegunaan di sini. Saya telah membuka permintaan fitur untuk menyarankan peningkatan status untuk target.
Mark Stosberg