Development Environment with Vagrant and Chef

In this article I will try to introduce you to the wonderful Vagrant and Chef utilities by the example of automatic configuration of the development environment for a PHP developer (in fact, PHP is just an example, everything described below can be used for any technology stack).

What do we do?

We will configure the virtual machine (VM) with Ubuntu 12.04 to work on a project in PHP, namely:

  • Apache
  • Mysql
  • PHP 5.4
  • xDebug
  • Memcached
  • Composer
  • We will immediately configure Virtual Host on a specific folder, accessible both from a virtual machine and from a real one. All this is parameterized for ease of creation and use.
  • and other..

It’s a rather boring task, especially if you do it with some frequency, so we will make the computer do it on its own.

How can this help you?

  • You don’t want to “clog” your system with many utilities, programs
  • You want to test your code in production-like conditions
  • You want to test your code on different versions of a particular platform (remember how Travis tests builds in various configurations, for example Symfony on different versions of PHP)
  • You do not want to help a new person on a project (layout designer, programmer) install everything from scratch
  • Do you want each person in the team to have an identical environment for working on a project

All this is a reality. The question is "how?"


Vagrant is a utility that allows you to create a virtual machine and configure it automatically as you specified. Out of the box, Vagrant works with VirtualBox, although there is support for other solutions.

Looking ahead, all you need to deploy the environment on the computer is to execute one command:

vagrant up

Everything will be done automatically. Let's get down to our task.

To configure Vagrant uses only one file - Vagrantfile . It is in it that everything that needs to be done when starting the virtual machine is described. To initialize a Vagrant project, you must run the command

vagrant init

at the root of your project.

The directory structure will be as follows:

One of the main concepts in Vagrant is box. Box is an archive that contains an image of a virtual machine and a settings file for Vagrant itself.

We will use the box from the Vagrant website (each box includes at least Chef and Puppet installed - this will be very useful to us a bit later).

The final Vagrantfile file will look like this (standard comments are deleted, see them in the documentation):

# -*- mode: ruby -*-
# vi: set ft=ruby : do |config|
  # имя box'a = "precise64"
  # ссылка, откуда можно скачать данный box
  config.vm.box_url = ""
  # по данному IP можно будет добраться до виртуальной машины :hostonly, ""
  # сообщаем о том, что между виртуальной машиной и реальной будут общие папки, автоматически синхронизируемые
  config.vm.share_folder "www", "/var/www", "www", :create => true
  # настраиваем Chef
  config.vm.provision :chef_solo do |chef|
    chef.cookbooks_path = "recipes/cookbooks"
    chef.roles_path = "recipes/roles"
    chef.add_role "web"
    # chef.data_bags_path = "../my-recipes/data_bags"
    chef.json = {
        "mysql" => {
            "server_root_password" => "%your_pass0%",			
	    "server_repl_password" => "%your_pass1%",
	    "server_debian_password" => "%your_pass2%"

Used by Ruby to describe the configuration file.
It makes no sense to describe all the details and trivia of Vagrant; you can (and even need to) read them in the documentation. She, by the way, is well written.

In the file, we indicate the name for box. If it has not already been downloaded, Vagrant will do this automatically and save it to your hard drive. For this, the URL is indicated where box can be found. It is possible to specify the path in the file system.

In the network property, we indicate that the VM will be available on IP This is done in order to be able to create and use several projects, determining their names and entering the file of our real computer in the hosts.

You can also use ports here: in this example

config.vm.forward_port 80, 8080

we configure the VM so that on port 8080 from the host machine we get to port 80 of the guest machine. (in the Vagrant documentation, the host machine is our computer, the guest machine is a virtual machine). More details here .

The share_folder property allows you to configure shared folders for the host machine and guest machine. It is very comfortable. You open your IDE and work with files located on your computer, and not on a VM (although you can configure the editor to work with deleted files), and they are instantly synchronized. By default, the folder with your project will be available on the VM along the way /vagrant. In our case, we make the folder available wwwon the host machine along the path /var/wwwon the guest machine.

Next come the Chef settings, which will be described below. With Chef, all the necessary software will be installed.
Here we have a choice , you can use:

  1. Chef
  2. Puppet
  3. bash scripts


Chef - a utility for configuration management, deployment of the project, and much more. In conjunction with Vagrant, we will use Chef to install all the software, as well as to create VirtualHost and the folders of the new project. Links to interesting articles on using Chef in clusters are provided at the end of the article.

This may raise the question - how is it all the same to install so many things automatically? A large Chef community and official cookbooks from its creators come to the rescue .

A cookbook is a collection of recipes, templates, attributes, and other settings files for Chef. For example, there is an Apache2 cookbook with which Chef will install apache on your OS.
It is not clear what recipes, templates, attributes are? Don't be afraid eatA great article that will shed some light and help you deal with Chef very quickly. Later in the article we will create our own cookbook and everything will become even more transparent.

To install all the necessary software, we will use the following existing cookbooks:

  1. Apache2
  2. MySQL
  3. Php
  4. Vim
  5. Composer
  6. and others (some cookbooks depend on others, so you have to install them additionally)

It is for Chef that the recipes folder exists in our directory structure .

Software installation process

For convenience, you can install Chef on the host machine to use knife to generate the basic folder structure for the new cookbook. This step is completely optional.

Under root, run the following command:

curl -L | bash

At the root of our project we make a config for Knife:

mkdir .chef
echo "cookbook_path [ '/path-to/recipes/cookbooks' ]" > .chef/knife.rb

We create our own cookbook. It will be executed after the standard ones, when all the software is already installed, and will create VirtualHost with the given domain name and with the given path to the project, as well as create a database with the given name. Call it app .

knife cookbook create app

Our cookbook will depend on the standard Database and, naturally, on Apache2 , so add dependencies:

name             'app'
maintainer       'YOUR_COMPANY_NAME'
maintainer_email 'YOUR_EMAIL'
license          'All rights reserved'
description      'Installs/Configures app'
long_description, ''))
version          '0.1.0'
depends "apache2"
depends "database"

