Skip to content

Instantly share code, notes, and snippets.

@jgn
Created May 20, 2012 17:19
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 1 You must be signed in to fork a gist
  • Save jgn/2758806 to your computer and use it in GitHub Desktop.
Save jgn/2758806 to your computer and use it in GitHub Desktop.

Stuff I learned about Puppet

Chef vs Puppet

  • My blink is that in 2012 Puppet is safer and more productive.
  • Puppet is declarative, Chef procedural.
  • Puppet brings system into compliance (state), Chef "does" things (recipes).
  • Puppet has strong security practices; Chef has a toleration for loose security in Chef itself.
  • Puppet makes it very hard to get "outside the lines" or violate its strong opinions; in Chef this is routine.

Puppet standalone becoming a "best practice"?

Not used very much, but . . .

Best things about Puppet

  • Declarative, not procedural.
  • Feels Ruby-ish. But never think that it is Ruby.
  • The fact, though, that it isn't Ruby is arguably good: One seeks for the best "Puppet"-style solution.

Worst thing about Puppet

  • Not Ruby. It has its own syntax. Lots of opportunities for screwups.
  • Difficult to understand differences between fundamental resources and what goes where (e.g., classes, modules, nodes).
  • Very hard to understand scopes.
  • Hard to inject.

Something apparently not used much: The Ruby DSL

Language oddities: "class"

  • A Puppet class is really something like a class, but everything inside of it "runs" as class-level behavior. There seem to be no "instances" of classes.
  • This is a big deal. When you import (include?) a class, its behavior runs.

Language oddities: "module"

  • Gotcha: There is really no such thing as a module
  • It just happens that a module is a directory with a conventional pattern

Not clear if puppet user is really required

  • Our config has a puppet user with a local Ruby 1.8.7 and its own gems.
  • The puppet user has a ~/.puppet directory; not clear if in play.

Definitely want default puppet file hierarchy

etc/
  puppet/
    puppet.conf
    manifests/
      site.pp     # manifest for site
    modules/
      # your modules here

Where do environment params go? Not clear

I put them in a module called icis::params

# /etc/puppet/modules/icis/manifests/params.pp
class icis::params {
  $faye_port = $environment ? {
    production    =>  9293,
    preproduction =>  9293,
    staging       =>  9292,
    training      =>  9294,
    vagrant       =>  9295,
    rackspace     =>  9296,
    bluebox       =>  9297,
    default       =>  fail("No defined faye port for #{environment}")
  }
}

Then these are injected, via the site manifest, into other modules:

# /etc/puppet/manifests/site.pp
include icis
class {'nginx':
  faye_port => $icis::params::faye_port,
}

(NOTICE: class {'nginx': ... } is essentially the same as include nginx but the class syntax allows the injection of parameters.)

The nginx class is defined to take a parameter:

# /etc/puppet/modules/nginx/manifests/init.pp
class nginx($faye_port) {

  # [much deleted]

  file { "/opt/nginx/conf/sites-available/${environment}.icisapp.com.conf":
    ensure      => file,
    content     => template('nginx/environment.icisapp.com.conf.erb'),
  }

  # [much deleted]
}

Then the $faye_port variable is used in the erb template like this:

# /etc/puppet/modules/nginx/templates/environment.icisapp.com.conf.erb
server {
  server_name faye<%= environment %>.icisapp.com;
  listen 443;

  location / {
    proxy_pass https://localhost:<%= faye_port %>;
  }
}

Very easy to screw up String interpolation

Ruby: "#{whatever}"
Puppet: "${whatever}"

No such thing as mkdir -p in Puppet

Instead,

file {
    [
      "/var/www/",
      "/var/www/${environment}.icisapp.com/",
      "/var/www/${environment}.icisapp.com/logs/",
    ]:
  ensure      => directory,
}

No support for service reloads

Instead,

exec { 'reload':
  command     => '/sbin/service nginx force-reload',
  refreshonly => true,
}

File['/opt/nginx/conf/nginx.conf'] -> Exec['reload']
File["/opt/nginx/conf/sites-available/${environment}.icisapp.com.conf"]
  -> Exec['reload']

No clarity at how a "shared" resource is used

Example: When we have a shared resource such as nginx.conf, we may want lines in that file for each particular environment. The patterns for this in Puppet look difficult.

To get this, we created a directory called sites-available/ (like Apache), and then when extra nginx config is needed, the environment-specific file is put in place.

However, this is problematic if we remove a shared resource. Puppet is good for declarative creation of resources, but to remove a resource would imply that to build the server, you need to build all of the environments at the same time, so that sites-available/ doesn't have leftovers from old setups.

What can be "removed" in Puppet? A "package" (see http://puppetcookbook.com/posts/remove-package.html). This suggests that the ICIS "identify" is itself a package, not a module.

Little clarity as to how you would set up virtual servers across distros

Few docs that explain how to write a single Puppet module that would work right across Centos, Ubuntu, etc. For example, our ICIS nginx setup makes assumptions about directory locations that probably won't work on Ubuntu. But see http://puppetcookbook.com/posts/packages-with-different-name-per-distro.html

Big tension between Capistrano roles and Puppet roles

E.g., http://semicomplete.com/presentations/puppet-presentation/puppet-at-loggly.html

How do you keep a Capistrano role (database) with a Puppet role (database)? E.g., where do migrations run? Should Capistrano look up role assignments from somewhere else?

Best parts of Puppet official docs

Learning Puppet: http://docs.puppetlabs.com/learning/ Language: http://docs.puppetlabs.com/guides/language_guide.html Types: http://docs.puppetlabs.com/references/latest/type.html Cheat sheet: referenced from: http://puppetlabs.com/blog/learning-puppet-and-cheat-sheets/

Better docs outside of Puppet official docs

@knoopx
Copy link

knoopx commented Oct 25, 2012

Wow, thanks for sharing this!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment