Tuesday, June 4, 2013

Role-based Puppet with Hiera

This is a method of configuring machines with Puppet based on their roles. It's similar to Jordan Sissel's nodeless Puppet in that there are no individual node declarations, just a default node that assigns one class. That one class is responsible for including all the other classes based on what 'roles' are assigned to the node. One difference between this role-based puppet and Jordan's nodeless puppet is that I'm not using an ENC. Instead of an ENC I'm using Hiera to assign to roles and specify custom parameters for the nodes. I put together a demo of role-based puppet as a Vagrant configuration, which you can get on GitHub.

Here is what the default node looks like:

The role class searches Hiera for 'roles' and includes them:

In Hiera multiple roles can be assigned, and data can be added to customize the roles. In this case we are adding the 'role::lb' load balancer role along with 'role::base', and specifying how much memory memcached should use and how many nginx processes should run.

The roles then include the actual classes that do the work, in this case nginx and memcache. In the real world the role would probably do a lot more, like configure sysctl. The role can pass site specific parameters to the classes, but it can also rely on Puppet to lookup parameters in Hiera.

Site-specific roles and generic modules

Every site is different, but there is no reason that every company should have its own nginx module. Modules should be generic and customizable, they shouldn't make assumptions about how you want to configure something. Roles are site-specific, they bring together modules in the way your site uses them. Data in Hiera can then customize modules or roles in node-specific ways.

For example puppetlabs-nginx (and jfryman's nginx module that it's based on) configures a yum repo hosted on, and they don't allow you to specify custom templates for configuration files. That means I would have to fork and customize the puppet module if I wanted to use my own yum repo with a version of nginx compiled with ngx_pagespeed. It shouldn't be that way. I forked puppetlabs-nginx and added parameters to use custom templates, I'm going to continue working on it to make it more generic while still being easy for the 90% use case. I would like Puppet to be as simple as Ansible for the easy cases, and still be efficient and powerful when you need to customize.