Install for example cookbook database . Since I installed Chef locally, I can use the capabilities of knife. Otherwise, you can simply download from github and copy it to the / path-to / recipes / cookbooks folder :

cd recipes/cookbooks/
knife cookbook site download database
tar zxf database-*.tar.gz
rm *.tar.gz

Any other cookbook we need is also installed.

Creating VirtualHost for Apache

Create a template:


   ServerAdmin <%= @params[:server_email] %>
   ServerName <%= @params[:server_name] %>
   DocumentRoot <%= @params[:docroot] %>
      Options Indexes FollowSymLinks MultiViews
      AllowOverride ALL
      Order allow,deny
      Allow from all
   ErrorLog ${APACHE_LOG_DIR}/<%= @params[:server_name] %>.log
   LogLevel debug

As you noticed, you can use variables in the template (set through attributes). We will save the default values ​​for them in a separate file:

default["app"]["database"] = "app"
default["app"]["path"] = "/var/www/vm-app"
default["app"]["server_name"] = "vm-app"
default["app"]["server_email"] = ""

And let’s override all the variable through Vagrantfile.

chef.json = {
    "app" => {
        "path" => "/var/www/cool-another-app",
        "server_name" => "cool-another-app",
        "server_email" => "",
        "database" => "cool_another_app_db"
    "mysql" => {
        "server_root_password" => "%your_path0%",           
        "server_repl_password" => "%your_path1%",
        "server_debian_password" => "%your_path2%"

Great, it remains with Chef to create the desired folder, and create a specific virtual host file. All this can be done through auxiliary functions called resources. We directly write these actions in the recipe:

# Cookbook Name:: app
# Recipe:: default
# Copyright 2013, YOUR_COMPANY_NAME
# All rights reserved - Do Not Redistribute
include_recipe "mysql::ruby"
# здесь мы создаём папку
directory node["app"]["path"] do
  owner "root"
  group "root"
  mode "0755"
  action :create
  recursive true
# а здесь создаём VirtualHost, используя наши переменные (атрибуты)
web_app 'app' do
  template 'vhost.erb'
  docroot node['app']['path']
  server_name node['app']['server_name']
  server_email node['app']['server_email']

At the same time, Chef will do everything automatically. In our case: add the site to / etc / apache2 / sites-available and execute a2ensite server_name

A list of all available resources can be found in the documentation .

DB creation

To do this, we simply add the following code to the /path-to/recipes/cookbooks/app/recipes/default.rb file :

mysql_database node['app']['database'] do
  connection ({:host => 'localhost', :username => 'root', :password => node['mysql']['server_root_password']})
  action :create

The list of all cookbooks that should be executed by Chef is configured in the run_list array of this in the file:

  "name": "web",
  "default_attributes": { },
  "override_attributes": { },
  "json_class": "Chef::Role",
  "description": "web server role",
  "chef_type": "role",
  "run_list": ["recipe[apt]", "recipe[chef-dotdeb]", "recipe[chef-dotdeb::php54]", "recipe[apache2]", "recipe[apache2::mod_php5]", "recipe[apache2::mod_rewrite]", "recipe[php]", "recipe[mysql]", "recipe[mysql::server]", "recipe[app]", "recipe[composer]", "recipe[sqlite]", "recipe[vim]", "recipe[cron]", "recipe[ntp]"]

That's all! Our environment is ready for verification. We execute in the root of the project:

vagrant up

After this command, Vagrant initializes the specified box and starts installing all the necessary software.

What do we have in the end?

As a result, we have a fully configured virtual machine. Access via SSH. To do this, simply execute

vagrant ssh

After adding the IP address and name of the test site to hosts, you simply open it in a browser on the host machine, and the code is executed on the VM.
An important point is maintaining the state of the VM. If this is not done, then after each launch through vagrant up, the software will be reinstalled . At the same time, the whole point of our idea is lost. To solve this situation, Vagrant has the following commands:

  1. vagrant suspend - saves the current state and after the command vagrant upoperation continues from the saved point
  2. vagrant halt - turn off the VM

After executing these commands, you can safely reboot the OS and resume work again.

To destroy all resources associated with the VM, use the vagrant destroy command .
Some articles advise keeping the database on the host machine so as not to risk data loss.

Using Vagrant, you can also raise a test cluster, while the communication of virtual machines with each other is configured through the network config property .

Useful reading links

For those who are interested, I suggest that you familiarize yourself with the following resources:

Vagrant + Chef environment files, which was configured in this article.


  1. - documentation. Required reading.
  2. — список box'ов на всех популярных ОС
  4. — очень классная статья по настройке staging окружения. Обязательна к прочтению.
  5. — php разработчикам


  1. — официальный сайт
  2. — deployment
  3. — обязательна к прочтению. Раскрывает все базовые вещи Chef

Thanks to everyone who read to the end. I hope the article turned out to be useful and aroused positive emotions in you, as it happens with those who hear, for example, about Vagrant for the first time.
I apologize in advance for inaccuracies and, possibly, technical illiteracy in one form or another.

Also popular now: