Although configuration is one of the most important aspects of cloud deployment, it is often neglected. There are several automation tools and platforms available, such as Opscode Chef or Puppet, but a minimal infrastructure is usually required to be able to use them. They are really good at automating configuration in large environments, but this is not always the use case in the cloud.

People want to create services in the cloud quickly and easily, without having to worry about infrastructure apart from the services that they are deploying. So how could service configuration be automated? SSH or command-line scripts are often very complex to build and maintain, and making them work on multiple operating systems can be painful. How could this be resolved quickly and easily? The answer is to team up Jclouds and Chef Solo. They’re a perfect match!

Cool features of Chef Solo:

  • Run cookbooks on your nodes without a Chef Server.
  • Many cookbooks are available, compatible with most common operating systems.
  • Configure roles and data bags.
  • Schedule Chef runs to keep your node up to date.

Ok, this sounds great, so let’s get into the code!

Cooking a basic web server

This first basic example will install an Apache2 web server on a node. It will download a tarball with all the cookbook definitions and install the Apache2 recipe on the deployed node.

[code lang=”java” light=”true”]// Create the connection to the cloud provider
ComputeServiceContext computeContext = ContextBuilder.newBuilder(“<provider>”)
.endpoint(“<provider endpoint>”)
.credentials(“<identity>”, “<credential>”)
.modules(ImmutableSet.<Module> of(new SshjSshClientModule()))
.buildView(ComputeServiceContext.class);
ComputeService compute = computeContext.getComputeService();

// Build the Chef Solo script that will download the cookbook definitions
// and install the selected recipes
Statement bootstrap = ChefSolo.builder().
.cookbooksArchiveLocation(“http://foo/bar/cookbooks.tar.gz”)
.runlist(RunList.builder().recipe(“apache2”).build())
.build();

// Select the template to be deployed
Template template = compute.templateBuilder()
.imageNameMatches(“Ubuntu.*”)
.options(runScript(bootstrap))
.build();

// Deploy the node and bootstrap it using Chef Solo!
compute.createNodesInGroup(group, 1, template)
[/code]

Have you noticed that there are only 5 lines of code? That’s how easy it is to bootstrap nodes with jclouds and Chef Solo!

Playing with roles and data bags

Chef Solo also lets you define roles and data bags on the fly, to provide more flexibility to your configuration. This example will show how a role can be created and used to customize the Apache2 installation.

[code lang=”java” light=”true”]Role role = Role.builder()
.name(“webserver”)
.description(“Web server with apache and SSL”)
.jsonDefaultAttributes(“{“apache”: {“listen_ports”:[“8888″]}}”)
.runlist(RunList.builder().recipe(“apache2”).build())
.build();

Statement bootstrap = ChefSolo.builder().
.defineRole(role)
.cookbooksArchiveLocation(“http://foo/bar/cookbooks.tar.gz”)
.runlist(RunList.builder().role(“webserver”).build())
.build();
[/code]

That’s it! With just these two lines you can create a role to set up the default configuration for your web server deployment.

Automating maintenance

In the examples I’ve used the cookbooksArchiveLocation to download a cookbook archive. This could also be a local file system path if you are able to upload the cookbooks to the node (for example, using the jclouds SshClient).

Instead of downloading or uploading a cookbook archive to the node, another common use case is to clone a git repository with all the cookbooks and set up a cron job to keep it up to date. Then the Chef Solo statement can be configured to run periodically, and this way the node will always be up to date with the latest version of the cookbooks.

[code lang=”java” light=”true”]// Clone all community cookbooks in the ‘/var/chef’ directory
Statement cloneCookbooks = CloneGitRepo.builder() //
.repository(“git://github.com/opscode/cookbooks.git”) //
.directory(“/var/chef”) //
.build();

// Configure Chef Solo to read the cookbooks from there
Statement chefSolo = ChefSolo.builder().
.cookbookPath(“/var/chef/cookbooks”)
.runlist(RunList.builder().recipe(“apache2”).build())
.build();

// Build a boostrap statement that installs Git, clones the cookbooks and
// runs Chef Solo
StatementList bootstrap = new StatementList(
new InstallGit(), cloneCookbooks, chefSolo);
[/code]

As you’ve seen here, bringing configuration management to the cloud is easy with jclouds and Chef Solo. There is no need to build complex infrastructures or deployments. Just start cooking your own stuff!

O