We’ve shown you how much you can do with Chef without ever needing to install its server component. However, to get the full benefits of Chef, you need to set up a Chef Server in your production environment. Using a Chef Server is recommended when you need to manage more than one machine at a time with Chef, which is typically how Chef is used. Chef Server adds more capabilities that can be used in your cookbooks, including roles, environments, data bags, and powerful search.
As of this writing, there are three flavors of Chef Server, as detailed in Table 9-1. Although there are subtle differences, they all contain common features, including an API endpoint, data bags, environments, node objects, roles, and search. Some of these terms are new; we will cover them in the remaining chapters of the book.
Table 9-1. Types of Chef Server
Chef Server is the centralized store for configuration data in your infrastructure. It stores and indexes cookbooks, environments, templates, metadata, files, and distribution policies. Chef Server is aware of all machines it manages, and in this way, Chef Server also acts as an inventory management system.
As of Chef 11, Chef Server is written in Erlang, a programming language designed with concurrency in mind. Chef Server is also composed of a web server, cookbook store, web interface, messaging queue, and backend database. Figure 9-1 shows how each of these pieces interact.
- Web server
- The nginx web server is a simple reverse proxy server that acts as the front-end interface for Chef Server (Erchef). It also performs load balancing for Chef Server. All requests to the Chef Server API are routed through the nginx web server.
- WebUI
- The WebUI is the consumer-facing web application. It is a Ruby on Rails application that provides a web-guided user interface for interacting with Chef Server.
- Chef Server
- Erchef is the component of Chef Server that processes API requests. As its name suggests, Chef Server is written in Erlang for high concurrency and reliability. Even though Chef Server is written in Erlang, it is still capable of running Ruby code. In fact, writing Erlang Chef recipes is not supported at this writing. Erchef is the core API for Chef Server.
- Bookshelf
- The Bookshelf is the central store for all Chef cookbooks and cookbook contents (such as files, templates, definitions, metadata, and recipes). Each cookbook is automatically checksummed and versioned. Bookshelf is a flat-file database and is intentionally stored outside of Chef Server’s index.
- Search Index
- The Search Index is an Apache Solr server that handles the indexing and searching mechanism for various API calls, both internally and externally. The server is wrapped by
chef-solr
, which exposes a RESTful API. - Message queues
- The queues handle all messages that are sent to the Search Index for parsing. The queues are managed by RabbitMQ, an open source queuing system.
chef-expander
pulls messages from the message queues, formats the messages, and then sends the messages to the Search Index. - Database
- The database is a PostgreSQL persistent data store. Prior to Chef 11, the data store was CouchDB, but was moved to PostgreSQL due to CouchDB’s inability to scale.
In the first part of this chapter, we’ll install Enterprise Chef On-Premises Server in a sandbox environment using Test Kitchen. In order to set up the server in a virtual machine, you’ll need at least 2 GB of free memory on your machine—1.5 GB for Chef Server itself plus 512 MB for the accompanying node.
With Enterprise Chef On-Premises, you can manage up to five nodes for free, more than enough for learning all the enterprise capabilities of Chef Server. Appendix A covers the installation of Open Source Chef Server, should you not wish to provide contact information and don’t currently need the advanced capabilities of Enterprise Chef in your organization. With Open Source Chef Server, you can manage an unlimited number of nodes for free. Appendix B presents a similar overview of Hosted Enterprise Chef, should you wish to explore the Chef—it also offers the ability manage up to five nodes with its free tier.
How to Install Enterprise Chef Server Manually
As shown in Figure 9-2, go to http://www.getchef.com/contact/on-premises and provide your contact information to receive download details and installation instructions for Enterprise Chef Server.
Once you accept the agreement, you’ll be presented a download link page as shown in Figure 9-3. Bookmark this download link page in your web browser for future reference. Copy the link for the Red Hat Enterprise Linux 6 download, as shown.
To manually replicate a basic Enterprise Chef install in a cookbook, we first need to download the Enterprise Chef Server install package for Red Hat Enterprise Linux 6, as we’ll be installing on CentOS 6.5. To match the exercises in the book, use version 11.1.8. Use the Copy Link Address option on the download link to copy the full download URL to your clipboard.
NOTE
The download page may not match the images presented in this book exactly. The download and install procedure should be similar even if the web presentation is different.
The rest of the steps necessary to install Chef Server are displayed below the download link:
- Install the chef-server package.
- Run
sudo private-chef-ctl reconfigure
.
Install Enterprise Chef Server
Assuming you have sufficient resources to install Enterprise Chef Server locally along with a test node, let’s create an
enterprise-chef
cookbook that will install Enterprise Chef Server. To maintain consistency with Hosted Enterprise Chef, create the directory chef-repo/cookbooks and create the enterprise
cookbook in that directory. Having a top-level chef-repo
directory will help you handle the additional files necessary to manage Enterprise Chef beyond the cookbooks themselves. You’ll definitely be using more than one cookbook in your organization, so we suggest putting them in a chef-repo/cookbooks subdirectory.
Create the chef-repo/cookbooks directory and make it the current working directory.
Linux/Mac OS X:
Windows:
Then generate the
enterprise-chef
cookbook with chef generate cookbook
or knife cookbook create
, depending on whether you are using the Chef Development Kit or the Chef Client. We’re going to go through the cookbook creation steps quickly in this chapter. If you need a refresher on what each of these commands mean and the expected output, refer back to Chapter 7.
Chef Development Kit:
Chef Client:
As shown in Example 9-1, edit the .kitchen.yml file to use the CentOS 6.5 basebox we prepared specifically for this book. Also, assign a private network address like we did in Chapter 7. This time, we’re going to use the IP address
192.168.33.34
. If this conflicts with an address already being used on your local network, change it to a nonconflicting one. We also need more memory than the default 512 MB allocated, so add a customize:
block with a memory:
statement to increase the memory to 1.5 GB (memory is specified in megabytes only).NOTE
Make sure that you use the
chef_solo
provisioner for this cookbook, as the in-memory Chef Server the chef_zero
provisioner spawns will cause a conflict with the hands-on exercises coming up in Chapter 10. As of this writing, if you want to automate the installation of a Chef Server with Chef cookbooks, using Chef Solo is recommended so that the deployment code doesn’t get confused by the presence of the in-memory Chef Server used in Chef Zero.
Generate a default attributes file in attributes/default.rb.
Chef Development Kit:
Chef Client:
Add an attribute specifying the download URL for the Chef Server package that you obtained from the Enterprise Chef download link page. We recommend using the 11.1.8 version URL as shown in Example 9-2, as we wrote the examples for this chapter for this version of Chef.
Let’s take an initial stab at coding a recipe to replicate the manual steps to install Chef Server outlined in How to Install Enterprise Chef Server Manually. Enter in the first version of the code as shown in Example 9-3. Let’s go over some of the highlights of the code in the following paragraphs.
Rather than typing in long variable names like
node['enterprise-chef']['url']
, feel free to use temporary local variables in a recipe with shorter names, such as:
Remember that you have the full power of Ruby classes and methods available to you in your Chef recipes, so don’t be afraid to use it. For example, you can use the
::File.basename()
method to extract the package name from the URL. The package name is the last component of the URL after the forward slash (“/”): private-chef-11.1.8-1.el6.x86_64.rpm
. Refer to the Ruby core API documentation for more information on the ::File
class:
Unfortunately, the
package
resource does not work with URLs, so we’re introducing a new resource, theremote_file
resource. The remote_file
resource will download files from a remote location. Rather than hardcoding a path like “/tmp” for the package download, Chef provides a variable you should use instead: Chef::Config[:file_cache_path]
. Let Chef choose the best place to store temporary files for you. Pass the local path where you want to store the file as a string parameter to remote_file
or as a name
attribute; in this case, we use the package_local_path
variable. The download URL should be passed to remote_file
as the source
attribute.
The
package
resource should be familiar to you by now, as we used it in Chapter 7.
In order to execute the
chef-server-ctl reconfigure
, we need to introduce another new resource, theexecute
resource. When you fail to find a resource that meets your needs, you can use the execute
resource to run arbitrary shell commands. Pass the shell command you want to execute as a string parameter to the execute
resource.
Here’s the full code listing shown in Example 9-3.
Introducing Idempotence
Although the recipe we created in Example 9-3 is a good first attempt, it is not idempotent. When Chef code is idempotent, it can run multiple times on the same system and the results will always be identical, without producing unintended side effects. All Chef default resources are guaranteed to be idempotent with the exception of the
execute
resource.execute
resources are generally not idempotent, because most command-line utilities can be run only once. They assume that a human being is interacting with the system and understands the state of the system. For example, assuming the file /learningchef/file1.txt exists, the following mv
command will work the first time it is run, but it will fail the second time:
A great way to test to see if your recipe is idempotent is to run
kitchen converge
twice. When a recipe has no unintended side effects, there should be 0 resources updated on the second run.
Does our recipe pass the idempotency test? Sadly, no. Here’s a sampling of the output from an initial
kitchen converge
:
Here’s the output from the second run. Chef mistakenly thinks there’s still stuff it needs to do—2/3 resources updated in this second run. If the recipe were truly idempotent, we’d see 0/3 resources updated. Chef would inspect the state of the system, recognize that nothing had changed since the last run—no one touched the node between the two runs—and perform no resource updates:
As mentioned earlier, most default Chef resources are idempotent. Notice that the remote_file resource is idempotent. It is reporting
(up to date)
. The package resource is normally idempotent. We specifically crafted this example to show you a platform-specific quirk related to idempotency when it is used on RedHat-variant platforms, such as CentOS, which we’ll show you how to address.
There are some issues with the
package
and execute
resources, however, as on the second kitchen converge
run Chef:- Reinstalled the rpm package, unnecessarily
- Executed
chef-server-ctl reconfigure
a second time
Let’s fix these idempotency issues in our code now. Example 9-4 has the final idempotent version of the code.
The first issue is a common one that Chef developers encounter with the
package
resource when they try to install from a downloaded rpm
instead of using a package repository. Instead of using a package
one-liner for a downloaded rpm
, you need to tell the package
resource to explicitly use the Chef::Provider::Package::Rpm
provider using the provider
attribute. You also need to specify the string representing the package name using the source
attribute, like so:NOTE
You can use the
rpm_package
short name to specify Chef::Provider::Package::Rpm
to the package
resource, if you prefer. The following code is equivalent to the preceding code:
Fixing the second issue with the
execute
resource is a little more involved. That’s why you should prefer built-in Chef resources over using the execute
resource, because it’s up to you to make the execute resources idempotent.
One way to fix this issue is with a
not_if
guard to the execute
resource. Guards are used to make a resource idempotent by allowing the resource to test for a desired state, and if the desired state is present, the resource should do nothing. In this case, we’ll test to see if the chef-server package is already installed, by adding a not_if
clause to the execute
resource as follows. not_if
will test to see if the exit code of the command is 0; if so, the resource does nothing.NOTE
If you need to test the opposite logic of
not_if
, there is also an only_if
guard. It’s more typical to use only_if
on Windows, given that a successful exit code for Windows commands is frequently the value 1 instead of 0. Take a look at http://bit.ly/common_functionality for more information.
Although this is a reasonable way to address the issue, it’s a little clunky. You have to figure out a way to detect whether Chef Server is installed, and the method used in the previous example is not very reliable. A better approach is to trigger the execute when the
package
resource installs the package. You can trigger events in other resources with a notifies statement.
In order to use
notifies
, we’ll need to change the execute
resource statement a bit. First, you’ll want to change the resource so it does nothing by default when execute
is evaluated during the Chef run; we do this by adding an action :nothing
attribute. Also, you’ll want to move the actual command line explicitly to the command
attribute, so you can use a short name to trigger the execute block. By default, the name
passed to the execute
resource as a string parameter is used as the command
attribute, which is great for a self-documenting one-liner. but not so great when you want to trigger the command by name. So let’s transform the execute
resource like so:
Then add the
notifies
attribute as follows. The notifies
attribute takes three parameters: an action, the name of the resource to notify, and a timer indicating when the action should be perform. As shown in the following code block, we want to perform the :run
action on the execute[reconfigure-chef-server]
resource, and we want the action performed :immediately
. For more information on notifies
parameters, refer to the Chef documentation:
Example 9-4 shows what the final version of our idempotent code looks like.
Try running
kitchen converge
against this revised recipe, and note that it reports 0/2 resources updated, which is the result we are looking for; no resources are updated after running kitchen converge
for the second time:
Always check your recipes to see if they are idempotent before deploying them to production. If we had deployed the first version of this recipe in production, given that the
chef-client
usually runs on a periodic timer performing Chef runs, all our nodes would have been reinstalling the Chef Server package and reconfiguring the server every 15 minutes!Configure Enterprise Chef Server
If your Enterprise Chef Server installed properly, you should be able to access the web admin console using the
private_network
IP address you configured in your .kitchen.yml. In our case, we used the address 192.168.33.34. After you dismiss a warning about the use of a self-signed SSL certificate, click on the Sign up link, as shown in Figure 9-4.
You will be prompted to create a user account. Enter in the required values, then click on the Submit button.Figure 9-5 shows the values we used for our user account; yours will be different, of course.
Once you click on the Submit button, the Enterprise Chef web UI indicates that the next step you should perform is to create an organization. Click on the Create link to create an organization, as shown in Figure 9-6.
An <organization> is the name of your company or organization. It is used as a unique identifier to authenticate your organization against Chef Server. Figure 9-7 shows how we filled out the organization fields in our setup.
Once you click on the Create Organization button, you will be prompted to save two files: the validation key and the knife configuration file, as shown in Figure 9-8:
- <organization>-validator.pem
- knife.rb
After you’ve download the <organization>-validator.pem and knife.rb files, click on your username link on the upper right-hand side of the web page as shown in Figure 9-9. Our username is
misheska
; yours will be different.
As shown in Figure 9-10, click on the Regenerate Private Key link to download the third and final configuration file you need <username>.pem.
Once you have these three files downloaded, go back to the root directory where you created chef-repo. Make it the current working directory. Then create a chef-repo/.chef directory.
Copy the <username>.pem, <organization>-validator.pem, and knife.rb files to the chef-repo/.chef directory. Once you’ve copied these files, the chef-repo directory should resemble the following:
Because we registered with the username “misheska” and the organization “learningchef,” our .chef directory contains the following:
- misheska.pem
- learningchef-validator.pem
- knife.rb
The <username>.pem file is a unique identifier used to authenticate you against Chef Server. This should be treated like a password—do not share it with anyone and do not alter the contents of the file.
The <organization>.pem file is a unique identifier used to authenticate your organization against Chef Server. This should be treated like a password, but it must also be shared among all your Chef developers. Anyone needing access to your Chef organization will also need a copy of this file. Do not alter the contents of this file.
Unlike a .pem file, the knife.rb file is meant to be edited, altered, and customized. The knife.rb file is recognized as Ruby and read by Chef when it issues commands:
Note that the
chef_server_url
field in our example uses a fake DNS hostname of default-centos65.vagrantup.com
because that’s the hostname vagrant set up. If you try to visit the URL https://default-centos65.vagrantup.com/organizations/learningchef, you will discover that it is not valid.
Chef Server requires that hosts have valid fully qualified domain names set up in your local domain name service (DNS). In production, you would have your Chef Server hostname configured in your Domain Name System (DNS) server before installing Chef Server. Let’s add a temporary host entry for
default-centos65.vagrantup.com
in your local host database in lieu of making a DNS change, as we are just doing a book exercise.
Run one of the following commands to add a host entry. Following are the commands we ran on our machine. If you used an IP address other than
192.168.33.34
, make sure it matches when you run the command.
Linux/Mac OS X:
Windows Command Prompt:
Windows PowerShell:
Now if you try to visit https://default-centos65.vagrantup.com in your web browser, your local host should think that this is a valid hostname.
You may add additional values to the knife.rb, such as EC2 credentials, proxy information, and encrypted data bag settings. Although certain pieces of the knife.rb will be common among your team members, the contents of the generally file should be unique to you and your machine. However, unless you have access keys and passwords in your knife.rb, you do not need to treat it like a password.
Testing the Connection
You should run the following commands from inside the Chef repository. Open your terminal or command prompt, and make chef-repo the current working directory. If you placed your Chef repo in a different location, use that instead:
Now you can use
knife
, the command-line tool for Chef Server, to test your connection and authentication against Chef Server. At the time of this writing, Chef does not provide a “connection test” command. However, asking Chef Server to list the clients will verify- Your network can connect to Chef Server.
- The authentication files are in the correct location.
- The authentication files can be read by Chef.
- The response from Chef Server is received by your workstation.
Issue the
knife client list
command on your terminal. You should see the following:
If you get an error, check the following:
- You can access https://default-centos65.vagrantup.com:443 from a web browser.
- You are running commands from inside the chef-repo directory.
- The .chef directory contains two .pem files and a knife.rb.
- Your authentication files have the correct file permissions (they should be only user-readable).
If you have confirmed the preceding steps and are still unable to connect to Chef Server, please consult the Chef online documentation.
Now that you have verified that your host can connect to Chef Server, let’s create another cookbook for a node instance and register it to be managed by Chef Server.
Bootstrapping a Node
In Chef, the term “bootstrapping” refers to the process by which a remote system is prepared to be managed by Chef. This process includes installing Chef Client and registering the target node with Chef Server.
CREATE A NODE IN A SANDBOX ENVIRONMENT
Let’s use Test Kitchen to define a project that spins up a node in a sandbox environment, similar to what we did back in Chapter 5 before we learned how to create cookbooks.
Create a
node
directory alongside the chef-server
cookbook you created in this chapter. This technically isn’t a cookbook—it’s just a Test Kitchen project—but putting it beside the chef-server
cookbook directory makes it convenient to go back and forth between the two.
Create the directory ~/chef-repo/cookbooks/node, and make it the current working directory:
The
knife client list
command should work even in this subdirectory. Verify this now:
This node directory will just be a test kitchen project, not a cookbook, so run the following commands to create a .kitchen.yml file for Test Kitchen:
Edit the .kitchen.yml file, as in Example 9-5, to use the CentOS 6.5 basebox we prepared specifically for this book. Also assign a private network address like we did in Chapter 7. This time, we’re going to use the IP address 192.168.33.35. Make sure this address does not conflict with the IP address of your Chef Server, which should be 192.168.33.34.
Note that we also changed the suite name to be
node
, as this sandbox environment will be running our node, but we also have another sandbox environment running our Chef Server. Having different names will disambiguate the two environments.
Also, we’ve configured a synced folder pointing at the root chef-repo directory. As shown in Figure 9-11, Vagrant can keep directories on your host Chef development workstation synchronized with directories in the sandbox environment running on the guest.
The following
synced_folders:
stanza in a .kitchen.yml file ensures that the chef-repo directory on the host is kept in sync with the /chef-repo directory on the guest:
The /chef-repo synced folder will be used later in Chapter 10 when we configure SSL verification with the server.
BOOTSTRAP THE NODE WITH KNIFE
Figure 9-12 is an overview of the setup we’ve configured so far in this chapter. We’ve configured a Chef server (or used Hosted Enterprise Chef), and we configured a knife.rb with the appropriate keys so we can communicate with the Chef server from our host, the administrator’s workstation. We’ve established that this communication channel works by verifying that
knife client list
produces the expected output.
Now let’s set up our node like we would in production by “bootstrapping” the node with
knife bootstrap
. ((((“Test Kitchen”,"in production environments”)))We won’t be able to use Test Kitchen in production!) When we run knife bootstrap
on the our host, it will install Chef Client on the node and register it to be managed by Chef Server.
Nodes must have valid fully qualified domain names set up in your local domain name service (DNS) as well. Let’s add an entry to our local host database for the node just like we did for Chef Server.
Run one of the following commands to add a node entry. Following are the commands we ran on our machine. If you used an IP address other than
192.168.33.35
, make sure it matches when you run the command.
Linux/Mac OS X:
Windows Command Prompt:
Windows PowerShell:
You also need to
kitchen login
to the node and configure the local host database on the node to provide it the name of the server when you run chef-client
. Once complete, exit
back out to your host prompt. As mentioned before, in production, you’d just make sure the DNS was configured with these hostnames before installing Chef Server and any nodes:NOTE
If you get the error “No instances for regex
node-centos65
,” you forgot to change the suite name to node. Run kitchen destroy
to clear the node instance with the incorrect name. Then refer to Example 9-5 and make sure the suites
stanza resembles the following:
Run
kitchen create
again after making the correction.
Run the following command to bootstrap your node:
You can tell from the output that it successfully installed Chef Client, and even performed a courtesy Chef Client run.
To verify that the node is now registered on Chef Server, log into the web interface and click on the Nodes tab. Now you should see that you have a node registered with your Chef Server, as shown in Figure 9-13.
If you click on the link to the node, you should see that Chef Server displays information about the node as shown in Figure 9-14. The values you see under attributes should look familiar; these are the attributes generated automatically by
ohai
. They are stored on Chef Server for each node, and the data is searchable by all clients.
We’ll be using both Chef Server and node sandbox instances in the next chapter, so don’t
kitchen destroy
them just yet, as you don’t want to have to go through all the setup steps you performed in this chapter. If you need to stop the virtual machines temporarily because you plan on powering off your machine before tackling the next chapter, you can use the vagrant halt
command. Unfortunately, as of this writing, Test Kitchen doesn’t have a way to halt or suspend virtual machines with the kitchen
command, so you have to use the vagrant
tool that Test Kitchen uses behind the scenes instead.
In order to run
vagrant halt
to perform a graceful shutdown of your virtual machines, you’ll need to make sure the Vagrantfile directory that is used by vagrant
to configure the virtual machine is the current working directory. As of this writing, the associated Vagrantfiles are located in the .kitchen directory that Test Kitchen uses for temporary files in a directory matching the suite name in the .kitchen.yml. To halt both virtual machines, run the following commands:Bootstrap Chef Server with Chef Solo
Before we conclude this chapter, it is worth mentioning that you can use Chef Solo outside of Test Kitchen to automate the deployment of Chef Server in production. We expect to see most Chef Solo-based software migrate to Chef Local/Chef Zero, as we covered in Chef Client Modes. However, Chef Solo is still singularly useful for bootstrapping Chef Server itself, as some scripts get confused about which server to communicate with when you try to set up Chef Server using Chef Local/Chef Zero, because Chef Zero launches a second in-memory Chef Server.
NOTE
Although we expect Chef coders to transition to Chef Local/Chef Zero, there are some truly amazing systems still built on Chef Solo. One tool worth checking out if you use Mac OS X is SoloWizard, by Pivotal Labs. By filling out a simple web form you can have it automatically generate a Chef Solo-based script to auto-generate a Mac OS X development workstation. As of this writing, there is no Chef Local equivalent of this tool, but there might be one by the time you read this.
Here’s an overview of the steps required to use Chef Solo to bootstrap Chef Server:
- Install Chef Client (which includes
chef-solo
). - Create /var/chef/cache and /var/chef/cookbooks directories. These are the default locations where
chef-solo
stores state information and looks for cookbooks, respectively. (You can override these settings by supplying a .json file with configuration settings on the command line. See http://docs.getchef.com/chef_solo.html for more information.) - Copy any necessary cookbooks down to the host.
- Run
chef-solo
.
Although we won’t go through another hands-on exercise bootstrapping Chef Server with Chef Solo, as you’ve done this already with Test Kitchen, here are the commands you would use to perform the preceding steps:
Summary
In this chapter, we’ve covered the basics of installing Chef Server. We showed you how to install a test Chef Server setup driven by Chef recipes in both sandbox environments using Test Kitchen, and on production servers using
chef-solo
.
We also introduced the concept of idempotence when we covered how to write Chef code to install Chef Server. Chef code is idempotent when it can run multiple times on the same system and the results will always be identical, without producing unintended side effects.
Although nearly all the default Chef resources are guaranteed to be idempotent, the
execute
resource is not. We showed you how to test that Chef code is idempotent by performing a Chef run twice in succession, such as with kitchen converge
. On the second run, idempotent Chef code should display no resource updates.
In the next chapter, we’ll talk about the Chef Community Cookbook. We’ll highlight the
chef-client
cookbook, an oft-used community cookbook people find useful in bootstrapping nodes in production.
Good article. Very interesting to read this article.
ReplyDeleteDevOps Training
DevOps Online Training