Freedom, Community & Sustainability

Set up a virtual development environment for PHP automatically

December 15, 2014 -- William
Last modified on February 2018
Duration: +- 15 minutes

To set up our development environment and be able to replicate it automatically we will use Vagrant, Puppet and Composer. With these three tools we can reproduce locally a development environment that is the same as the production environment. This is the ultimate solution to the problems that are "strange because it works on my machine"! This tutorial is intended for GNU/Linux users.

Vagrant will take care of the virtual machines, it downloads the iso images, creates a virtual machine in virtualbox (you need to have VirtualBox installed as well), installs the OS and then, calls Puppet.

Puppet will take care of ensuring that the services that we need on this machine (LAMP) are installed and running. Otherwise it will install them for us. Among other things it can also ensure that Composer is installed and run it.

Composer is a dependency manager for PHP. It will take care of ensuring that all PHP dependencies are installed with the correct versions.

How to proceed

Install Vagrant:

sudo apt-get install vagrant
mkdir ~/vagrant
cd ~/vagrant
vagrant box list
vagrant init <name of a box in the list>
vagrant up
vagrant ssh

With these commands you install Vagrant, initiate a vagrant box and log into it. At this point you are on the command line of your newly created virtual machine. That's a pretty easy way to create a virtual machine to work on.

The command vagrant box list displays the list of available boxes (those that were already downloaded). To add more boxes use the command vagrant box add <name> <url>. The URL of many boxes can be found at vagrantbox.es.

Configure Vagrant:

vim Vagrantfile

The Vagrantfile is where you can configure the box, the provisions, the network, additional modules and so on. At the very minimum you need to specify the config.vm.box you want to use (the one specified when you ran the vagrant init <name> command). Some common configurations are:

config.vm.box = "<name of the box>"
config.vm.box_url = "<URL of the box>"
config.vm.provision "puppet"
config.vm.synced_folder "../", "/home/vagrant/"
config.vm.network :forwarded_port, guest: 80, host: 8080
# Use VBoxManage to customize the VM. For example: change memory
config.vm.provider :virtualbox do |vb|
  vb.customize ["modifyvm", :id, "--memory", "1024"]

On the above example we are first specifying the name of the box (config.vm.box) we are using and the URL of that box (config.vm.box_url). Specifying the URL is good for people who are copying your Vagrant file because they won't have to look for the box on the internet in order to be able to download it.

Then we call puppet to provision the box for us (config.vm.provision). Provisioning means to add services to a box by executing shell scripts automatically in the command line of the virtual machine. It works just as if you logged into the virtual machine and executed some shell commands manually. What we want here is to automate the provisioning of our Vagrant box by calling Puppet to do this for us. If you want to run a shell script that you wrote manually, instead of using puppet, you should write instead :

config.vm.provision :shell, :path => "<path to the provision.sh file>"

The synched_folder is good to access the folders of your site without having to ssh into the virtual machine. In short, this will keep a local folder synchronized between the virtual machine and your real computer. Usually you will use a version control system like GIT on a folder on your machine rather than logging into the virtual machine to do this.

Finally we are configuring VirtualBox (config.vm.provider) to have 1Mb of RAM by customizing the VirtualBox configurations.

There are many more configurations you can set up on a Vagrantfile but this should be more than enough to get you started.

Take a look at Vagrant configurations for puppet on the official Vagrant documentation.

Install Puppet:

sudo apt-get install puppet

Configure Puppet:

You need to either download ready-to-use modules from https://forge.puppetlabs.com/ or create your own puppet “manifests” in order for puppet to do it's magic. You will probably want a combination of both, download a module and then tweak it to your needs. Writing puppet manifests is not hard but it's not trivial either. For the scope of this tutorial we will just give you some hints to understand manifests that were already written by others.

Manifests are files with "pp" extension, written in the puppet language. Once you have written the manifest you can check it's syntax with the command puppet parser validate file_name.pp. If the validation doesn't return anything you can apply it with puppet apply file_name.pp.

Puppet has its own declarative language to specify the state of resources. In it's basic form it follows this structure:

type {'title':
attribute => 'value',

See all types here: https://puppet.com/docs/puppet/5.3/type.html. You can also use variables, conditionals and loops like in any other programming language. Take a look at the official documentation about writing puppet manifests or puppet modules.

Once you have a manifest file, use “include module_name” in your custom puppet configuration file (manifests/default.pp) in order to use the module. Next to your config file you can create a "modules" folder and put all modules on this folder. There should be only one manifest outside the modules folder, the one for global configurations.

Note: classes in puppet are not like the OOP classes. Puppet classes are blocks of code that can be invoked by name using "include".

Puppet on the command line:

You can interact with puppet in the command line (without having to enter the manifests).
To have a general view of a certain type of resource you can type puppet describe resource_type

puppet describe user

Lists info about users.

To view resources you can type: puppet resources <type> <title>:

puppet resource package apache2

Checks if the package apache2 needs to be installed. The resources command shows the specific portion of code concerning the "type" and "title".

Type puppet help to see other subcommands apart from describe and resources.

Composer configuration:

Composer is a dependency manager for PHP. It is not a package manager because it handles packages locally whereas package managers install packages globally. Composer is perfect for us because we want to set up different PHP configurations for different projects.

The best way to learn about composer is to visit their website at https://getcomposer.org/. To summarize what you need to know as a developer, keep in mind that you need to:

  1. Install composer (this creates a composer.phar file):
    curl -sS https://getcomposer.org/installer | php
  2. Create a composer.json file following the explanations below or the documentation.
  3. Install the dependencies using Composer with one simple command
    php composer.phar install
  4. A file called composer.lock will be created to prevent version updates for these dependencies.

In it's simplest form, the composer.json file will contain the name of the packages and the version of the PHP modules you want to install. You can require any of the official packages in your composer.json file like so:

    "require": {
       "mysql/autobackup": "3.0-rc6"

After creating your composer.json file you need to update your configurations with the command:

php composer.phar update

This is all you need to do in order to create automatic backups of your mysql databases in all your virtual machines.

I hope this tutorial helped you grasp the power of leveraging the configuration of your development environments to automation tools. By using in combination Vagrant, Puppet and Composer we are able to replicate locally the same environment you will have in production.

Read also:

Add new comment