Is your application delivered as a set of services running on top of Linux? Did you think about writing a custom controller service that would start your application services in the correct order and monitor their health? Please, stop thinking about it! In this blog post I would like to convince you that you can leverage the existing systemd service manager to control your application services to your greatest benefit.
systemd is the default service manager on all major Linux distributions. We’re going to demonstrate how it can be used to control a custom multi-service application.
Our application consists of three services: Service 1, Service 2 and Service 3. The following set of requirements should be met when controlling the services using systemd:
- User can permanently enable/disable any of the services
- User can start and stop the services as a group
- User can start and stop each service independently
- Service 2 should start before the Service 3 can start
- Service 3 should be stopped before the Service 2 can be stopped
- Services 1 and 2 should start in parallel to speed up the application startup
- Components should be monitored and restarted in the case of failure
Required service startup order:
Creating the systemd unit files
Let’s begin creating the systemd unit files. First, we’ll define a pseudo-service called app
. This service doesn’t run any deamon. Instead, it will allow us to start/stop the three application services at once.
|
|
In the next step, we’ll create systemd unit files for the three services that constitute our application. I included some explanatory comments in the first app-component1
service definition. The definitions of the remaining two services app-component2
and app-component3
follow the same schema.
|
|
The definition of the service app-component2
resembles the definition of service app-component1
:
|
|
We would like the service app-component3
to start after the service app-component2
. Systemd provides the directive After
to configure the start ordering. Note that we don’t use a Wants
directive to create a dependency of app-component3
on app-component2
. This Wants
dependency would instruct systemd to start the app-component2
whenever the app-component3
should be started. The app-component2
would be started even in the case that it was disabled before. This is however not what we wanted as we require the user to be able to permanently disable any of the components. If app-component2
is not enabled, systemd should just skip it when starting the application services.
|
|
Adding the application services to systemd
After we finished the creation of the four systemd unit files, we need to copy them to the systemd configuration directory:
|
|
Next, we have to ask systemd to reload its configuration:
|
|
If everything went well, you should be able to see the new services in the unit file list:
|
|
Testing the application services
After all the hard work we’re now ready to exercise our configuration. First, let’s enable all the application services:
|
|
To start all the services, you can type:
|
|
The systemd status command should display all the services as active
:
|
|
Note that while the component services are marked as running
, the pseudo-service app
is showed as exited
. This is an expected behaviour as the service app
is of type oneshot
. (I’m not showing the output of the systemctl status command here).
Next, let’s check the starting order of the services. Systemd logs its messages into the journal. Let’s list the recent log entries with:
|
|
In our sample output we can see that the service app-component3
was indeed started after the service app-component2
:
|
|
Now we’re going to check that we can disable any service independently of other services. Let’s stop the service app-component2
and disable it:
|
|
When we stop and start our application the service app-component2
will remain disabled.
|
|
Unfortunately, I realized that when using the restart
command, systemd will enable the service app-component2
:
|
|
The behaviour of the systemd stop
command followed by the start
command is not consistent with the behaviour of the systemd restart
command. As a workaround, you can use the systemd mask
command to really disable the application service, for example:
|
|
This way, the service app-component2
remains disabled no matter what.
Conclusion
systemd provides a feature-rich service manager. Instead of implementing a home-grown solution you might want to think about using systemd to control your application services. Some of the benefits of opting for systemd are:
- systemd is a standard service manager any Linux administrator is familiar with
- systemd is battle tested to the extent your proprietary solution probably cannot be
- You can discover many other useful systemd features which you can employ right away
Have fun!