DEV Community

Cover image for Write and auto-deploy daemons on FreeBSD
Daniel Ziltener
Daniel Ziltener

Posted on • Updated on

Write and auto-deploy daemons on FreeBSD

Goal

Our goal is to write an rc.d file that allows us to start anything as a daemon, and an accompanying settings file, and to get to know the commands to use for automated deploy.

Settings File

We will start with the settings file. Technically you can do in there whatever you want; if you have any sanity left, you will simply use it to set environment variables. This makes it easy to follow the third rule of the Twelve-Factor App. And it really is that simple, you just add export statements, and make "dummy values" you will replace in your CI/CD script using sed:

export HTTP_PORT=3000
export POSTGRES_IP=SED_PGSQL_IP
export POSTGRES_USERNAME=SED_PGSQL_USER
export POSTGRES_PASSWORD=SED_PGSQL_PASS
Enter fullscreen mode Exit fullscreen mode

This file has to be stored with the same name as your actual service file, but under /usr/local/etc/rc.conf.d/. The RC system will auto-detect it.

Daemon file

This one is going to be a little bit longer. Let's first take a look at the whole script:

#!/bin/sh

# PROVIDE: location_service
# REQUIRE: LOGIN DAEMON NETWORKING
# KEYWORD: shutdown

. /etc/rc.subr

name=location_service
rcvar=${name}_enable
pidfile="/var/run/${name}.pid"
pidfile_child="/var/run/${name}_jvm.pid"
logfile="/var/log/${name}.log"
location_service_chdir="/usr/local/share/location-service"

command="/usr/sbin/daemon"
start_cmd="location_service_start"
procname="daemon"

load_rc_config ${name}
: ${location_service_enable:=no}

location_service_start() {
    /usr/sbin/daemon -r -f -P ${pidfile} -p ${pidfile_child} -t ${name} -o ${logfile} /usr/local/bin/java -jar location-service.jar
}

run_rc_command "$1"
Enter fullscreen mode Exit fullscreen mode

Main variables

There is some magic going on with the variable names, but that aside, it is a pretty standard shell script file. In this case, we are working with a location service that is to be run by the JVM, but it really doesn't matter - you can run literally anything as a service this way.

  • . /etc/rc.subr loads subroutines that enable the "magic" to run the service.
  • rcvar is the flag that you can set to enable or disable your service in the rc.conf file.
  • The two pidfiles are holding the process id of the daemon and the actual process, so the system can keep track of it.
  • and the location_service_chdir (or whatever_you_name_it_chdir) sets the working directory.

The Daemon command

FreeBSD ships with a program aptly called daemon, and we are using it to run our normal program as one. We thus tell the rc system to use /usr/sbin/daemon as the main command, and tell it that the process started by it - procname - will be called "daemon". We also tell it to run a custom starting function, start_cmd, which in this case is called "location_service_start".

Configure the daemon

We configure the daemon by setting the flags when starting it. We have the following flags:

  • -r: Restarts the process if it dies
  • -f: Redirects standard input/output and standard error to /dev/null
  • -p: the pidfile for the process you want to have daemonized
  • -P: the pidfile of the daemon process itself - that is what the rc system needs
  • -o: the log file to log to
  • -t: gives the process a name (optional)
  • -u: (not used here): the user to run the process as

This service file has to be stored under /usr/local/etc/rc.d and be made executable.

Automatic deployment

We almost have it - the only thing missing are the commands for your CI/CD. It is really simple once you have both files at their respective locations.

You can set the config variables using sed -i.bak "s/SED_PGSQL_IP/${your_ci_var}/g" /usr/local/etc/rc.conf.d/location_service. Remember, if your variable contains the "/" character, you can use something else for sed, whatever character follows the "s" will be the separator.

Enable the service using sysrc -f /etc/rc.conf "location_service_enable=YES".

And finally, don't forget to actually (re-)start it using service location_service restart.

Have fun!

Top comments (0)