Wednesday, September 13, 2017

chef-Role Playing

Reducing Complexity through Abstraction

What are Roles?

How should we use them?

§ Up till now, we've just been adding recipes directly to our node's run
list. Across a large number of nodes, this can be time consuming,
error prone and highly inefficient.
§ Roles allow you to easily encapsulate all of the recipes and attributes
required for a server to become:
A Web Server
An Application Server
A Database
§ In practice, Roles make it easy to configure many nodes identically
with the minimal amount of typing.

Best Practice: Roles belong in your source
control

§ At the Gap, roles live in the gapChef repo in the roles directory
§ This is the only way to create them at Gap.
§ You must check in your role to Git and then the Jenkins pipeline will
push your role to the Chef Servers
§ This is most important, because roles, like nodes and data bags are
unversioned objects in Chef.
§ Source control makes the tracking down of changes of these types of
files easy.

Create the webserver role

(roles/webserver.rb)
Create the webserver role

§ A Role has
− name
− description
− run_list
§ We can also set node attributes
with a role.


{
"name": "webserver",
"description": "Web Server",
"json_class": "Chef::Role",
"default_attributes": {
"mysite": {
"sites": {
"athleta": {
"port": 8000
}
}
}
},
"chef_type": "role",
"run_list": [
"recipe[mysite]"
]
}

This is JSON data, it takes " " and
loves commas.


Upload the webserver role

knife role from file webserver.json!


Updated Role webserver!!



Use knife to view role on Chef Server

knife role show webserver


chef_type: role
default_attributes:
mysite:
sites:
athleta:
port: 8000
description: Web Server
env_run_lists:
json_class: Chef::Role
name: webserver
override_attributes:
run_list: recipe[mysite]

knife search role 'run_list:recipe\[mysite\]'

1 items found

chef_type: role
default_attributes:
mysite:
sites:
athleta:
port: 8000
description: Web Server
env_run_lists:
json_class: Chef::Role
name: webserver
override_attributes:
run_list: recipe[mysite]

Best Practice: Nodes belong in your source
control

§ At the Gap, nodes also live in the gapChef repo..but in the nodes
directory
§ This is the only way to create them at Gap.
§ You must check in your node to Git and then the Jenkins pipeline will
push your node to the appropriate Chef Servers
§ This is most important, because nodes, like roles and data bags are
unversioned objects in Chef.
§ Download the node object from the chef server to your nodes
directory
§ $ knife node show node1 –Fj > node1.json

Edit the node's run_list to add our role

(nodes/node1.json)

{
"name": "node1",
"chef_environment": "_default",
"run_list": [
"role[webserver]",
"recipe[motd]",
"recipe[repos]"
],
"normal": {
"tags": [
]
}
}


Upload the node file to the Chef Server

knife node from file node1.json

Updated Node node1!

Show the node on the server again
(Where did our attributes go?)

knife node show node1 -l

Node Name: node1!
Environment: _default!
FQDN:!
IP:!
Run List: role[webserver], recipe[motd],!
Roles:!
Recipes:!
Platform:!
Tags:!
Attributes:!
tags:Default Attributes:!
Override Attributes:!
Automatic Attributes (Ohai Data):!

Run chef-client

sudo chef-client

[2015-08-16T17:32:38+00:00] INFO: Forking chef instance to
converge...!
Starting Chef Client, version 12.4.1!
[2015-08-16T17:32:38+00:00] INFO: *** Chef 12.4.1 ***!
[2015-08-16T17:32:38+00:00] INFO: Chef-client pid: 28316!
[2015-08-16T17:32:40+00:00] INFO: Run List is [role[webserver],
recipe[motd], recipe[repos]]!
[2015-08-16T17:32:40+00:00] INFO: Run List expands to [mysite,
motd, repos]!
[2015-08-16T17:32:40+00:00] INFO: Starting Chef Run for node1

* template[/srv/apache/athleta/index.html] action create!
[2015-08-16T17:32:45+00:00] INFO: Processing template[/srv/apache/athleta/index.html]
action create (mysite::default line 37)!
[2015-08-16T17:32:45+00:00] INFO: template[/srv/apache/athleta/index.html] created file /
srv/apache/athleta/index.html!
- create new file /srv/apache/athleta/index.html!
[2015-08-16T17:32:45+00:00] INFO: template[/srv/apache/athleta/index.html] updated file
contents /srv/apache/athleta/index.html!
- update content in file /srv/apache/athleta/index.html from none to 0540c0!
--- /srv/apache/athleta/index.html !2015-08-16 17:32:45.521000221 +0000!
+++ /tmp/chef-rendered-template20150816-28316-1mep5sm !2015-08-16 17:32:45.520000221
+0000!
@@ -1 +1,8 @@!
+<html>!
+ <body>!
+ <h1>Welcome to Gap, Inc.</h1>!
+ <h2>We love athleta</h2>!
+ 172.16.232.5:8000!
+ </body>!
+</html>!



Check your work!

Welcome to Gap inc

172.xxxxxxxxxxx

Attributes are attributes...

Its their precedence type and location will determine their fate in the merge

§ Our mysite cookbook has an attribute file that defines 2 sites:

