Binding two SystemD-services to manage Loadbalancer IPVS

We have demonstrated how to makeĀ scalable resilient UDP service behindĀ  IPVS load-balancer.

In this article we will see how we can bind two systemd services (one is the process on a given port and the other is registering it to IPVS)

Requires, Before and After

When you write systemd unit files for two dependent systemd services, let’s say A then B, usually we specify both “Requires and “After” for example, in B.service you specify “Requires=A.service” and “After=A.service” which imply that A.service is “Before=B.service”

The order of “Before” and “After” is reversed when you stop the service.

How “BindsTo” work

Refer to “systemd.unit” manual page for details, in short it’s just like Requires but it if it’s down it would take the other one with it.

So if the process died it will be removed from the load-balancer. If it’s up it’s added. When you stop a process, first it would be removed from load-balanced then stopped.

Our unit file that launch the service on a given port looks like this

#/etc/systemd/system/aggron-udp@.service

[Unit]
Description=Aggron UDP Server on port %I
After=network.target
Before=aggron-udp-lb@%i.service
Requires=network.target aggron-udp-lb@%i.service

[Service]
User=aggron
Group=aggron
Restart=always
KillSignal=SIGQUIT
ExecStart=bash -c "cd ~/aggron/ && exec ./cli.py udp_server port=%i"

[Install]
WantedBy=multi-user.target

And the unit file for the service that register it in IPVS load-balancer

#/etc/systemd/system/aggron-udp-lb@.service

[Unit]
Description=LoadBalancer for Aggron UDP Server on port %I
After=network.target aggron-udp@%i.service
Requires=network.target aggron-udp@%i.service
BindsTo=aggron-udp@%i.service

[Service]
Type=oneshot
RemainAfterExit=yes
EnvironmentFile=/etc/sysconfig/aggron.rc
ExecStart=/bin/bash -c "exec /sbin/ipvsadm -a -u $IP:7000 -r $IP:%i -m"
ExecStop=-/bin/bash -c "exec /sbin/ipvsadm -d -u $IP:7000 -r $IP:%i"

[Install]
WantedBy=multi-user.target

Note that the first service is running as a user while the other is a single shot command (no running daemon) executed as root.