Search icon CANCEL
Subscription
0
Cart icon
Your Cart (0 item)
Close icon
You have no products in your basket yet
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Conferences
Free Learning
Arrow right icon
Arrow up icon
GO TO TOP
Infrastructure as Code Cookbook

You're reading from   Infrastructure as Code Cookbook Automate complex infrastructures

Arrow left icon
Product type Paperback
Published in Feb 2017
Publisher Packt
ISBN-13 9781786464910
Length 440 pages
Edition 1st Edition
Arrow right icon
Authors (2):
Arrow left icon
Pierre Pomès Pierre Pomès
Author Profile Icon Pierre Pomès
Pierre Pomès
Stephane Jourdan Stephane Jourdan
Author Profile Icon Stephane Jourdan
Stephane Jourdan
Arrow right icon
View More author details
Toc

Table of Contents (12) Chapters Close

Preface 1. Vagrant Development Environments FREE CHAPTER 2. Provisioning IaaS with Terraform 3. Going Further with Terraform 4. Automating Complete Infrastructures with Terraform 5. Provisioning the Last Mile with Cloud-Init 6. Fundamentals of Managing Servers with Chef and Puppet 7. Testing and Writing Better Infrastructure Code with Chef and Puppet 8. Maintaining Systems Using Chef and Puppet 9. Working with Docker 10. Maintaining Docker Containers 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.

You have been reading a chapter from
Infrastructure as Code Cookbook
Published in: Feb 2017
Publisher: Packt
ISBN-13: 9781786464910
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $19.99/month. Cancel anytime
Banner background image