default['mysite']['sites']['gap'] = { 'port' => 80 }
default['mysite’]['sites']['oldnavy'] = { 'port' => 81 }


While our webserver role has
attributes that define a new 3rd
site.

"default_attributes": {
"mysite": {
"sites": {
"athleta": {
"port": 8000
}
}
}
}

Display mysite.sites on all nodes running
our new role

knife search node 'role:webserver' -a mysite.sites

1 items found

node1:
mysite.sites:
athleta:
port: 8000
gap:
port: 80
oldnavy:
port: 81

Edit the webserver role

(roles/webserver.rb)


§ Add oldnavy to our role and
change its port to 8081
§ Don't forget the comma after the
altheta stanza

This is JSON data, it takes " " and
loves commas.

PRO TIP: Use your IDE to check
the syntax of your json file. Or go
to a site like http://jsonlint.com


{
"name": "webserver",
"description": "Web Server",
"json_class": "Chef::Role",
"default_attributes": {
"mysite": {
"sites": {
"athleta": {
"port": 8000
},
"oldnavy": {
"port": 8081
}
}
}
},
"chef_type": "role",
"run_list": [
"recipe[mysite]"
]
}

Upload the webserver role

knife role from file webserver.json

Updated Role webserver

Run chef-client
[
sudo chef-client

* template[/etc/httpd/conf.d/oldnavy.conf] action create!
[2015-08-16T18:19:20+00:00] INFO: Processing template[/etc/httpd/conf.d/oldnavy.conf]
action create (mysite::default line 22)!
[2015-08-16T18:19:20+00:00] INFO: template[/etc/httpd/conf.d/oldnavy.conf] backed up to /
var/chef/backup/etc/httpd/conf.d/oldnavy.conf.chef-20150816181920.646040!
[2015-08-16T18:19:20+00:00] INFO: template[/etc/httpd/conf.d/oldnavy.conf] updated file
contents /etc/httpd/conf.d/oldnavy.conf!
- update content in file /etc/httpd/conf.d/oldnavy.conf from 887e0a to 5d1642!
--- /etc/httpd/conf.d/oldnavy.conf !2015-08-16 02:43:30.824000202 +0000!
+++ /tmp/chef-rendered-template20150816-28617-fwve5 !2015-08-16 18:19:20.641000221
+0000!
@@ -1,6 +1,6 @@!
- Listen 81!
+ Listen 8081!
-<VirtualHost *:81>!
+<VirtualHost *:8081>!
ServerAdmin webmaster@localhost!
!
DocumentRoot /srv/apache/oldnavy!


Display mysite.sites on all nodes running
our new role

knife search node 'role:webserver' -a mysite.sites

1 items found

node1:
mysite.sites:
athleta:
port: 8000
gap:
port: 80
oldnavy:
port: 8081


Attribute Precedence

§ Attribute Precedence is determined by 3 factors:
§ Its precedence type
Automatic
Override
Default
§ Where the attribute is defined
attribute file
recipe
node
role
environment



Where it exists in the Nodes Run_List
Did we mention that Order Matters?


Best Practice: Roles set default attributes

§ While we can dabble with the various precedence types, in reality
there is little need to use anything other that default.
§ IF you always set default attributes in your cookbooks...
§ You can almost always set default attributes in your role and let the
merge do the rest

(If someone decides to start using force_default or normal...YMMV)


Best Practice: Use base roles!

§ In addition to obvious roles, such as "webserver", it is a common
practice to group any functionality that "goes together" in a role.
§ Enter the base role! This is where we can define all of the recipes
that we want to run on every node.
§ At Gap, we use the base role to:
Manage the client.rb on your node
Add in repos for your node
Add default monitoring to your node
Set NTP to make sure your node is in sync with our time server
Configure your node for LDAP authentication
And much much more...


Create the base.rb

(roles/base.rb)


name 'base'
description 'Base Server Role'
run_list 'recipe[motd]','recipe[repos]'


§ This role is written in Ruby syntax instead of JSON.
§ Most of our testing tool chain only uses JSON, so it is the preferred
format.


Upload the base role

knife role from file base.rb

Updated Role base!

Edit the node's run_list to add our base
role

(nodes/node1.json)

{
"name": "node1",
"chef_environment": "_default",
"run_list": [
"role[base]",
"role[webserver]",
"recipe[motd]"],
"recipe[repos]"
],
"normal": {
"tags": [
]
}
}


Upload the node file to the Chef Server

knife node from file node1.json

Updated Node node1


Run chef-client
[
sudo chef-client

[2015-08-16T19:15:11+00:00] INFO: Forking chef instance to converge...!
Starting Chef Client, version 12.4.1!
[2015-08-16T19:15:11+00:00] INFO: *** Chef 12.4.1 ***!
[2015-08-16T19:15:11+00:00] INFO: Chef-client pid: 28901!
[2015-08-16T19:15:13+00:00] INFO: Run List is [role[base], role[webserver],
recipe[motd], recipe[repos]]!
[2015-08-16T19:15:13+00:00] INFO: Run List expands to [motd, repos, mysite]!
[2015-08-16T19:15:13+00:00] INFO: Starting Chef Run for node1!
[2015-08-16T19:15:13+00:00] INFO: Running start handlers!
[2015-08-16T19:15:13+00:00] INFO: Start handlers complete.!
[2015-08-16T19:15:13+00:00] INFO: HTTP Request Returned 404 Not Found:!
resolving cookbooks for run list: ["motd", "repos", "mysite"]!
[2015-08-16T19:15:13+00:00] INFO: Loading cookbooks [motd@0.1.0, pci@0.1.0,
repos@0.1.0, mysite@0.2.0]!

Best Practice: Be explicit about what you
need or expect!

§ Chef will only execute a recipe the first time it appears in the run list
§ BE EXPLICIT about what you need for for your run list either by
nesting roles or using include_recipe
§ Use them liberally

Clean up your Nodes Run List

Go ahead and set your node's run list to just:
§ 'role[base]', 'role[webserver]'
Tell me 3 ways to do this?
(I'll let you decide how to do it)












No comments:

Post a Comment