Puppet master with nginx, unicorn and systemd

I finally had time to setup a puppet master on my new root server (again). Puppetlabs provides great apt repositories for Ubuntu and Debian. Or you can use the older packages provided by the Debian main repository.

I’ve first added the repository and installed the puppetmaster package.

The package comes with a SysVinit script running puppet master with Webrick. As Webrick is only intended to be a simple server while developing Ruby projects it is not recommended for production systems. My favored choice is unicorn as a application web server, nginx as a reverse proxy and SSL endpoint and all powered by systemd as the init system. I will not cover how to setup systemd on Wheezy, I assume you have one running.

But let’s start with the puppet master. First we can disable the default SysVinit service in /etc/default/puppetmaster. Set START to no:

# Defaults for puppetmaster - sourced by /etc/init.d/puppetmaster

# Enable puppetmaster service?

# Setting this to "yes" allows the puppet master service to run.

# Setting this to "no" keeps the puppet master service from running.

#

# If you are using Passenger, you should have this set to "no."

START=no

# Startup options

DAEMON_OPTS=""

# On what port should the puppet master listen? (default: 8140)

PORT=8140

Also make sure to stop a running puppet master by invoke-rc.d puppetmaster stop.

Now we can install unicorn. Instead of installing it via Rubygems we can use the Debian provided package and therefore profit from security updates and stability from Debian:

root@puppet:~# apt-get install unicorn

Next we need a unicorn configuration file. Paste the following to /etc/puppet/unicorn.rb:

worker_processes4

# TODO: Check if /run/puppet exists if SysVinit script was never run

listen"/run/puppet/puppetmaster.sock",:backlog=>512

pid"/run/puppet/puppetmaster.pid"

timeout120

# TODO: Check if master could be started as puppet use by systemd

user'puppet'

preload_apptrue

# TODO: Reload not working, no access or missing HOME

before_forkdo|server,worker|

old_pid="#{server.config[:pid]}.oldbin"

ifFile.exists?(old_pid)&&server.pid!=old_pid

begin

Process.kill("QUIT",File.read(old_pid).to_i)

rescueErrno::ENOENT,Errno::ESRCH

# someone else did our job for us

end

end

end

The worker_processes defines the number of worker processes unicorn will spawn. As my setup is quite tiny even one process would be enough but I like to have more ;).

Next big thing is the systemd service description. We can create our custom service in /etc/systemd/system/puppetmaster.service:

We first provide a service description and define the basics, working directory, syslog identifier and PID file. Make sure the PID file matches the one in unicorn.rb.

The ExecStart defines the command systemd uses to launch unicorn. We provide the full path to unicorn, point to our configuration file and finally the path to the puppet master rack configuration that is shipped with the puppet master packages. You may need to fetch the config.ru from Puppetlabs when using Debian’s puppet packages as they may not ship this file.

The ExecStop and ExecReload options specify the commands used to send unicorn the shutdown or reload signals.

Now we can start our puppet master. First reload service descriptions systemctl --system daemon-reload and then systemctl start puppetmaster.service.

The upstream must match the socket configure in unicorn.rb. I only listen on IPv4 listen 8140, and not IPv6, as the machine is public IPv6 reachable, but in a private IPv4 virtual network.

The SSL certificates and private keys are generated by puppet and named by the hostname. They should already exists as our puppet master is already running. The root directory can point to any directory and does not need to exist.

Last but not least we are redirecting all request to our puppet master upstream.

Now reload nginx and try to run a puppet agent:

root@puppet:~# invoke-rc.d nginx reload

root@puppet:~# puppet agent --test

Warning: Unable to fetch my node definition, but the agent run will continue: