What is DevOps?
DevOps is a term that John Willis and Damon Edwards came up with (according to my sources) around 2010. Initially defined as a set of principles with the acronym CAMS.
Culture: the right mindset to address constructively issues and solve them rapidly and efficiently;
Automation: all with the click of a button, so it is repeatable;
Measurement: deployment frequency, MTTR, and other relevant metrics can identify bottlenecks and show where the efforts should concentrate;
Sharing: in and outside the team.
What is Puppet?
Puppet is an open-source IT automation tool. The Puppet Domain Specific Language (DSL) is a Ruby-based coding language that provides a precise and adaptable way to describe a desired state for each machine in your infrastructure. Once you’ve described a desired state, Puppet does the work to bring your systems in line and keep them there. Yes, you can do it all with scripts, but Puppet gives you platform independent abstraction and the ability to manage quite a considerable number of nodes without losing your mind.
Puppeteering 101
Puppet is build with a client server architecture, the Master (or server) builds a catalog of collected facts from the different Nodes (or clients). This catalog is then pushed to all the involved Nodes and diffed against local existing configuration, updating when necessary. This last operation will generate a report for the Master used to update the dashboard and, more in general, to have a feedback on the operation.
The catalog is build in .pp
files, usually a main manifest and one or more classes. These files are a representation of the desired state of the configuration. Through the DSL any element of a system is mapped to a resource with the generic format of:
type { 'title':
key1 => value1,
key2 => value2,
...
}
Where type represents the type of the resource described. It can be a file, a user, a package, a service and so on.
The title is the unique identifier, within the current module, for the resource. For instance, assuming I’m writing a user management tool, it makes sense to have a single place that maps my user John Smith, that would be the title.
The list of keys and values are the attributes and the parameters needed to complete the configuration description.
Some keys are package specific, needed for its complete configuration, some though, are for Puppet’s validation.
The most relevant keys are ensure and the four metaparameters to define relationships before, require, notify and subscribe.
- ensure will validate that a resource is present or belongs to a specific resource type
- before (read as “is father of”), applies the current resource before the one specified in the values
- require applies the value before the current resource definition
- notify like before with forced refreshes when the dependency changes
- subscribe like require with forced refreshes when the dependency changes
Where are my Puppetry things ?
There are some paths and files to be aware of so as to not mix up concerns in the configuration description and avoid conflicts. The first manifest file the Puppet agent checks when connecting to master is site.pp
. This file contains the node definitions and defines global settings and resources on a per environment basis. By default, the main manifest for a given environment is <ENVIRONMENTS DIRECTORY>/<ENVIRONMENT>/manifests
.
The master manifest will therefore be in /etc/puppetlabs/code/environments/production/manifests
.
Similarly /etc/puppetlabs/code/environments/production/modules
will contain modules for your production environment.
For site specific modules that need to be available for all environments /etc/puppetlabs/code/modules
is the expected folder. Puppet itself uses modules and stores them in /opt/puppetlabs/puppet/modules
.
I’ve clothed my Puppet
We are now ready to address the process workflow for an average Puppet configuration to be applied. A suggested common approach is the cycle package/file/service. This pattern addresses installing a package as a first step, followed by customizing that package’s functionality with configuration files, and finally starting the service as expected. By defining relationships correctly with metaparameters we can ensure that the configuration file is re-created every time a package is installed or updated and the service is restarted if said configuration file has changed.