Using Unicorn

This support is present in release 0.24.6 and later versions only – it is not supported in earlier releases

Alternatively see: Using Mongrel and Using Passenger

Why You’d Do This

Traditionally, the puppetmaster would embed a WEBrick or Mongrel Web Server to serve the puppet clients. This may work well for you, but when you start scaling out to hundreds of clients you really need to do things a bit more efficiently.

Adding Unicorn to your Puppetmaster stack brings one major advantage – seamless restarts of your puppetmasters.

What is Unicorn ?

http://unicorn.bogomips.org/ a HTTP server for Rack applications designed to only serve fast clients on low-latency, high-bandwidth connections and take advantage of features in Unix/Unix-like kernels.

Puppet (>0.24.6) now ships with a Rack application which can embed a puppetmaster. While it should be compatible with every Rack application server, it has only been tested with Passenger and Unicorn.

Installation Instructions for Puppet 0.25.x

First install Unicorn and Rack:

$ sudo gem install unicorn rack

Now copy in the config.ru file in the ext/rack directory:

$ sudo cp ext/rack/files/config.ru /etc/puppet/

Next, we need to create a configuration file for Unicorn, we’re calling ours unicorn.conf.

$ sudo touch /etc/puppet/unicorn.conf

Here’s the contents of a sample file:

    
    worker_processes 8
    working_directory "/etc/puppet"
    listen '/var/run/puppet/puppetmaster_unicorn.sock', :backlog => 512
    timeout 120
    pid "/var/run/puppet/puppetmaster_unicorn.pid"
    
    preload_app true
    if GC.respond_to?(:copy_on_write_friendly=)
      GC.copy_on_write_friendly = true
    end
    
    before_fork do |server, worker|
      old_pid = "#{server.config[:pid]}.oldbin"
      if File.exists?(old_pid) && server.pid != old_pid
        begin
          Process.kill("QUIT", File.read(old_pid).to_i)
        rescue Errno::ENOENT, Errno::ESRCH
          # someone else did our job for us
        end
      end
    end

Running unicorn

To test that Unicorn is running Puppetmaster correctly you can fire it directly.

$ cd /etc/puppet
$ sudo unicorn -c unicorn.conf

For continued use, you’ll probably want to have something manage the unicorn process for you – this is where god comes in handy

Installing god

First, install god

$ sudo gem install god

You can find initscripts for god out there, but I prefer to have init spawn god, so:

$ sudo mkdir /etc/god
$ sudo echo "god:2345:respawn:/path/to/god --log-level error -D -c '/etc/god/*.god'" >> /etc/inittab
$ sudo touch /etc/god/puppetmaster.god
$ sudo telinit q

Configuring god to manage Unicorn

Drop the following into /etc/god/puppetmaster.god

    God.watch do |w|
      w.name = "puppetmaster"
      w.interval = 30.seconds
      w.pid_file = "/var/run/puppet/puppetmaster_unicorn.pid"

      w.start = "cd /etc/puppet && /path/to/unicorn -c /etc/puppet/unicorn.conf -D"
      w.stop = "kill -QUIT `cat #{w.pid_file}`"
      w.restart = "kill -USR2 `cat #{w.pid_file}`"

      w.start_grace = 10.seconds
      w.restart_grace = 10.seconds

      w.uid = "puppet"
      w.gid = "puppet"

      w.behavior(:clean_pid_file)

      w.start_if do |start|
        start.condition(:process_running) do |c|
          c.interval = 5.seconds
          c.running = false
        end
      end
    end

Finally, restart god to pick up the new config

$ sudo killall god

God should now be managing your Unicorn instance. You can test this by:

$ sudo god status
puppetmaster: up

Running Nginx

Drop this config into your Nginx setup. Requires nginx 0.7.63 or newer.

    upstream puppetmaster_unicorn {
        server unix:/var/run/puppet/puppetmaster_unicorn.sock fail_timeout=0;
    }
    
    server {
        listen 8140;
    
        ssl on;
        ssl_session_timeout 5m;
        ssl_certificate /var/lib/puppet/puppetmaster-ssl/certs/puppetmaster.pem;
        ssl_certificate_key /var/lib/puppet/puppetmaster-ssl/private_keys/puppetmaster.pem; 
        ssl_client_certificate /var/lib/puppet/puppetmaster-ssl/ca/ca_crt.pem; 
        ssl_ciphers SSLv2:-LOW:-EXPORT:RC4+RSA; 
        ssl_verify_client optional; 
    
        root /usr/share/empty;
    
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Client-Verify $ssl_client_verify; 
        proxy_set_header X-Client-DN $ssl_client_s_dn;
        proxy_set_header X-SSL-Issuer $ssl_client_i_dn;
        proxy_read_timeout 120;
    
        location / { 
            proxy_pass http://puppetmaster_unicorn;
            proxy_redirect off; 
        } 
    }