May 12, 2015

Process Monitoring with Systemd

For most Linux distributions, Systemd will be the officially support init process. This will, among many other things, monitor our processes like SysVInit and Upstart did. Get a leg up and learn how to use it now!

For most Linux distributions, Systemd will be the officially support init process. This will, among many other things, monitor our processes like SysVInit and Upstart did. Get a leg up and learn how to use it now!We'll see how to use Systemd to monitor a process. For this video, we'll create a small Golang utility to listen for HTTP connections and respond to them.

Systemd will monitor this listener and ensure it stays running!

I spun up a fresh CentOS system for this video and installed vim and golang to start:

sudo yum install vim golang

SELinux

Let's check SELinux and see if it might get in our way.

$ sestatus
SELinux status:                 enabled
Current mode:                  enforcing

It's enabled, and I didn't show it, but it's also enforcing. If we run into issues, we'll see about making it let us use this port the Golang listener will use.

Golang Listener

Here's the Go code used to make a (stupid) listener, found in /opt/listen.go in this video:

package main

import (
    "fmt"
    "net/http"
)

func handler(w http.ResponseWriter, r *http.Request) {
    fmt.Fprintf(w, "Hi there!")
}

func main() {
    http.HandleFunc("/", handler)
    http.ListenAndServe(":8181", nil)
}

This is in file "listener.go". To build it, we can simply run:

go build listen.go

Now if we run the "listen" command generated, we will have a web listener listening on all networks on port 8181. Because this is a high port, SELinux did not block it's use.

Web User

We don't want the listener to run as user root, so I make a new user to run it as. This will be an administrative user, which is to say, one that is not meant to be logged in as (no shell, lower uid/sid, no home directory).

adduser -r -M -s /bin/false www-data
  • -r - Make a system user
  • -M - Don't create a home directory
  • -s /bin/false - Don't assign a shell (or more accurately, make the shell /bin/false, so the user cannot be logged into)
  • www-data - the user we create

We can see more information about this user in the /etc/passwd file:

cat /etc/passwd | grep www

Systemd Unit File

Let's finally create the Systemd unit file that will control this Golang listener.

In general, we'll find Unit files and other configuration in /etc/systemd, however these are mostly symlinks to files found in /usr/lib/systemd/system. It's in this latter directory that we'll make our unit file.

Create the file: sudo vim /usr/lib/systemd/system/goweb.service

Here's the file itself:

[Unit]
Description=Webhook

[Service]
User=deployer
Group=www-data
Restart=on-failure
ExecStart=/opt/listen

[Install]
WantedBy=multi-user.target

Then run:

sudo systemctl enable goweb.service
sudo service goweb status
sudo service goweb start

And that's it! We can further control this service with the systemctl command:

systemctl list-unit-files | grep goweb
systemctl enable goweb
systemctl is-enabled goweb
systemctl disable goweb

A Bigger Example

Here's a larger example with more things you can do!

[Unit]
Description=Webhook
After=another.target
After=some.service

[Service]
Type=simple  # forking, oneshot

User=deployer
Group=www-data

WorkingDirectory=/opt

Restart=on-failure

Environment=VAR1=whatever "VAR2=something else"
EnvironmentFile=/path/to/file/with/variables

ExecStartPre=/run/some/command
ExecStartPre=/run/some/other/command
ExecStart=/usr/bin/node /opt/webhook/server.js
ExecStartPost=/lastly/run/this

[Install]
WantedBy=multi-user.target

All Topics