Over a million developers have joined DZone.

Chef With Berkshelf, Test Kitchen, and InSpec

DZone 's Guide to

Chef With Berkshelf, Test Kitchen, and InSpec

This tutorial shows how to create a local Ubuntu instance and install Nginx, then test it, using Chef, Berkshelf, Test Kitchen, and InSpec.

· DevOps Zone ·
Free Resource

Chef has been one of the most stable and powerful configuration management and automation tools in the DevOps world. Different frameworks to support infrastructure as code also evolved along with configuration management. 

Following is a simple example of how to create a local Ubuntu instance and install Nginx. Our expectation is that at the end of the example, we should be able to provision the instance using $kitchen converge. With this, a hello world page should be available on port 80. We should be able to test the setup with the command $kitchen verify.

In the below example, the latest frameworks like Berkshelf, Test Kitchen, and InSpec have been used for dependency management build and testing the code or configuration.


  • Virtualbox

  • Vagrant

  • Chef DK

Check the dependencies:

ubuntu@hostname:~$ chef -v
Chef Development Kit Version: 2.3.4
chef-client version: 13.4.19
berks version: 6.3.1
kitchen version: 1.17.0
inspec version: 1.36.1 

With Chef workstation, we can develop and test our code before pushing to the Chef server. So, let's start by creating a Chef project using the below command, chef-example. 

 chef generate app chef-example 

This will generate the project structure and create kitchen config file. We have to update the .kitchen.yml file and add the required configuration:

 $ vi chef-example/.kitchen.yml 

Add the driver which is vagrant, in this case, to create a local instance- 


name: vagrant

name: chef_zero

Now its time to define the platform or instance we are looking to provision. We will use HashiCorp/Precise32 which is one of the most popular minimal ubuntu image. InSpec will be used to test our code locally, so we will leave as it is.


name: inspec

- name: hashicorp/precise32

We have to specify our recipes required to provision the VM in the run_list. We have two recipes: default and install_nginx. 


- name: default
- recipe[chef-example::default]
- recipe[chef-example::install_nginx]

Let's leave the test cases in the default directory:


- test/smoke/default

Our kitchen configuration is ready. We will create a recipe to install the Nginx on the VM. Different packages are available. We can use nginx::repo, and our recipe should look like this:

$ vi cookbooks/chef-example/recipes/install_nginx.rb

# Cookbook Name:: chef-example
# Recipe:: install_nginx
# Copyright (c) 2016 The Authors, All Rights Reserved.

# Only needed if you want to install latest stable package from nginx.org
include_recipe 'nginx::repo'

package 'nginx' do
action :install

service 'nginx' do
supports status: true, restart: true, reload: true
action :enable

This will install Nginx on the target VM, however, we would like to place our own file, which displays hello world on the browser. We need to append below section at the end of our recipe:

cookbook_file "/usr/share/nginx/html/index.html" do
source "index.html"
mode "0644"

Of course, we have to create our own indext.html file with hello world content as referred above in our recipe. Let's create the directory named files in our cookbook and create nginx.html-

 $ vi cookbooks/chef-example/files/index.html 

and add this snippet:

<title>Hello world</title>
<h1>Hello world</h1>

We have to add the dependencies for recipes in the metadeta.rb

depends 'nginx', '~> 7.0.1'

For Nginx installation, we have created a separate recipe; instead, though, we could have used the default one as well as its small example. However, we can add an upgrade requirement in there. Let's append the below snippet in the recipe/default.rb.

execute "apt-get update" do
 command "apt-get update"

We have to add this dependency our metadata.rb file, add below line

depends 'apt-repo', '~> 0.1.2'

Now we need to install the dependencies:

 $ berks install 

We are now done with our provisioning requirement and its time to add some test cases to our code in order to verify the setup.

Let's edit the default test file and replace the sample test cases with some real ones. We can check cases like:

  • If Nginx has been installed on the target VM

  • If it's running on port 80.

  • If its configuration file exists.

  • Also, as we have added our own hello world file, we would like to check if the index.html file contains any string 'hello world.'

Let's add these test cases in default test file:

$ vi test/smoke/default/default_test.rb

#The package should be installed
describe package("nginx") do
it { should be_installed }

#NginX should be running on port 80
describe port(80) do
it { should be_listening }

#nginx configuration file should exist
describe file('/etc/nginx/nginx.conf') do
it { should exist }

# inde.html should have matching words
describe file('/usr/share/nginx/html/index.html') do
it { should exist }
its(:content) { should match(/Hello world/) }

Now our test cases are also complete, its time to run and verify the instance.

Run below command to converge the instance 

 $ kitchen converge 

It will take a couple of minutes and create the ubuntu instance using vagrant and install Nginx as we have specified in our recipe. Once complete you can see the instance using the list command:

$ kitchen list

Instance Driver  Provisioner Verifier Transport Last Action Last Error
default-hashicorp-precise32 Vagrant ChefZero Inspec   Ssh      Converged   <None>

We can see our instance is listed and it's converged. We can login to the instance with

$ kitchen login

Now our instance is ready, we can run our test cases to verify the setup:

 $ kitchen verify  

Image title

devops ,chef ,test kitchen ,ruby ,vagrant

Opinions expressed by DZone contributors are their own.

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}