Using SystemD Timers (Like Cron) – Centos

The more I use it, the more I like using SystemD to manage services.  It is sometimes verbose, but in general, it is very easy to use and very powerful.  It can restart failed services, start services automatically, handle logging and rolling for simplistic services, and much more.

SystemD Instead of Cron

Recently, I had to take a SystemD service and make it run on a regular timer.  So, of course, my first thought was using cron… but I’m not a particularly big fan of cron for reasons I won’t go into here.

I found out that SystemD can do this as well!

Creating a SystemD Timer

Let’s say you have a (very) simple service defined like this in SystemD (in /etc/systemd/system/your-service.service):

[Unit]
Description=Do something useful.

[Service]
Type=simple
ExecStart=/opt/your-service/do-something-useful.sh
User=someuser
Group=someuser

Then you can create a timer for it by creating another SystemD file in the same location but ending with “.timer” instead of “.service”. It can handle basically any interval, can start at reboot, and can even time tasks based on the reboot time.

[Unit]
Description=Run service once daily.

[Timer]
OnCalendar=*-*-* 00:30:00
Unit=your-service.service

[Install]
WantedBy=multi-user.target

Once the timer file is made, you can enable it like to:

sudo systemctl daemon-reload
sudo systemctl enable your-service.timer
sudo systemctl start your-service.timer

After this, you can verify the timer is working and check its next (and later on, previous) execution time with this command:

$> systemctl list-timers --all
NEXT                         LEFT          LAST                         PASSED  UNIT                         ACTIVATES
Tue 2019-03-05 20:00:01 UTC  14min left    Mon 2019-03-04 20:00:01 UTC  23h ago systemd-tmpfiles-clean.timer systemd-tmpfiles-clean.service
Wed 2019-03-06 00:30:00 UTC  4h 44min left n/a                          n/a     your-service.timer     your-service.service
n/a                          n/a           n/a                          n/a     systemd-readahead-done.timer systemd-readahead-done.service

SystemD/SystemCTL Tail or View Service Log (Centos 7)

By default, systemd services will log their output to /var/log/messages, and you can view these messages with journalctl commands.

To tail the logs for a specific service you are running, you can simply do the following.

journalctl -u service-name -f

Just remove the -f if you want to view the log in general.

You can also just lazily use -f without the -u and service name if you want to tail recent system logs, which is often useful.

HA Proxy + Centos 7 (or RHEL 7) – Won’t bind to any ports – SystemD!

What are the Symptoms?

This has bitten me badly twice now. I was deploying Centos 7.5 servers and trying to run HA Proxy on them through SystemD (I’m not sure if it is an issue otherwise).

Basically, no matter what port I use I get this message:

Starting frontend main: cannot bind socket [0.0.0.0:80]

Note that as I was too lazy to set up separate logging for the HAProxy config, I found this message in /var/log/messages with the other system messages.

Of course, seeing this your first thought is “he’s running another process on that port!”… but nope.  Also, the permissions are set up properly, etc.

What is the Problem?

The problem here is actually SE Linux.  I haven’t quite dug into why, but when running under SystemD, SELinux will deny access to all ports for HAProxy unless you go out of your way to allow it to access them.

How Do We Fix It?

The fix is very simple thankfully, just set this selinux boolean as a root/sudo user:

sudo setsebool -P haproxy_connect_any 1

…and voilà! if you restart your HAProxy it will connect fine.  I spent a lot of time on this before I found a decent documentation and forum references in these places.  I hope this helps you fix it faster!  I also found a stack-overflow eventually… but the accepted/good answer is like 10 down so I missed it the first pile of times.

Centos7 / RHEL7 Services with SystemD + Systemctl For Dummies – Presto Example

History – SystemV & Init.d

Historically in Centos and RHEL, you would use system-v to run a service.  Basically an application (e.g. Spring Boot) would provide an init-d script and you would either place it in /etc/init.d or place a symbolic link from there to your script.

The scripts would have functions for start/stop/restart/status and they would follow some general conventions.  Then you could use “chkconfig” to turn the services on so they would start with the sysem when it rebooted.

SystemD and SystemCTL

Things have moved on a bit and now you can use SystemD instead.  It is a very nice alternative.  Basically, you put a “unit” file in /etc/systemd/system/.service.  This unit file has basic information on what type of application you are trying to run and how it works.  You can specify the working directory, etc as well.

Here is an example UNIT file for Facebook’s Presto application.  We would place this at /etc/systemd/system/presto.service.

[Unit]
Description=Presto
After=syslog.target network.target

[Service]
User=your-user-here
Type=forking
ExecStart=/opt/presto/current/bin/launcher start
ExecStop=/opt/presto/current/bin/launcher stop
WorkingDirectory=/opt/presto/current/bin/
Restart=always

[Install]
WantedBy=multi-user.target

Here are the important things to note about this:

  1. You specify the user the service will run as – it should have access to the actual program location.
  2. Type can be “forking” or “simple”.  Forking implies that you have specific start and stop commands to manage the service (i.e. it kind of manages itself).  Simple implies that you’re just running something like a bash script or a Java JAR that runs forever (so SystemD will just make sure to start it with the command you give and restart it if it fails).
  3. Restart=always will make sure that, as long as you had it started in the first place, it starts whenever it does.  Try it; just kill -9 your application and it will come back.
  4. The install section is critical if you want the application to start up when the computer reboots.  You can not enable it for restart without this.

Useful Commands

  • sudo systemctl status presto (or your app name) –> current status.
  • sudo systemctl stop presto
  • sudo systemctl start presto
  • sudo systemctl restart presto
  • sudo systemctl enable presto -> enable for starting on reboot of server.
  • sudo systemctl disable presto -> don’t start on reboot of server.
  • sudo systemctl is-enabled presto; echo $? –> show if it is currently enabled for start-on-boot.