Component Pattern

This is part of a series of posts on puppet patterns. If you can spot any flaws or think of better solutions let me know!

This pattern is similar to the PuppetLabs best practices of roles and profiles. If you’re not using roles and profiles it’s a good idea to look into them, there’s a post by Craig Dunn which explains it really well. The basic idea is reuse via abstraction. There’s an acronym in development DRY which stands for Don’t Repeat Yourself (the antitheses being WET, Write Everything Twice, so smart!!) so we try to “dry out” our code by reducing all the times we repeat ourselves. So we use profiles to abstract classes and roles to abstract profiles:

node webserver01 {
  include role::webserver
}

node webserver02 {
  include role::webserver
}

class role::webserver {
  include profile::tomcat
  # other profiles
}

class profile::tomcat {
  # include classes and/or add parameterised classes
}

Instead of defining all the classes we need with all the parameters etc on every node, we wrap all related classes together into profiles and then group the profiles into roles. Yes we could define both nodes as a comma separated list, but pretend they’re in different files! This pattern also works well if you’re using an ENC, each node only has one role so that’s a lot less configuration/management in the ENC

Roles and profiles look just like normal modules:

puppet
  - modules
    - role
      - manifests
        - webserver.pp
    - profiles
      - manifests
        - tomcat.pp

I have found one downside though. Even in a relatively non-trivial environment structure, by the time you’ve created roles to describe every different type of machine in all of your environments, your role names either become too long and cumbersome, or they become too vague and unclear.

The component pattern is designed to be an abstraction on top of profiles that focuses on the deployed components on the nodes instead of the role of the node as a whole:

node webserver01, webserver02 {
  include component::company_webapp
}

node apiserver01, apiserver02 {
  include component::search_api
  include component::rest_api
}

node dbserver01 {
  include component::main_db
}

node testserver01 {
  include component::company_webapp
  include component::search_api
  include component::rest_api
  include component::main_db
}

class component::company_webapp {
  include profiles::tomcat
  include profiles::company_webapp
  # other profiles
}

class component::search_api {
  include profiles::tomcat
  include profiles::search_api
  # other profiles
}

class component::main_db {
  include profiles::mysql
  include profiles::main_db
  # other profiles
}

Each component has everything it needs to run in isolation, but you can also put all your components on one node if you want too, even if they share resources e.g. the webapp and both APIs are probably all going to run on the same JVM behind the same instance of tomcat, but because of the way we structure our components, profiles and classes, any combination should be possible (assuming your apps play nicely together)

Yes, it’s a bit more code in the node definitions and there is more potential for repetition, but I think the node definitions are a lot more transparent and the component classes are reusable all over the place allowing you to structure your environments however you want.

Thera are some wins for ENCs too. You can create new environments and new layouts, or add components to existing nodes without having to create new roles. You can also give more context to your ENC because you’re now defining nodes by the components that are running on them rather than the role. I came up with this pattern when I was working out how to structure a release orchestration tool I’m tinkering with. I can now define components in the tool’s database and assign them to nodes in a layout in any combination and then easily translate that layout into ENC definitions.

So component classes only include profiles and have everything they need to run your component. However they are also designed to run side by side with any other components allowing any combination you want.

Advertisements

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s