Now that you have a sandbox environment in which to experiment with Chef, let’s set up your guest system to be managed by Chef. In this chapter, you will use Test Kitchen to install Chef Client on your guest virtual machine so it can run Chef recipes. As a reminder, in Chapter 4 you learned that a Chef recipe is a file that contains Chef code.
What Is a Node?
Before we show you how to install Chef Client on the guest with Test Kitchen, let’s first introduce some Chef-specific terminology to describe the different types of machines that we are now using.
The machine on which you author Chef code is referred to as the Chef Developer’s Workstation or Chef Administrator’s Workstation. Your host machine is your Chef Developer Workstation. In Chapter 2 you installed the Chef Development Kit on your host so that you have all the tools necessary to write Chef recipes using a programmer’s editor and to manage changes to your Chef code with a source control system.
A machine that is managed by Chef is called a node. A machine is managed by Chef when it runs Chef recipes to ensure the machine is in a desired configuration, as shown in Chapter 4. A node can be a physical machine, a virtual machine, a cloud instance, or a container instance—it makes no difference to Chef. As long as the node has Chef Client installed, it can be managed by Chef and it can run Chef recipes.
Because the Chef Development Kit is a superset of Chef Client, you could install the Chef Development Kit on a node. This is what we did in Chapter 4, making your host act as both a Chef Developer Workstation and as a node managed by Chef. However, the Chef Development Kit is about double the footprint of Chef Client. All of the extra tools included with the Chef Development Kit are for writing Chef code, not running Chef code. In Chapter 5 we made the case that in real-world production environments, these roles are split between two different machines because you do not write Chef code on every machine in your infrastructure. We are using Test Kitchen to manage a sandbox environment running CentOS 6 as a guest virtual machine. Now we need to make the guest virtual machine a Chef node.
NOTE
Chef uses the generic term node because Chef is not limited to managing servers or compute nodes. Chef can manage other components in your infrastructure as well, such as switches, routers, and storage.
Going forward, we will refer to your guest virtual machine sandbox environment simply as a node. In fact, you might not even be using a guest virtual machine if you decided to opt for the alternative setups covered on http://learningchef.com. So it makes sense to just refer to the “other machine” being managed by Chef generically as a node.
Create a New Sandbox Environment for a Node
Within the directory structure you have created for this book’s code, as outlined in Create a Directory Structure for Your Code, create a project directory to contain the sandbox environment for your node. Create a new directory called node and make it the current directory, just like you did in Chapter 5. For example:
Then perform the same steps you performed in Chapter 5, running
kitchen init
to generate all the required Test Kitchen configuration, and bundle install
to install the supporting gems:
In this case, running
bundle install
is really not necessary, because you are setting up a sandbox environment identical to the one you created in Chapter 5. However, it is a good idea to acquire the habit of running bundle install
after kitchen init
.
Edit the .kitchen.yml file as shown in Example 6-1, and make it resemble the state of the final .kitchen.yml when you finished Chapter 5.
Then run
kitchen create
to spin up a new sandbox environment to serve as your node. As before, it will use the cached version of the learningchef/centos65
box, and Test Kitchen will not try to download the box again if it sees the box in the cache. So the sandbox environment should start fairly quickly, in less than a minute:Installing Chef Client with Test Kitchen
Use the
kitchen login
command to connect to your node (a.k.a. the sandbox environment), and access the command prompt of the node running CentOS 6. Then, check to see if the Chef Client is installed on the node by running chef-client --version
:
Nope, doesn’t seem to be installed. How do we install
chef-client
on the node? Although we could follow the instructions again for Installing Chef Client on Linux from Chapter 2 by running the following, don’t do this:
There is an easier way. Type in the
exit
command on your node to get back to your host prompt:
Double-check to make sure that the prompt being displayed is actually your host prompt (no
vagrant@default-centos65
). Run the command kitchen setup default-centos65
to install chef-client
:
If you inspect the output, the
kitchen setup
command installed the chef-client
for you. The kitchen setup
command is used to run a provisioner. Provisioner is a generic term for any kind of configuration management software, as Test Kitchen can be used with other configuration management tools besides Chef. By default, Test Kitchen is configured to use the ChefSolo provisioner, which installs Chef Client without configuring the tools to use a Chef Server. kitchen setup
will automatically install chef-client
for you using the commands you entered in Chapter 2 if chef-client
is not present.
If you run
kitchen list
now, you’ll notice that the Last Action
column changed from Created to Set Up:Your First Chef-Client Run
Although you could use
chef-apply
to execute code in a Chef recipe file like you did in Chapter 4, the chef-client
tool is more commonly used in production environments. chef-client
provides the ability to execute Chef code across multiple recipe files, which we’ll see more of in Chapter 7. In order to manage real-world production environments, you’ll be running a lot of Chef code. In order to make maintenance easier, one normally spreads production code across multiple recipe files. Although chef-apply
will do in a pinch for simple management tasks, you’ll end up using chef-client
most of the time to manage a node with Chef.
To show you the basics of using
chef-client
, let’s create a new Chef recipe file that prints out some of the information Chef maintains about each node.
The
log
resource can be used to print out strings from a recipe. For example, the statement log "Hello"
in a recipe would write out the string Hello
. Let’s give this a try. We assume you’re still logged in to the node environment. Create the file hello.rb on the node with the following command:NOTE
In Chapter 7 we will show you how to edit files in your host environment and automatically transfer them to the node. Until then, we’re showing you commands that you can use to create hello.rb in lieu of using editors such as
vi
or nano
directly on the node. Some readers might not feel comfortable with editing files in a Linux-based operating environment. Feel free to use a text editor instead.
This command will produce the following source file.
When you use
chef-client
to perform actions in a recipe, this is referred to as a Chef run. Execute your first Chef run by entering chef-client --local-mode hello.rb
--log_level
info
on a command line. The --local-mode
option will prevent chef-client
from trying to time out looking for a nonexistent Chef Server. We will introduce Chef Server later in this book. The --log_level info
option is also necessary because by default, chef-client
will only print errors, not informative messages. This option will tell chef-client
to print out the strings from any Chef::Log.info
commands.NOTE
When you run
chef-client --local-mode hello.rb
on the node, the output should resemble the following:
During your
chef-client
run, the following output indicates that “Hello, this is an important message.” was written to the log for the Chef run:
To actually see the log message, you need to change the
chef-client
log level. Every message written to the log has severity level. The levels, in order of priority from lowest to highest, are debug
, info
, warn
, error
, and fatal
. The log
resource uses the info
level as a default, which is appropriate for your “Hello” message. However, chef-client
only prints out messages of severity warn
or greater unless you change the chef-client
log level.
To change the log level, use the
--log_level
option. The --log_level
option takes a parameter (--log_level
<level>), changing the lowest level severity messages chef-client
will write to its log. If you add the option --log_level info
to your chef-client
command line, it will display the log message you just added. Try that now:
By default,
chef-client
prints out log messages to the screen. Now that you have reset the log level, you see your important message in the log output (along with some other messages that are also at the info
level of severity).Chef Client Modes
- Local mode
- Client mode
- Solo mode
When
chef-client
is running in local mode, it simulates a full Chef Server instance in memory. Any data that would have been saved to a server is written to the local directory. The process of writing server data locally is called writeback. This is why client-client
created the nodes/ directory. Local mode was designed to support rapid Chef recipe development by using Chef Zero, the in-memory, fast-start Chef server.
On the other hand, when
chef-client
is running in client mode, it assumes you have a Chef Server running on some other system on your network. In production, this is how most people use Chef. In client mode, chef-client
is an agent (or service/daemon) that runs locally on a machine managed by Chef. Chef Server is a centralized store for the information needed to manage infrastructure with Chef. It is recommended that you set up Chef Server when you need to manage more than one machine at a time.
Before
chef-client
local mode was implemented in version 11.8, the only way to run Chef recipes without a Chef Server was to use chef-solo
. chef-solo
offers an additional client mode called solo mode. Solo mode provides a limited subset of Chef functionality intended to be able to run Chef locally. chef-solo
does not support writeback. In most cases, local mode is far more convenient to use than solo mode. Eventually, Chef software plans to retire solo mode once local mode has feature parity with solo and when the majority of customers have migrated to chef-client
11.8 or higher. Solo mode is most popular in places still using older versions of Chef.Ohai
When Chef Client performs a Chef run, a separate command-line tool called
ohai
is used to collect system information. Ohai exposes this collection of node information to Chef as a set of automatic attributes.
Try running
ohai
yourself, so you can see what information is being collected about your node. On our system, ohai
generates 1058 lines of output, so make sure you pipe the command’s output through the more
command to present the information a screen at a time. You don’t have to look through the whole output. When you’re done, hit the q key to exit back to the command line:
As you can see,
ohai
collects a lot of information about the current state of the computer: networking configuration, CPU state, operating system type and version, memory consumption, and much, much more.
As an example, let’s take a look at this subset of the information generated by
ohai
. As you can see in the following, ohai
collects the node’s IP address, MAC address, OS information, hostname, and even that we are running in a virtualized guest:
In the next section, we’ll access the information collected by
ohai
in our Chef code. Let’s learn more about how the information gets into Chef and how we can refer to this information in our code.ohai
output is in JavaScript Simple Object Notation (JSON) form. JSON is a commonly used format for machine-readable output, as it can be easily parsed into the object-representation used for programming languages like Ruby. Although you can run ohai
as a standalone application, this is not very common. Instead, the output of ohai
is intended to be read by machines, specifically by chef-client
and associated tools, so JSON is the perfect format. chef-client
reads the JSON output from ohai
and converts it into a node
object, which is accessible by your Chef code.
You can refer to the node’s IP address in your code with the following attribute. An attribute is a variable maintained by Chef. In your code, you specify a quoted string in a pair of brackets with the name used as an index in the collection, then Chef will return the value. In this case, we want to know the IP address. By referring to the prior
ohai
output, Chef knows the index name is ipaddress
:
We used an attribute variable in our Chef code back in Recipes Specify Desired Configuration.
node
is another attribute Chef makes available to your code. It contains all the information generated by running ohai
on the node. Similar to the ENV
attribute we used in Recipes Specify Desired Configuration, the node
attribute is a collection of name/value pairs.
Name/value pair collections can be nested. This is what is indicated in the multiple levels of indentation in the
ohai
output. So to access the kind of virtualization software we are using (the “virtualization system”), use the following nested set of name/value pair references, because system
is a name/value pair within the virtualization
collection:NOTE
The string variant
node['virtualization']['system']
tends to be the most commonly used node attribute form. However, because attribute expressions are evaluated as a Mash
, you’ll encounter Chef code that uses the other possible Mash
variants:node[:virtualization][:system]
node['virtualization']['system']
node.virtualization.system
Use a form that makes the most sense to you.
Accessing Node Information
As we discussed in the last section,
chef-client
collects a lot of information about the state of a node using ohai
. Collecting this information is necessary so that Chef can intelligently reason how to put the node into the desired configuration specified in a recipe. Chef does not keep this information to itself. It makes this information available to your Chef code as a node
attribute. An attribute is a variable maintained by Chef.
Let’s use the
log
resource that you just used in Your First Chef-Client Run to print out some node
information. Create a new file called info.rb on the node with the following sequence of commands:
This command will produce the source file seen in Example 6-3.
The syntax using
#{<variable>}
to print out information contained in variables should be familiar to you. This is similar to what we did in Chapter 4 to access #{ENV['HOME']}
. In this case, the variable is node
instead of ENV
.
The
log
statements in Example 6-3 will produce the following output during your Chef run. The use of log
statements to show the content of attributes is a recommended Chef recipe debugging technique:
You should still be logged into the node. Perform a Chef run using
chef-client
in local mode. This time we will use the short options for --local-mode
and --log_level
. The output should resemble the following:
Notice that
chef-client
printed out the relevant information about your node. Your data should be similar, but some of the details, such as the IP Address
, will most likely be slightly different. Chef collects a great deal of information about the state of a target machine in the node object. This node information is used to make intelligent decisions about how to automatically place the node into a desired configuration.
Run the
exit
command to get back to the host prompt, then run kitchen destroy default-centos65
. This will shut down the VM and destroy the instance in your virtualization software, as you are done with this instance for now:Summary
In this chapter, we introduced the concept of a node. Because Chef can manage things other than personal computers, such as network switches and embedded storage systems, Chef uses the more generic term node to refer to the entities managed by Chef instead of server or host.
Any entity managed by Chef must have Chef Client installed. We showed you how to use Test Kitchen to install Chef Client on a node while writing Chef code. In Bootstrap the Node with Knife, we’ll show you how the
knife bootstrap
command is used to install Chef Client on production nodes, as Test Kitchen isn’t intended for production use.
You learned how to use the
chef-client
tool to perform a Chef run. This is how Chef manages a node. chef-client
reads recipes during a Chef run. Recipes indicate a desired configuration through resources, and Chef determines the optimal sequence of steps in order to put the node into the desired state. Chef is able to reason intelligently about the node configuration, because it collects detailed information about the state of a node in an associated node attribute
based on the information collected by ohai
. We also showed you how you can access the information in your Chef recipes.
In the next chapter, we’ll show you how to organize multiple recipe files into a cookbook. We’ll also show you how you can run
chef-client
on a node using Test Kitchen on your host instead of hopping back and forth between the host and the guest.
No comments:
Post a Comment