Systemd – How to Create Virtual Service to Stop/Start Multiple Instances

systemdUbuntu

I plan to host several instances of the same web app for customers using systemd. I would like to be able to stop and start each customer instance using systemd, as well as treating the whole collection of customer instances as a single service that can be stopped and started together.

systemd seems to provide the building blocks I need using PartOf, and template unit files, but went I stop the parent service, the child customer service is not stopped. How can I make this work with systemd? Here's what I have so far.

The parent unit file, 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

A unit template file named app@.service, used to create customer instances:

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

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

My app-poc.sh script (Proof of concept that just prints to log file in a loop):

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

For the proof of concept, I've got the systemd unit files in ~/.config/systemd/user.

I then start up the parent and an instance based on the template (after systemctl --user daemon-reload ):

systemctl --user start app
systemctl --user start app@customer.service

From using journalctl -f I can see that both started and that the customer instance continues to run. Now I I expect shutting down the parent will stop the child (because I used PartOf), but it doesn't. Also, starting the parent isn't starting the child as expected either.

systemctl --user stop app

Thanks!

(I'm using Ubuntu 16.04 with systemd 229).

Best Answer

You need to move the line

PartOf=app.service

out of [Service] and into the [Unit] section, and add to the [Unit] of app.service the list of customers to start, eg

Wants=app@customer1.service app@customer2.service

or as sourcejedi said in the comments, Requires= the same thing. You can keep the PartOf to stop services you start by hand that are not in the above list, like systemctl --user start app@customer3.service.