greenfield puppet: getting it right from the start
TRANSCRIPT
Greenfield PuppetDavid Danzilio
@djdanzilio
$(whoami)
What’s this all about?
A collection of wisdom that I wish I had available when I first started using Puppet
This could change in future releases
Don’t just take my word for it
– Wikipedia
“a greenfield is a project that lacks any constraints imposed by prior work”
A (not so) hypothetical scenario…
Department of BasketweavingFU
Foo University
class apache {! package { [‘apache2’, ‘rails’, ‘libapache2-mod-passenger’]:! ensure => present,! }! file { ‘/etc/apache2/sites-enabled/bw-app.conf’:! ensure => file,! source => ‘puppet:///apache/bw-app.conf',! require => Package[‘apache2’],! }! file { ‘/var/www/bw-app’:! ensure => directory,! owner => www-data,! group => www-data,! source => ‘puppet:///apache/bw-app',! recurse => true,! require => File[‘/etc/apache2/sites-enabled/bw-app.conf’]! }! service { ‘apache2’:! ensure => running,! require => [! File[‘/var/www/bw-app’],! Package[’rails’, ‘libapache2-mod-passenger’],! ]! }!}
I want to use Graphitefor all my!
basket data
OH NOES!
–Doug McIlroy
“Write programs that do one thing and do it well. Write programs to work together.”
Modules
Don’t write modules unless you absolutely have to!
Check the Forge first
2,617
Don’t customize Forge modules!
Use the Roles and Profiles pattern
Roles and Profiles
Craig Dunn’s blog post: “Designing Puppet – Roles
and Profiles”
A node includes one role
node db01.example.com { include role::db::server } !
node db02.example.com { include role::db::server::dev }
A role includes one or more profiles
class role::base { include profile::base } !class role::db::server inherits role::base { include profile::mysql include profile::application::database } !class role::db::server::dev inherits role::base { include profile::mysql include profile::percona }
A profile manages modules
class profile::mysql { ! $mysql_version = hiera(‘mysql_version’) ! class { ‘mysql::server’: package_ensure => $mysql_version } ! class { ‘mysql::backup’: } class { ‘nagios::mysql’: } !}
Like MVC for Puppet
The Forge
Look for modules with lots of downloads and recent
updates
Lots of downloadsRecent update
Do some background research on the author of the
module
Give priority to modules written by Puppet Labs
Be weary of modules with strange dependencies
WHY!??!?!
Don’t use a module without vetting it
Puppet Deployment
Have a solid deployment pipeline
Use librarian-puppet or r10k to deploy your code to your
Puppet masters
Reliable metadata is key to a successful Puppet deployment
$ cat /etc/facter/facts.d/metadata.json { "datacenter": "Boston", "rack": "R23", "role": "webserver", "cluster": "C89" }
Use environments to keep your nodes safe
Understand the lifecycle of a module
Use Hiera from the start
Don’t get too crazy with your hierarchy
:hierarchy: - “%{::app}/%{::environment}/%{::datacenter}/%{::fqdn}” - “%{::app}/%{::environment}/%{::datacenter}” - “%{::app}/%{::environment}” - “%{::app}” - “%{::cluster}/%{::environment}/%{::datacenter}/%{::fqdn}” - “%{::cluster}/%{::environment}/%{::datacenter}” - “%{::cluster}/%{::environment}” - “%{::cluster}” - “%{::environment}/%{::datacenter}/%{::fqdn}” - “%{::environment}/%{::datacenter}” - “%{::environment}” - “%{::realm}/%{::region}/%{::datacenter}/%{::fqdn}” - “%{::realm}/%{::region}/%{::datacenter}” - “%{::realm}/%{::region}” - “%{::realm}” - “%{::region}” - “%{::datacenter}/%{::rack}/%{::cluster}/%{::fqdn}” - “%{::datacenter}/%{::rack}/%{::cluster}” - “%{::datacenter}/%{::rack}” - “%{::datacenter}” - “%{::rack}” - “%{::cluster}”
Puppet Development
Puppet code is real code
Puppet is Ruby
Puppet modules need a design specification
rspec-puppet for TDD
Design modules with other people in mind
Fail fast
fail(“${::osfamily} is not supported by this module.”)
Public classes should expose a stable API
Semantic Versioning is your friend
Major.Minor.Patch
X.0.0
0.X.0
0.0.X
Remember the UNIX philosophy
Share your custom modules with the community!
Manage your dependencies with care
Keep artifacts out of your Puppet modules
Embedding data makes your modules less modular
class foo ( $pkg_version = $foo::params::pkg_version, $pkg_name = $foo::params::pkg_name, ) inherits foo::params { ! ... !}
Keep business logic out of templates
<% if @app == ‘foo’ %> ... <% else %> ... <% end %>
$template = ? $app { ‘foo’ => ‘foo.conf.erb’, default => ‘generic.conf.erb’, } !file { ‘/path/to/app.conf’: ensure => file, content => template(“module/${template}”), }
Standard Library
Use the standard library to level-up your modules
Avoid duplicate resources with ensure_packages and ensure_resource
package { ‘apache2’: ensure => present, }
ensure_packages([‘apache2’])
Validate inputs with validate_array, validate_bool, validate_hash, validate_re, and validate_string
Protect private classes with private
Modules should be easy to use and hard to abuse
StyleSubstance
Style is important
puppet-lint
puppet-syntax
source 'https://rubygems.org' !
gem 'rake' gem 'puppet' gem 'puppet-lint' gem 'puppet-syntax'
require 'puppet-lint/tasks/puppet-lint' require 'puppet-syntax/tasks/puppet-syntax' !exclude_paths = [ "pkg/**/*", "vendor/**/*", "spec/**/*", ] !PuppetLint.configuration.ignore_paths = exclude_paths PuppetSyntax.exclude_paths = exclude_paths
$ bundle install Fetching gem metadata from https://rubygems.org/........ Resolving dependencies... Installing rake 10.3.2 Installing CFPropertyList 2.2.8 Installing facter 2.1.0 Installing json_pure 1.8.1 Installing hiera 1.3.4 Installing rgen 0.6.6 Installing puppet 3.6.2 Installing puppet-lint 0.3.2 Installing puppet-syntax 1.3.0 Using bundler 1.6.2 Your bundle is complete! Use `bundle show [gemname]` to see where a bundled gem is installed.
$ bundle exec rake -T rake lint # Run puppet-lint rake syntax # Syntax check Puppet manifests and templates rake syntax:hiera # Syntax check Hiera config files rake syntax:manifests # Syntax check Puppet manifests rake syntax:templates # Syntax check Puppet templates
Documentation is important
We’re all Keynesians now.developers
Keeping Up
Puppet is evolving really fast
There is a fantastic community out there
Pay attention to thought leaders
Refactor your code as the language evolves
Contribute to modules on the Forge!
Questions?
Thank you!
Image Credits• http://officeimg.vo.msecnd.net/en-us/images/MP900430517.jpg • http://imgur.com/gallery/YNI5wud • http://www.reddit.com/r/funny/comments/1jgxtq/new_york_and_boston_the_difference/ • http://openclipart.org/detail/195046/ubuntu-geek-by-stephencuyos-195046 • http://design.ubuntu.com/downloads?metadata=element-logo+brand-ubuntu • http://commons.wikimedia.org/wiki/File:Ruby_on_Rails-logo.png • https://github.com/phusion/passenger • http://kaleidos.net/weapons/apache-webserver/ • http://puppetlabs.com/company/news/media-kit • http://copiousnotes.bloginky.com/2014/06/17/summer-classic-dr-strangelove-2/ • http://imgur.com/iWKad22 • http://cheezburger.com/6230961920 • http://www.craigdunn.org/stuff/puppet_big.png • http://www.quickmeme.com/meme/362un7 • http://programmerryangosling.tumblr.com/image/22790837971 • http://www.quickmeme.com/meme/3sogf9 • http://wall.alphacoders.com/big.php?i=238266
Further Reading• http://www.craigdunn.org/2012/05/239/ • https://www.youtube.com/user/PuppetLabsInc/playlists • https://github.com/puppetlabs/puppetlabs-stdlib • http://continuousdelivery.com • http://www.slideshare.net/PuppetLabs/tddforpuppet • http://www.slideshare.net/PuppetLabs/roles-rofiles • http://www.slideshare.net/PuppetLabs/steamlining-
puppetdevelopmentpuppetconfny2014 • http://garylarizza.com/blog/2013/12/08/when-to-hiera/ • http://www.devco.net/archives/2013/12/09/the-problem-with-params-pp.php • http://www.devco.net/archives/2013/12/08/better-puppet-modules-using-hiera-data.php • http://puppet-lint.com • https://github.com/gds-operations/puppet-syntax