shopping24 tech blog

s is for shopping

December 22, 2013 / by Daniel Lucks / / @

Tutorial: Create a development environment using Vagrant and Puppet

A lot of web developers are common with the following situation - somebody in your company shows you a bug on your web platform and wants you to fix it. The first thing to do is to reproduce this bug in your local development environment and start debugging. But whatever you do, you cannot reproduce this bug on your machine. Damn! So the only option left is to ssh onto your production environment and modify some files to find and fix the bug. Very bad idea! - But is this the really only option?

The problem is obvious. Your local development environment is not identical to your production environment! Different OS, different versions of applications and modules, different access data, different technology, and so on. This blog post will help you how to get rid of this problem by showing you how to set up and getting started with two tools: Vagrant and Puppet.

Vagrant

Vagrant is an application for managing and configuring virtual machines. The only thing you have to do is to write a single configuration file which describes the setup and state of your virtual machines. Vagrant takes care of everything else. Vagrant also provides a simple CLI for interacting with the VM.

Puppet

Puppet is a very powerful tool for server configuration management. By writing so called manifest files you describe the setup of your server. That means you define which software or packages should be installed, which services have to run, and so on.

Step 1: Installing the components

To get started with this tutorial, you will have to download and install the latest versions of the following software:

Step 2: Get a Vagrant box

Vagrant works with so called vagrant boxes. A vagrant box is something like a common virtual machine image wrapped by some vagrant container. In this tutorial we will use such a box containing a VirtualBox Ubuntu (Lucid Lynx) image. This box is provided by the Vagrant website. Open your terminal and execute:

$ vagrant box add lucid32 http://files.vagrantup.com/lucid32.box

This command will download this box file and add it to your Vagrant installation. Now this Lucid Lynx VM should be listed under your available boxes:

$ vagrant box list
lucid32    (virtualbox)

And now let’s start a new project and add a Vagrant configuration file to it:

$ mkdir awesome-project
$ cd awesome-project
$ touch Vagrantfile

We created a new file named Vagrantfile in our project. This empty file has to be filled with the Vagrant configuration. So open it with your favourite text editor and add the following lines to it:

Vagrant::Config.run do |config|
  config.vm.box = "lucid32"
  config.vm.forward_port 80, 3000
end

This config block contains two entries. config.vm.box defines which VM to use and config.vm.forward_port fowards port 3000 of the host (our local machine) to port 80 of the guest (the VM). This is necessary to access our web application running on the VM from our local machine later. And that’s it! To boot the VM just execute the following command in your project directory.

$ vagrant up

Step 3: Get local source code onto the VM

Now the VM is running and ready work with. So let’s add some PHP code to our project - in this case we just add a simple “Hello World” application:

$ mkdir htdocs
$ echo "<?php echo 'Hello World';" > htdocs/index.php

So, we created this PHP code on your local machine. But how do we get it into the VM? You know what!? It is already there! Vagrant mounted our project directory as a shared directory into the VM. To see it, we just log into the VM.

$ vagrant ssh
$ cd /vagrant
$ ls

With vagrant ssh we are able to log into the VM, and Vagrant mounted our local project directory under /vagrant.

Step 4: Setting up a web server using Puppet

The VM is set up and contains our application code. Now it is time to setup a web server. Maybe at this point of this tutorial you’ll ask why there’s not a web server already installed on the VM. Well, of course you can create a vagrant box containing your complete production environment. But what, if you update the software or add some modules in future? You will have to create a completely new box file and distribute it to all of your developers. To avoid this, we are using Puppet.

Let’s create a manifest file in our project directory. By default Puppet tries to load a manifest file located under manifests/default.pp. So just create this file in our project.

$ mkdir manifests
$ touch default.pp

Now we fill this file step by step. At first add the following content.

exec { "apt-get update":
  path => "/usr/bin",
}

This Puppet statement is called a resource. Every resource has a type, title and a set of attributes. The type of this resource is exec, i.e. this resource is an execution of a command. The title of this resource is the command to execute. In this case we want the package manager to update. To install an start an Apache web server add the following two resources to the manifest file.

package { "apache2":
    ensure  => present,
    require => Exec["apt-get update"],
}
service { "apache2":
    ensure  => "running",
    require => Package["apache2"],
}

The first resource is a package resource. This is used to describe any pieces of software that should be installed. In this case, the package apache2 should be installed. You may wonder why not to create just another execution resource like apt-get install apache2. This is because you don’t know if this package may already be installed on the VM. The package resource just says something like “Make sure apache2 is installed” to Puppet.

You even may notify the require attribute in the package resource. This is used to define dependencies between single resources in Puppet. In this case the first exec resource has to be executed completely before installing the apache2 package. This is to ensure the latest stable version of apache2 will be installed.

The third resource is a service resource. It is to start the Apache web server on the VM after installing it. So the web server is installed, but the PHP module is still missing. No problem! Just add another resource to the manifest file.

package { 'php5' :
    ensure => latest,
    require => Exec["apt-get update"],
}

The last step is to link our PHP code into the default document root of the Apache. So the last resource we have to add is to create a symlink file to the shared vagrant directory.

file { "/var/www/htdocs":
    ensure  => "link",
    target  => "/vagrant/htdocs",
    require => Package["apache2"],
    notify  => Service["apache2"],
}

Step 5: Bringing the things together

The last step of this tutorial is to tell Vagrant to use the Puppet manifest file when starting up the VM. And this is very simple. Just add the following line to your Vagrantfile.

config.vm.provision :puppet

If the Lucid32 VM is still running, destroy and re-up it with our new configuration. Just execute the two commands in our local project folder.

$ vagrant destroy
$ vagrant up

This time the vagrant up will take a little bit longer because of the packages to install. But when it finished open your web browser, type http://localhost:3000/htdocs and be happy!

Benefits

  • With a Vagrant and Puppet setup you are able to create a development environment that is identical to your production environment. This makes it easier to debug and fix your application. No more “But it works on my machine!” excuses.
  • Very short setup time for new developers in your team. They just have to install VirtualBox and Vagrant and get the code from your repository.
  • You will be able to version-control your infrastructure. Just think about including your puppet manifests into your project as a git submodule or something else.

This tutorial just wanted to give you an idea of what powerful tools Vagrant and Puppet are - and how to get things running. There will follow a tutorial showing some little more advanced techniques like setting up virtual hosts, create databases or installing Memcached.