initial commit
This commit is contained in:
commit
ca6a4d45d1
113 changed files with 10501 additions and 0 deletions
126
content/blog/how-i-classify-puppet-nodes/index.md
Normal file
126
content/blog/how-i-classify-puppet-nodes/index.md
Normal file
|
@ -0,0 +1,126 @@
|
|||
---
|
||||
date: 2015-09-10
|
||||
title: How I Classify Puppet Nodes
|
||||
category: devops
|
||||
---
|
||||
|
||||
The basics of defining what modules get applied to a particular node is
|
||||
really simple in Puppet. Out of the box you just use the hostname and
|
||||
the FQDN and everyone is happy. You find this everywhere in
|
||||
documentation, blog posts, presentations, etc. However is has a problem:
|
||||
scale.
|
||||
|
||||
What if you have an elastic infrastructure with nodes being created and
|
||||
destroyed automatically? What if you want to use the same manifests in
|
||||
different environment, but use different hostnames? What if you have
|
||||
stupidly complex host naming conventions that you cannot get your head
|
||||
round (current day job problem for me :-( )?
|
||||
|
||||
In all these cases and more, using the hostname to classify the node
|
||||
falls down. I like to add in Role that can then be access in 2 ways.
|
||||
With Hiera, one could do something like:
|
||||
|
||||
```
|
||||
:hierarchy:
|
||||
- "nodes/%{::trusted.certname}"
|
||||
- "roles/%{role}"
|
||||
- "%{environment}"
|
||||
- "%{osfamily}-osreleasemajor"
|
||||
- global
|
||||
```
|
||||
|
||||
And with in `site.pp` we can add in a simple `case` statement:
|
||||
|
||||
```
|
||||
node default {
|
||||
case $::role {
|
||||
'loadbalancer': {
|
||||
class { 'haproxy': }
|
||||
}
|
||||
'db': {
|
||||
class { 'mysql': }
|
||||
}
|
||||
default: {
|
||||
notify('no specific classes assigned')
|
||||
}
|
||||
}
|
||||
class { 'security': }
|
||||
}
|
||||
```
|
||||
|
||||
Now, we can still classify nodes individually but there is something in
|
||||
between the wider environment and OS categories that we can define
|
||||
ourselves. Of course we now need to define the role, which is everywhere
|
||||
from simple to complex or even not completely clear in my head for now.
|
||||
|
||||
I create a custom role fact that my manifests will look at. This is
|
||||
universal, no matter what mechanism is used to populate that fact that
|
||||
is the only place I will search in my Puppet code.
|
||||
|
||||
When your nodes are under Openstack or EC2, this is simple. They both
|
||||
have the concept of user-defined metadata as key-value pairs. I simple
|
||||
add a role pair:
|
||||
|
||||
```
|
||||
nova meta <instance-id> set role=loadbalancer
|
||||
```
|
||||
|
||||
You can also set this when you create the instance.
|
||||
|
||||
```
|
||||
nova boot --meta role=loadbalancer --<other-settings> <hostname>
|
||||
```
|
||||
|
||||
Now we just need the fact to look it up.
|
||||
|
||||
```
|
||||
require 'net/http'
|
||||
require 'json'
|
||||
require 'uri'
|
||||
|
||||
module RoleModule
|
||||
def self.add_facts
|
||||
Facter.add("role") do
|
||||
productname = Facter.value(:productname)
|
||||
case productname
|
||||
when 'OpenStack Nova'
|
||||
setcode do
|
||||
url= "http://169.254.169.254/openstack/latest/meta_data.json"
|
||||
uri = URI.parse(url)
|
||||
http = Net::HTTP.new(uri.host,uri.port)
|
||||
response = http.get(uri.path)
|
||||
JSON.parse(response.body)['meta']['role']
|
||||
end
|
||||
when 'ProLiant MicroServer'
|
||||
setcode do
|
||||
'lab-compute'
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
RoleModule.add_facts
|
||||
```
|
||||
|
||||
What is happening here? First it checks the productname fact so it can
|
||||
work out what to do. If that is OpenStack Nova then it knows that is
|
||||
needs to look in the Openstack Metadata service
|
||||
(<http://169.254.169.254/openstack/latest/meta_data.json>). Our
|
||||
key/value pair is returned as part of that JSON data and is pushed in to
|
||||
the role fact.
|
||||
|
||||
Likewise, if the productname is an HP Microserver, it will always be a
|
||||
lab compute node (in my case).
|
||||
|
||||
Physical machines otherwise fall down here. There is no way to
|
||||
dynamically modify their role, but I have a couple of solutions:
|
||||
|
||||
- Part of the kickstart file for provisioning the node could populate
|
||||
a configuration file (`/etc/role.conf`). If the `virtual` fact
|
||||
contains `physical` the role fact goes and looks it up from there.
|
||||
- A seperate node classification service that returns a role based on
|
||||
the contents of various facts that are passed via the custom fact
|
||||
code.
|
||||
|
||||
The important part with both of these is the classification is totally
|
||||
seperate from my Puppet code.
|
Loading…
Add table
Add a link
Reference in a new issue