Symfony2, Vagrant, and Chef


If you are like me, I hate having a lot of extra stuff on my laptop such as mysql, apache/nginx, etc. All those extra services are such a pain in the ass to maintain and other developers may have different versions of the same things. This can lead to issues during development and has the potential to cause issues with your application when in production that cannot be reproduced.

Assumptions

It is assumed that you have the following installed and working.

Creating a chef-repo and an app Cookbook

You can read more about this process here https://docs.chef.io/chef/essentials_repository.html since this is not the full process. You are just wanting to get from point A to point B quickly.

$ cd /path/to/symfony2
$ mkdir -vp app/chef-repo/cookbooks
mkdir: created directory ‘app/chef-repo’
mkdir: created directory ‘app/chef-repo/cookbooks’
$ berks cookbook app app/chef-repo/cookbooks/app
      create  app/chef-repo/cookbooks/app/files/default
      create  app/chef-repo/cookbooks/app/templates/default
      create  app/chef-repo/cookbooks/app/attributes
      create  app/chef-repo/cookbooks/app/libraries
      create  app/chef-repo/cookbooks/app/providers
      create  app/chef-repo/cookbooks/app/recipes
      create  app/chef-repo/cookbooks/app/resources
      create  app/chef-repo/cookbooks/app/recipes/default.rb
      create  app/chef-repo/cookbooks/app/metadata.rb
      create  app/chef-repo/cookbooks/app/LICENSE
      create  app/chef-repo/cookbooks/app/README.md
      create  app/chef-repo/cookbooks/app/CHANGELOG.md
      create  app/chef-repo/cookbooks/app/Berksfile
      create  app/chef-repo/cookbooks/app/Thorfile
      create  app/chef-repo/cookbooks/app/chefignore
      create  app/chef-repo/cookbooks/app/.gitignore
      create  app/chef-repo/cookbooks/app/Gemfile
      create  .kitchen.yml
      append  Thorfile
      create  test/integration/default
      append  .gitignore
      append  .gitignore
      append  Gemfile
      append  Gemfile
You must run `bundle install' to fetch any new gems.
      create  app/chef-repo/cookbooks/app/Vagrantfile

You can commit all of this into your repository. If you plan to expand on this and use more cookbooks or upload them to a chef server, you will need to do some more work. This will just get you started in the right direction.

The app cookbook is only used locally to help provision you vagrant machine(s).

Next we will need to modify the cookbook we created so it provisions the vagrant machine correctly.

Add Required Cookbooks

You will need to append these cookbooks to the metadata.rb file.

# ./app/chef-repo/cookbooks/app/metadata.rb
depends 'apache2', '~> 3.0.0'
depends 'apt', '~> 2.6.0'
depends 'database', '~> 2.3.0'
depends 'php', '~> 1.5.0'
depends 'postgresql', '~> 3.4.14'

NOTE: You can swap out the postgresql cookbook with mysql, the reason I use postgresql is because I deploy symfony 2 apps to heroku.

You can find other cookbooks by checking out the Chef Supermarket

Create a Template for Apache Vhost

# ./app/chef-repo/cookbooks/app/templates/default/default.conf.erb
# -*- mode: apache -*-
# vi: set ft=apache :
<VirtualHost *:80>
    #ServerName domain.tld
    #ServerAlias www.domain.tld

    DocumentRoot /var/www/web
    <Directory /var/www/web>
        # enable the .htaccess rewrites
        AllowOverride All
        Order allow,deny
        Allow from All
    </Directory>
</VirtualHost>

You can see more about this on symfony’s web site; Configuring a Web Server

Create Your attributes File

# ./app/chef-repo/cookbooks/app/attributes/default.rb
default['app']['dbname'] = 'symfony'
default['app']['dbuser'] = 'postgres'

The attributes file allows you modify things a little easier when deploying the project to production or if you need to change a few settings.

Modify Your default Recipe

# ./app/chef-repo/cookbooks/app/recipes/default.rb
%w{git vim ruby-dev php5-curl php5-pgsql php5-xdebug libpq-dev}.each do |pkg|
  package pkg do
    action :upgrade
    notifies :run, 'execute[apt-get-update-periodic]'
  end
end

# Apache
web_app 'symfony' do
  template 'default.conf.erb'
  notifies :restart, 'service[apache2]'
end

# Postgress
postgresql_connection_info = {
  :host     => '127.0.0.1',
  :username => node['app']['dbuser'],
  :password => node['postgresql']['password']['postgres']
}
file "/home/vagrant/.pgpass" do
  content "#{node['postgresql']['config']['listen_address']}:#{node['postgresql']['config']['port']}:#{node['app']['dbname']}:#{node['app']['dbuser']}:#{node['postgresql']['password']['postgres']}"
  owner "vagrant"
  group "vagrant"
  mode '0600'
  action :create
end
postgresql_database node['app']['dbname'] do
  connection postgresql_connection_info
end

Creating Your Berksfile

# ./Berksfile
# -*- mode: ruby -*-
# vi: set ft=ruby :
source "https://supermarket.getchef.com"
cookbook "app", path: "app/chef-repo/cookbooks/app"

Creating Your Vagrantfile

# ./Vagrantfile
# -*- mode: ruby -*-
# vi: set ft=ruby :

Vagrant.require_version ">= 1.7.1"
Vagrant.configure(2) do |config|
  config.berkshelf.enabled = true
  config.vm.box = "ubuntu/trusty64"
  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", type: "nfs"
  config.vm.provider "virtualbox" do |vb|
    # Customize the amount of memory on the VM:
    vb.memory = "1024"
  end
  config.push.define "heroku" do |push|
    push.app = ""
  end
  config.vm.provision "shell", inline: "sudo apt-get update"
  config.vm.provision "chef_solo" do |chef|
    chef.run_list = [
      'recipe[apt]',
      'recipe[php]',
      'recipe[database::postgresql]',
      'recipe[postgresql::server]',
      'recipe[postgresql::client]',
      'recipe[apache2]',
      'recipe[apache2::mod_php5]',
      'recipe[apache2::mod_env]',
      'recipe[apache2::mod_alias]',
      'recipe[app]',
    ]
    chef.json = {
      php: {
        directives: {
          expose_php: 'Off',
          max_input_time: '-1',
          memory_limit: '-1',
          error_reporting: 'E_ALL',
          display_errors: 'On',
          post_max_size: '128M',
          upload_max_filesize: '128M'
        }
      },
      apache: {
        mpm: 'prefork',
        docroot_dir: '/var/www/web'
      },
      postgresql: {
        enable_pgdg_apt: true,
        config: {
          listen_addresses: '*'
        },
        password: {
          postgres: 'postgres'
        }
      }
    }
  end
end

End

You should now be able to run vagrant up and then visit http://localhost:8080 in your browser. This should allow all developers on your team to work within the exact same stack and will allow you to easily modify configuration settings to how you want.

This guide should be basic enough to get you up and running. You may need to modify some of the files to your liking or to configure some extras.