While Cloud-Init is a general system for running scripts for whatever purpose you like, there are numerous tools dedicated solely to configuration management. Puppet, Chef, Salt, and Ansible aren’t the only options in this realm, but they are definitely the biggest players, and they have some important similarities and differences to consider if they are to be used as part of an OpenStack-backed deployment.
First off, all of these applications share the idea of plug and play modules (called
recipes in Chef, and playbooks in Ansible). These prebuilt blocks are the biggest thing that differentiates them from configuring a server with Bash or other
scripting tools like Cloud-Init. Modules are available from public repositories that anyone can submit to or retrieve from, similar to PIP in Python or NPM in
Node.js. Additionally, they have all attempted to come up with a simple
language/structure for describing a server’s configuration, handle installation errors, and provide different configurations for servers in different roles. The formats are familiar—JSON, YAML, etc., but the actual syntax and methodology are proprietary and not portable across solutions.
The language they were built upon, their need to have installed clients (Ansible, for example, doesn’t need one), and the breadth and depth of their module
libraries, are really what differentiates these tools from each other. As with most technologies, you will find enthusiastic supporters and dissenters of each, but for most purposes they are equivalent. In fact, their similarity, and the ability to
develop a generic syntax for their use, is a big reason why there is growing support for all of these tools within OpenStack.
Let’s look at what a simple Puppet Manifest might look like to configure a server to run Apache and PHP:
# install apache package { 'apache2': ensure => installed }
# start apache and ensure its running service { 'apache2':,
require => Package['apache2'], ensure => running
} # install php package { 'php5': require => Package['apache2'], ensure => installed }
#create an info.php file to show that this all worked file { '/var/www/html/info.php': ensure => file, content => '<?php phpinfo(); ?>', mode => 0444, require => Package['php5'] }
With the Puppet client correctly installed and the preceding file saved as
manifest.pp, you could then execute this template as follows: $ sudo puppet apply ./manifest.pp
Puppet deals with any error handling, determines the order things have to happen in based upon the require statements, and handles all of the differences in OS
types. For example, using these tools, you don’t have to write one script for
CentOS that installs software via Yum, and another version that supports apt-get installation on Debian or Ubuntu.
As was mentioned before, Heat actually provides hooks for all of these tools in the form of a SofwareConfig resource. If your configuration supports Chef, then a Heat template to set up Wordpress might look like this:
resources: wordpress_config: type: OS::Heat::SoftwareConfig::Chef properties: cookbook: http://www.mycompanycom/hot/chef/wordpress.zip role: wordpress
# input parameters that the chef role(s) need inputs: wp_admin_user: type: string mapping: wordpress/admin_user wp_admin_pw: type: string mapping: wordpress/admin_password db_endpoint_url: type: string mapping: wordpress/db_url
# various other input parameters …
# Have chef output the final wordpress url outputs:
wp_url:
type: string
From the OpenStack documentation at
https://wiki.openstack.org/wiki/Heat/Blueprints/hot-software-config-spec:
The resource type OS::Heat::SoftwareConfig::Chef indicates that this is a Chef-specific Software Config definition. The cookbook property points to the used Chef cookbook, and the role property points to the role to be set up via this Software Config. The inputs section contains the definition of input parameters that have to be passed to Chef for configuring the role. Input parameters are defined in terms of name and type. In addition, a mapping specifies to which role attribute the respective input parameters needs to be assigned (i.e. Chef-specific metadata).
If this seems confusing, don’t worry. This example is simply meant to show the developers behind OpenStack are aware of these tools, and that if you are familiar with them, there are a number of ways to tightly integrate them into your
deployment. Again, exactly how you choose to configure your servers and your application is entirely up to you. Your company and/or your operations team may have a lot to say on the subject, or the choice might be yours alone. What’s
important is to have a general understating of the options available and form a game plan.
With that in mind, let’s to go over two other important pieces of functionality that all of these configuration management solutions provide. First off, they offer
centralized management of servers. Once the client is installed, and the server has been registered into the master, you can use a web interface to do things like
search for a server, see what software is installed, or even push/schedule a patch for it (see Figure 6.5).
Figure 6.5
This configuration isn’t required though, and these tools can all be used in masterless mode where this central authority is entirely absent. There is a lot of crossover between what these centralized systems and what OpenStack/Horizon can offer, so it’s not unusual to use them in this masterless manner.
The other piece of functionality they all offer is the ability to execute arbitrary commands on remote servers. This is an aspect of the same mechanism that
allows the master servers to patch remote computers. Ansible in particular can be an indispensible tool when used for this purpose.
Unlike Puppet, Chef, and Salt (to some extent), Ansible doesn’t require the
installation of a specialized client to support remote command execution. It uses SSH and private/public keys to achieve a similar result. It is also easy to configure Ansible with a local file to push these commands to many servers at once (as
opposed to sequentially). This makes remote execution quick and easy from any computer with Ansible installed. A configuration file for Ansible looks like this:
[devservers]
[prodservers] prod01.cloud.mycompany.com prod02.cloud.mycompany.com prod03.cloud.mycompany.com [otherservers] server1.cloud.mycompany.com server2.cloud.mycompany.com
This file defines three groups of servers (devservers, prodservers, and
otherservers). Commands can be run on an individual box, a group, or all groups at once. You can also determine how many servers to run the command on
simultaneously. So if, for example, you want to update Git on all of your production servers at once you could run:
$ ansible prodservers -a "yum update -yq git" -f 3 -u myusername ––sudo ––ask-sudo-pass -i /myuser/ansible_hosts
Since Yum often requires sudo access, the ask-sudo-pass value has been invoked,
and -f 3 indicates that you want to run it on three servers at once. If there were 6
servers defined in the prodservers group, then it would run this in two separate
batches. This is often useful to avoid things like cache slamming or to avoid rebooting all of your servers at once, making your application temporarily unavailable.
Ansible is highly recommended as an easy way to execute remote commands, but this does not make it a shoe-in for the configuration solution for our demo
application. In fact, there is one drastically different option to consider.