Book Image

Infrastructure as Code (IAC) Cookbook

By : Stephane Jourdan, Pierre Pomès
Book Image

Infrastructure as Code (IAC) Cookbook

By: Stephane Jourdan, Pierre Pomès

Overview of this book

Para 1: Infrastructure as code is transforming the way we solve infrastructural challenges. This book will show you how to make managing servers in the cloud faster, easier and more effective than ever before. With over 90 practical recipes for success, make the very most out of IAC.
Table of Contents (18 chapters)
Infrastructure as Code (IAC) Cookbook
Credits
About the Authors
About the Reviewer
www.PacktPub.com
Customer Feedback
Preface
Index

Simulating Chef upgrades using Vagrant


Wouldn't it be awesome to simulate production changes quickly? Chances are you're using Chef in production. We'll see how to use both Chef cookbooks with Vagrant, as well as how to simulate Chef version upgrades between environments. This kind of setup is the beginning of a good combination of infrastructure as code.

Getting ready

To step through this recipe, you will need the following:

  • A working Vagrant installation

  • A working VirtualBox installation

  • An Internet connection

How to do it…

Let's start with a minimal virtual machine named prod that simply boots a CentOS 7.2, like we have in our production environment:

Vagrant.configure("2") do |config|
  config.vm.box = "bento/centos-7.2"
  config.vm.define "prod" do |config|
    config.vm.hostname = "prod"
    config.vm.network "private_network", type: "dhcp"
  end

end

Vagrant Omnibus Chef plugin

Now, if we want to use Chef code, if we want to use Chef code (Ruby files organized in directories that form a unit called a 'cookbook' that configure and maintain a specific area of a system), we first need to install Chef on the Vagrant box. There're many ways to do this, from provisioning shell scripts to using boxes with Chef already installed. A clean, reliable, and repeatable way is to use a Vagrant plugin to do just that—vagrant-omnibus. Omnibus is a packaged Chef. Install it like any other Vagrant plugin:

$ vagrant plugin install vagrant-omnibus
Installing the 'vagrant-omnibus' plugin. This can take a few minutes...
Installed the plugin 'vagrant-omnibus (1.4.1)'!

Then, just add the following configuration in your VM definition of the Vagrantfile and you'll always have the latest Chef version installed on this box:

config.omnibus.chef_version = :latest

However, our goal is to mimic production, maybe we're still using the latest in v11.x series of Chef instead of the latest 12.x, so instead let's specify exactly which version we want:

config.omnibus.chef_version = "11.18.12"

Now that we're using a new plugin, our Vagrantfile won't work out of the box for everybody. Users will have to install this vagrant-omnibus plugin. If you care about consistency and repeatability, an option is to add the following Ruby check at the beginning of your Vagrantfile:

%w(vagrant-vbguest vagrant-omnibus).each do |plugin|
  unless Vagrant.has_plugin?(plugin)
    raise "#{plugin} plugin is not installed! Please install it using `vagrant plugin install #{plugin}`"
  end
end

This code snippet will simply iterate over each plugin name to verify that Vagrant returns them as installed. If not, stop there and return a helpful exit message on how to install the required plugins.

A sample Chef recipe

This part of the book isn't about writing Chef recipes (read more about it later in the book!), so we'll keep that part simple. Our objective is to install the Apache 2 web server on CentOS 7 (httpd package), and start it. Here's what our sample recipe looks like (cookbooks/apache2/recipes/default.rb); it does exactly what it says in plain English:

package "httpd"

service "httpd" do
  action [ :enable, :start ]
end

Vagrant and Chef integration

Here's how, in our VM definition block, we'll tell Vagrant to work with Chef Solo (a way of running Chef in standalone mode, without the need of a Chef server) to provision our box:

    config.vm.provision :chef_solo do |chef|
      chef.add_recipe 'apache2'
    end

As simple as that. Vagrant this up (vagrant up), and you'll end up with a fully provisioned VM, using the old 11.18.12 version, and a running Apache 2 web server.

Our manual tests can include checking that the chef-solo version is the one we requested:

$ chef-solo --version
Chef: 11.18.12

They can also check if we have httpd installed:

$ httpd -v
Server version: Apache/2.4.6 (CentOS)

Also, we can check if httpd is running:

$ pidof httpd
13029 13028 13027 13026 13025 13024

Note

Various other options than chef-solo exist, such as chef-client and chef-zero.

Testing the Chef version update

So we simulated our production environment locally, with the same CentOS version, the apache2 cookbook used in production, and the old Chef version 11. Our next task is to test if everything is still running smoothly after an upgrade to the new version 12. Let's create a second "staging" VM, very similar to our production setup, except we want to install the current latest Chef version (12.13.37 at the time of writing, feel free to use :latest instead):

  config.vm.define "staging" do |config|
    config.vm.hostname = "staging"
    config.omnibus.chef_version = "12.13.37"
    config.vm.network "private_network", type: "dhcp"
    config.vm.provision :chef_solo do |chef|
      chef.add_recipe 'apache2'
    end
  end

Launch this new machine (vagrant up staging) and we'll see if our setup still works with the new major Chef version:

$ vagrant ssh staging
$ chef-solo --version
Chef: 12.13.37
$ httpd -v
Server version: Apache/2.4.6 (CentOS)
$ pidof httpd
13029 13028 13027 13026 13025 13024

So we can safely assume, as far as our testing goes, that the newest Chef version still works correctly with our production Chef code.

There's more…

Here are more ways of controlling a Vagrant environment, and use even better Chef tooling inside it.

Controlling default Vagrant VMs

You may not always want to boot both production and staging vagrant virtual machines, especially when you just want to work on the default production setup. To specify a default VM:

config.vm.define "prod", primary: true do |config|
  […]
end

To not start automatically a VM when issuing the vagrant up command:

config.vm.define "staging", autostart: false do |config|
  […]
end

Berkshelf and Vagrant

Chances are, if your production environment is using Chef, you're also using Berkshelf for dependency management and not 100% local cookbooks (if you aren't, you should!).

Vagrant work pretty well with a Berkshelf enabled Chef environment, using the vagrant-berkshelf plugin.

Note

Your workstation will need the Chef Development Kit (Chef DK: https://downloads.chef.io/chef-dk/) for this to work correctly.

Testing with Test Kitchen

This setup is in fact so close to what's used to make infrastructure code testing that you'll see a lot of similarities in the dedicated section of this book.