Vagrant, Puppet, and Symfony2 - The Three Musketeers


So I have been playing with Vagrant, Puppet, and Symfony for about the past month or so. There have been a few issues that I have run into, but it has mostly been a joy to work with.

Vagrant

Vagrant allows you to use VirtualBox to spin up a virtual machine. This machine can be pretty much anything. The thing that makes vagrant so awesome is I can include the Vagrantfile in my repository and all a developer has to do is run vagrant up and if they do not already have the base box, it will download it for them and boot up the machine.

A box is basically a base server. For example, do a base install of ubuntu on a VM and that is where you will start from. It is where everyone else will start from as well. You will use Puppet to provision the box, but more on that later.

To get started, download vagrant. If you are using an old version of vagrant (ie 1.0.x) then you will need to uninstall it.

Here’s an example Vagrantfile:

# -*- mode: ruby -*-
# vi: set ft=ruby :

Vagrant.configure("2") do |config|
  config.vm.box = "precise64"
  config.vm.box_url = "http://files.vagrantup.com/precise64.box"
  config.vm.network :forwarded_port, guest: 80, host: 8080
  config.vm.network :private_network, ip: "192.168.33.10"
  config.vm.synced_folder ".", "/var/www/app.local", :nfs => true
  config.vm.provider :virtualbox do |vb|
    vb.customize ["modifyvm", :id, "--memory", "1024"]
  end
  config.vm.provision :puppet do |puppet|
    puppet.options        = "--verbose --debug"
    puppet.manifests_path = "app/Resources/puppet/manifests"
    puppet.manifest_file  = "base.pp"
    puppet.module_path    = "app/Resources/puppet/modules"
  end
end

I want to point out that the puppet.options can be commented out. I am one of those really odd people that like to see a lot of things scroll on the screen. This is also really helpful for when you run into issues when booting up the VM.

Another thing that I want to point out is the manifest and module path. These are both included in the app/Resources folder so there is one place within the project that I can put these. In my projects, everything in the modules directory is a git submodule.

Puppet

Next, let’s work on the manifest file. You are going to need to include some modules. The ones that you will need are MySQL, Apache, firewall, and stdlib. Please read the documentation for these since they show you how to set use these in your manifest file.

If you would like to use more, you can visit http://forge.puppetlabs.com for a large list of various modules.

Now let’s setup our manifest file.

exec { "apt-update":
    command => "/usr/bin/apt-get update",
}
####
#
# Dependencies
#
$dependencies = [
    "php5",
    "php5-cli",
    "php-apc",
    "php5-curl",
    "php5-sqlite",
    "php5-intl",
    "php5-mcrypt",
    "php5-imagick",
    "php5-xdebug",
    "git",
    "vim",
    "sendmail",
]
package { $dependencies:
    ensure  => present,
    require => Exec['apt-update'],
}
#### EOF: Dependencies ####

file { "/var/www/app.local":
    ensure  => "directory",
    #owner   => "www-data",
    #group   => "www-data",
    #mode    => "0775",
    recurse => true,
}

class { "apache": }
class { "apache::mod::php": }
apache::vhost { "app.local":
    priority   => 000,
    port       => 80,
    docroot    => "/var/www/app.local/web",
    ssl        => false,
    servername => "app.local",
    options    => ["FollowSymlinks MultiViews"],
    override   => ["All"],
    ensure     => present,
    require    => File['/var/www/app.local']
}

class { "mysql": }
class { "mysql::php": }
class {"mysql::server":
    config_hash => {
        "root_password" => "root"
    }
}
mysql::db { 'symfony':
    user     => 'symfony',
    password => 'symfony',
    host     => 'localhost',
    grant    => ['all'],
}

I know there’s a lot of stuff in there, but once you take a look at it, it’s pretty straight forward. There might be some edits to this manifest file that you’ll need to make based on what you want to do.

As I was setting this up, one of the issues I had was trying to get packages installed via apt-get. The first part of the manifest takes care of that part.

Next, it will install all the php stuff. You can customize this to your needs. If you are working on a project and it complains that some feature needs to be installed, say mcrypt for php. Usually you would just run sudo apt-get install php5-mcrypt or apt-cache search mcrypt to find that package you want. This is all that puppet is doing. Pretty simple right?

So now I want to pick apart

file { "/var/www/app.local":
    ensure  => "directory",
    #owner   => "www-data",
    #group   => "www-data",
    #mode    => "0775",
    recurse => true,
}

I ran into some issues when I had the owner/group uncommented. This is because Vagrant sets up that directory as a NFS share. I left it in because I plan on eventually finding a way since when the project gets deployed, I can use puppet again. This also makes sure that this directory exists on the server.

Next comes all the apache stuff. It will setup your vhost and make sure that apache is installed and running. Update this to your liking.

NOTE: If you want to enable SSL, you need to be aware that you’ll need to setup the proper port forwarding. It took me a little while on Google to find some solutions.

NOTE: The vhost that is setup will response to requests that are for app.local so make sure you add a line in your /etc/hosts file. ie: 127.0.0.1 app.local

Vagrant and Symfony

Now things should be ready for you to run vagrant up and watch the VM boot. If you did not comment out the puppet options in the Vagrantfile it can be pretty interesting to watch it work it’s magic.

There are a few things that you need to be aware of with this work flow. Most of the symfony console commands are now useless to you. Because MySQL is running on the VM you no longer can use run any commands that need to connect to the database.

You also cannot clear your cache or run some of the other commands you are use to. This is because the path on your host machine is different than the path on the guest machine. At least I assume this is the case.

To be able to run these commands, you need to ssh into the vagrant vm by running the vagrant ssh command.

Conclusion

I hope that you have learned something from this and in the future I will be posting about how I use Capifony to deploy this setup to a server.

Further Reading

  1. https://gist.github.com/JoshuaEstes/5230868
  2. http://docs.vagrantup.com/v2/
  3. http://docs.vagrantup.com/v2/cli/index.html
  4. http://docs.vagrantup.com/v2/synced-folders/nfs.html
  5. http://docs.vagrantup.com/v2/debugging.html
  6. https://github.com/mitchellh/vagrant/wiki/Available-Vagrant-Boxes
  7. http://docs.puppetlabs.com/puppet/
  8. http://docs.puppetlabs.com/references/stable/type.html
  9. http://forge.puppetlabs.com/