Deploying a LAMP application with Chef, Vagrant, and EC2 (3 of 3)

This is the final article in a three-part series on managing LAMP environments with Chef, Vagrant, and EC2. This article covers configuring and deploying PHP web applications.

In this context, configuring an application refers to setting up an Apache virtual host, granting database privileges, writing application config files, etc. Deployment refers to checking out the latest sources from version control, building the application, and installing it on all the nodes. Chef is the perfect tool to configure a web application, and in some cases it can be appropriate for deployment as well.

Articles in this series:

In this article:

In this tutorial, we’ll configure and deploy an example application called “hello_app”. You can get the code for the hello_app cookbook at Github. All the files in this cookbook are designed to make it easy to re-use them for other applications. You can just do a search and replace on the application name “hello_app” (though you’ll almost certainly want to customize some other aspects of the configuration as well).

Configuring the application

Application configuration is the process of configuring the system to support the application, and writing config files for the application which describe the surrounding system.

Create a new cookbook

Start by creating a new cookbook for the web application.

knife cookbook create hello_app

Edit the README.

Edit cookbooks/hello_app/README.md and add a short description.

Define metadata.

Edit cookbooks/hello_app/metadata.rb.

If you configured knife to automatically set the maintainer and license information when setting up Chef and knife, you’ll just need to specify the cookbook dependencies. Our LAMP web application depends on having the mysql and apache2 cookbooks in our Chef repository. Specify the dependencies by adding these lines to metadata.rb:

depends          "apache2"
depends          "mysql"

Edit the default recipe.

Edit cookbooks/hello_app/recipes/default.rb. This default recipe was created automatically by knife. If you configured knife properly, the default recipe will contain a nice header with maintainer, copyright, and license information. You can copy/paste this header into the other recipes you’ll create below. Edit this default recipe so that it just loads the app webserver recipe, by adding the following line to cookbooks/hello_app/recipes/default.rb:

include_recipe "hello_app::webserver"

Define default attributes

Define defaults for the attributes we’ll use in our recipes in cookbooks/hello_app/attributes/default.rb.

default['hello_app']['db_user'] = 'hello_app'
default['hello_app']['db_name'] = 'hello_app'
default['hello_app']['server_name'] = 'hello_app.example.com'
default['hello_app']['docroot'] = '/srv/hello_app/current'
default['hello_app']['config_dir'] = '/srv/hello_app/shared/config'

These values are fine for this tutorial, though you’ll obviously want to change them when configuring your own applications.

Create a webserver recipe for the application

Most of the cookbook’s work is done by recipes. See Recipes in the Chef documentation for details about how to write them.

The first recipe we’ll create is for configuring the hello_app application on web servers.

Create the recipe file cookbooks/hello_app/recipes/webserver.rb. You can copy the comment header from the default.rb recipe; only the “Recipe::” name should need changing.

#
# Cookbook Name:: hello_app
# Recipe:: webserver
#
# Copyright 2012, Jason Grimes
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

app_name = 'hello_app'
app_config = node[app_name]
app_secrets = Chef::EncryptedDataBagItem.load("secrets", app_name) 

include_recipe "apache2"
include_recipe "apache2::mod_php5" 

# Set up the Apache virtual host 
web_app app_name do 
  server_name app_config['server_name']
  docroot app_config['docroot']
  #server_aliases [node['fqdn'], node['hostname']]
  template "#{app_name}.conf.erb" 
  log_dir node['apache']['log_dir'] 
end

# Determine the master database
if node['roles'].include?('db_master')
  master_db_host = 'localhost'
else
  results = search(:node, "role:db_master AND chef_environment:#{node.chef_environment}")
  master_db_host = results[0]['ipaddress']
end 

#
# Set up the local application config.
# This part is most likely to be different for different applications.
#

directory "#{app_config['config_dir']}" do
  owner "root"
  group "root"
  mode "0755"
  action :create
  recursive true
end

template "#{app_config['config_dir']}/local.config.php" do
  source "local.config.php.erb"
  mode 0440
  owner "root"
  group node['apache']['group']
  variables(
    'db_master' => {
      'user' => app_config['db_user'],
      'pass' => app_secrets[node.chef_environment]['db_pass'],
      'dbname' => app_config['db_name'],
      'host' => master_db_host,
    } 
  )
end

The hello_app::webserver recipe does the following:

  • Ensures the appropriate apache and php recipes are loaded using include_recipe. This is where you should specify the Apache modules, PHP extensions, and other packages your application requires.
  • Creates an Apache virtual host using the web_app resource from the apache2 cookbook.
  • Determines the master database by searching the Chef server for nodes in the current environment with the db_master role. (See Search in the Chef manual for details.)
  • Creates a config directory (with the directory resource) and writes a PHP config file (with the template resource) with database connection information for the application.

The recipe creates config files from templates. Chef template files use ERB, a Ruby templating system. See the Chef documentation on Templates for details.

Add a template for the Apache virtual host configuration. Create cookbooks/hello_app/templates/default/hello_app.conf.erb with the following contents:

<VirtualHost *:80>
  ServerName <%= @params[:server_name] %>
  ServerAlias <% @params[:server_aliases] && @params[:server_aliases].each do |a| %><%= "#{a}" %> <% end %>
  DocumentRoot <%= @params[:docroot] %>

  <Directory <%= @params[:docroot] %>>
    Options FollowSymLinks
    AllowOverride All
    Order allow,deny
    Allow from all
  </Directory>

  LogLevel info
  ErrorLog <%= @node[:apache][:log_dir] %>/<%= @params[:name] %>-error.log
  CustomLog <%= @node[:apache][:log_dir] %>/<%= @params[:name] %>-access.log combined
</VirtualHost>

Add a template for local application config (database connection info, etc.). Create cookbooks/hello_app/templates/default/local.config.php.erb:

<?php
// Database connection config
return array(
    'db_master' => array(
        <% @db_master.each do |key, value| -%>
        '<%= key %>' => '<%= value %>',
        <% end -%>
    ),
);

Create a database recipe for the application

Another recipe is used to configure the master database for the application. It sets up a MySQL user account for the application, and creates the application’s logical database.

Create the recipe file cookbooks/hello_app/recipes/db_master.rb:

#
# Cookbook Name:: hello_app
# Recipe:: db_master
#
# Copyright 2012, Jason Grimes
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

app_name = 'hello_app'
app_secrets = Chef::EncryptedDataBagItem.load("secrets", app_name) 

# Get mysql root password
mysql_secrets = Chef::EncryptedDataBagItem.load("secrets", "mysql")
mysql_root_pass = mysql_secrets[node.chef_environment]['root'] 

# Create application database
ruby_block "create_#{app_name}_db" do
  block do
    %x[mysql -uroot -p#{mysql_root_pass} -e "CREATE DATABASE #{node[app_name]['db_name']};"]
  end 
  not_if "mysql -uroot -p#{mysql_root_pass} -e "SHOW DATABASES LIKE '#{node[app_name]['db_name']}'" | grep #{node[app_name]['db_name']}";
  action :create
end

# Get a list of web servers
webservers = node['roles'].include?('webserver') ? [{'ipaddress' => 'localhost'}] : search(:node, "role:webserver AND chef_environment:#{node.chef_environment}")

# Grant mysql privileges for each web server 
webservers.each do |webserver|
  ip = webserver['ipaddress']
  ruby_block "add_#{ip}_#{app_name}_permissions" do
    block do
      %x[mysql -u root -p#{mysql_root_pass} -e "GRANT SELECT,INSERT,UPDATE,DELETE 
        ON #{node[app_name]['db_name']}.* TO '#{node[app_name][:db_user]}'@'#{ip}' IDENTIFIED BY '#{app_secrets[node.chef_environment]['db_pass']}';"]
    end
    not_if "mysql -u root -p#{mysql_root_pass} -e "SELECT user, host FROM mysql.user" | 
      grep #{node[app_name]['db_user']} | grep #{ip}"
    action :create
  end
end

Create an encrypted data bag with the database passwords for the application:

APP=hello_app
knife data bag create --secret-file ~/.chef/encrypted_data_bag_secret secrets $APP

{
  "id": "hello_app",
  "prod": {
    "db_pass": "awesome-mysql-password-for-hello_app-user"
  },
  "dev": {
    "db_pass": "hello-dev-db-password"
  }
}

Store the encrypted data bag in version control.

cd $CHEF_REPO
mkdir -p data_bags/secrets 
knife data bag show secrets $APP -Fj > data_bags/secrets/$APP.json
git add data_bags
git commit -m "Add encrypted data bag for $APP secrets."

Commit and upload the application cookbook

Commit to Git:

git add cookbooks
git commit -m 'Add cookbook for hello world LAMP application.'

Upload the cookbook to the Chef server:

knife cookbook upload hello_app

Customize attributes in the dev environment

There will be slight differences in the application’s config on our development VM. This can be handled by specifying “override attributes” in the dev environment, which will be used in place of the default attributes.

Edit environments/dev.rb and append the following:

override_attributes ({
  "hello_app" => {
    "server_name" => "hello_app.dev",
    "docroot" => "/home/vagrant/apps/hello_app"
  }
})

The reason for overriding the web server document root is that we want to store the application source files in our development working directory. In part 2 of this tutorial, we configured /home/vagrant/apps as a shared directory in our VM, which maps to ~/dev/lamp-vm on our host development workstation. This lets us edit the source files in our IDE and view the changes immediately on the VM web server, without having to deploy them.

Commit the environment changes to version control:

git add environments
git commit -m 'Override hello_app attributes in dev environment.'

Upload the environment definition to the Chef server:

knife environment from file dev.rb

Add to Chef roles

Edit roles/webserver.rb and add the hello_app::webserver recipe to the webserver role. If you want it to run in all environments, add the recipe to the all_env array we created when setting up roles in Part 2 of this tutorial:

all_env = [ 
  # ..., 
  "recipe[hello_app::webserver]", 
]

If you only want it to run in the dev environment, merge it with the all_env array directly in the env_run_list command, like this:

env_run_lists(
  "_default" => all_env,
  "prod" => all_env,
  "dev" => all_env + ["recipe[hello_app::webserver]"],
)

Edit roles/db_master.rb and add the hello_app::db_master recipe to the db_master role (either in the all_env array, or directly in the env_run_list arguments, just like the webserver recipe):

all_env = [
  "role[base]", 
  "recipe[mysql::server]",
  "recipe[hello_app::db_master]"
]

Commit roles to Git:

git add roles
git commit -m 'Add hello_app recipes to webserver and db_master roles.'

Upload roles to Chef server:

knife role from file webserver.rb
knife role from file db_master.rb

Provision and test

SSH into both the Vagrant and EC2 instances and run the following command to configure the new application:

sudo chef-client

Then add the dev and production hostnames to /etc/hosts:

localhost hello_app.dev 
1.2.3.4 hello_app.example.com # Use your public EC2 IP address instead of 1.2.3.4

When you’re ready to release it publicly, you’ll need to add a DNS record for your production hostname instead of using your hosts file. You should also make sure you’ve manually allocated an elastic IP, instead of using the temporary public IP that is automatically assigned to new instances.

To test it out, copy a test file to your document root and then load it in your browser. You can use the test-config.php file from my sample hello_app repository.

To get the test file into your development VM:

mkdir -p /home/vagrant/apps/hello_app
cd /home/vagrant/apps/hello_app
ln -s /srv/hello_app/shared/config ./config # Or, on a Windows host, copy the directory over instead of symlinking.
wget https://raw.github.com/jasongrimes/hello_app/master/test-config.php

Then load http://hello_app.dev:8080/test-config.php in your browser. You should see an OK message.

In your EC2 instance:

sudo mkdir /srv/hello_app/test
sudo ln -s /srv/hello_app/test /srv/hello_app/current
cd /srv/hello_app/current
sudo ln -s /srv/hello_app/shared/config /srv/hello_app/current/config
cd /srv/hello_app/current
sudo wget https://raw.github.com/jasongrimes/hello_app/master/test-config.php

…and load http://hello_app.example.com/test-config.php in your browser.

Deploying the application

Deployment is the process of getting the latest version of an application installed on all the nodes.

Should you use Chef to deploy your web application?

Application deployment is a different animal from application configuration. To configure a LAMP application, you have to know something about the surrounding systems–what’s the database password, where’s the memcache server, what’s the hostname. This is the sort of thing that a configuration management tool like Chef is perfect for.

But in my view, web application deployment belongs more in the realm of day-to-day development. While configuration changes infrequently, deployment is the sort of thing a developer should be able to do as often as possible.

There are also cases in which deployment should not be entirely automatic–for example, if a database schema change will lock tables for a long time, it may need to be done manually, taking systems offline one at a time, to avoid prolonged downtime.

In larger or more complex projects, I think a separate deployment toolchain is appropriate (ex. Capistrano, Fabric, or hand-rolled scripts run through a build tool like Phing).

But in simple cases, or when just getting started with a project, it can be easiest to just deploy the application with Chef. The rest of this tutorial shows one way to do that.

Overview of Chef’s deploy resource

Chef’s deploy resource can be used to deploy web applications. It’s a port of the popular Ruby deployment tool Capistrano.

The deployment process happens in four phases:

  1. checkout: Check out the source code from version control into a versioned directory.
  2. migrate: Run database “migrations” (i.e. schema changes). This step just executes whatever migration tool you use in your build process (ex. dbdeploy or Doctrine migrations). Setting up a migration tool is beyond the scope of this tutorial, so we’ll skip the migration step for now and assume you update the database schema separately before deploying the application.
  3. symlink: Symlink the checked out sources as the “current” version, and add symlinks to any shared configuration files. (Using symlinks in this way makes it quick to switch to the new version, and to roll back if needed.)
  4. restart: Restart any necessary services (like Apache).

Hooks are available to execute custom code as callbacks in between each phase: before_migrate, before_symlink, before_restart, and after_restart. You also specify custom migrate and restart commands.

See the deploy discussion in the Chef documentation for details about the deployment process.

Create a deploy recipe

We’ll create a dedicated recipe for deploying the hello_app application. Create the following file in cookbooks/hello_app/recipes/deploy.rb:

#
# Cookbook Name:: hello_app
# Recipe:: deploy
#
# Copyright 2012, Jason Grimes
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

include_recipe "hello_app::webserver" 

deploy_revision node['hello_app']['deploy_dir'] do
  scm_provider Chef::Provider::Git 
  repo node['hello_app']['deploy_repo']
  revision node['hello_app']['deploy_branch']
  enable_submodules true
  shallow_clone false
  symlink_before_migrate({}) # Symlinks to add before running db migrations
  purge_before_symlink [] # Directories to delete before adding symlinks
  create_dirs_before_symlink ["config"] # Directories to create before adding symlinks
  symlinks({"config/local.config.php" => "config/local.config.php"})
  # migrate true
  # migration_command "php app/console doctrine:migrations:migrate" 
  action :deploy
  restart_command do
    service "apache2" do action :restart; end
  end
end

Add attributes for deployment to cookbooks/hello_app/attributes/default.rb:

default['hello_app']['deploy_repo'] = 'git://github.com/jasongrimes/hello_app' 
default['hello_app']['deploy_branch'] = 'HEAD'
default['hello_app']['deploy_dir'] = '/srv/hello_app'

This will cause Chef to check out the master branch from my public hello_app repository at Github into a directory under /srv/hello_app/releases/{id}, and then create a /srv/hello_app/current symlink pointing to it.

You can go ahead and use my hello_app repo for this tutorial, or you can point this to one of your own Github repositories.

If you don’t want to deploy from the master branch, another approach is to set “deploy_branch” to something like “production”, so only code that is merged into the production branch will be deployed.

Note that this deploys from a public Github repository. To deploy from a private repository instead, read the next section. If your application is stored in a public repo, you can skip ahead to commit and upload the deploy recipe.

Detour: deploying from a private Github repository

Deploying from a private repository is a little more complicated. You’ll need to set up an SSH keypair, and access Git over SSH.

Create an SSH keypair for use as a Git “deploy key”:

cd ~/.ssh
KEYNAME=hello_app_deploy_key
ssh-keygen -f"$KEYNAME" -N ''

Go to Github and add a deploy key to your repository. Use the public key from hello_app_deploy_key.pub.

Next we need to add the private key to the encrypted data bag for the application secrets. Because data bags are in JSON format, the private key must be stored with all newlines replaced by the string “\n”.

On Mac OS X, you can use the following command to translate newlines from the private key and copy it to the clipboard. (If you’re not using a Mac, omit the |pbcopy part, and manually copy/paste the key.)

tr "n" "#" < $KEYNAME | sed 's/#/\n/g' | pbcopy

Edit the encrypted data bag for the application secrets:

APP=hello_app
knife data bag edit secrets $APP --secret-file ~/.chef/encrypted_data_bag_secret

Add a deploy_key property at the end, with the newline-translated private key

{
  "id": "hello_app",
  "prod": {
    "db_pass": "..."
  },
  "dev": {
    "db_pass": "..."
  }, 
  "deploy_key": "-----BEGIN RSA PRIVATE KEY-----nMIIEowIBAAKCAQEAsv1rrIIvTz5Msv6uwTo....PdLSnWyoxTvjbyEdPizfYn-----END RSA PRIVATE KEY-----n"
}

Store the encrypted data bag item in version control:

knife data bag show secrets $APP -Fj > data_bags/secrets/$APP.json
git add data_bags
git commit -m "Add deploy_key to $APP encrypted data bag secrets."

Add a Git SSH wrapper template: cookbooks/hello_app/templates/default/git-ssh-wrapper.erb:

#!/usr/bin/env bash
# 
# SSH wrapper for deploying from private Github repository
#
# Rendered by Chef - local changes will be replaced

/usr/bin/env ssh -o "StrictHostKeyChecking=no" -i "<%= @deploy_dir %>/id_deploy" $1 $2

Modify the deploy recipe to access Git via SSH using the deploy key. It needs to get the private key into a protected file, and set up the SSH wrapper for Git. You also need to specify the git_ssh_wrapper in the deploy block. The revised cookbooks/hello_app/recipes/deploy.rb is shown below:

#
# Cookbook Name:: hello_app
# Recipe:: deploy
#
# Copyright 2012, Jason Grimes
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#

include_recipe "hello_app::webserver" 

# Handle ssh key for git private repo
secrets = Chef::EncryptedDataBagItem.load("secrets", "hello_app")
if secrets["deploy_key"]
  ruby_block "write_key" do
    block do
      f = ::File.open("#{node['hello_app']['deploy_dir']}/id_deploy", "w")
      f.print(secrets["deploy_key"])
      f.close
    end
    not_if do ::File.exists?("#{node['hello_app']['deploy_dir']}/id_deploy"); end
  end

  file "#{node['hello_app']['deploy_dir']}/id_deploy" do
    mode '0600'
  end

  template "#{node['hello_app']['deploy_dir']}/git-ssh-wrapper" do
    source "git-ssh-wrapper.erb"
    mode "0755"
    variables("deploy_dir" => node['hello_app']['deploy_dir'])
  end
end

deploy_revision node['hello_app']['deploy_dir'] do
  scm_provider Chef::Provider::Git 
  repo node['hello_app']['deploy_repo']
  revision node['hello_app']['deploy_branch']
  if secrets["deploy_key"]
    git_ssh_wrapper "#{node['hello_app']['deploy_dir']}/git-ssh-wrapper" # For private Git repos 
  end
  enable_submodules true
  shallow_clone false
  symlink_before_migrate({}) # Symlinks to add before running db migrations
  purge_before_symlink [] # Directories to delete before adding symlinks
  create_dirs_before_symlink ["config"] # Directories to create before adding symlinks
  symlinks({"config/local.config.php" => "config/local.config.php"})
  # migrate true
  # migration_command "php app/console doctrine:migrations:migrate" 
  action :deploy
  restart_command do
    service "apache2" do action :restart; end
  end
end

Edit cookbooks/hello_app/attributes/default.rb and set the deploy_repo to the SSH path format:

default['hello_app']['deploy_repo'] = 'git@github.com:jasongrimes/hello_app' # Format for private repos
default['hello_app']['deploy_branch'] = 'HEAD'
default['hello_app']['deploy_dir'] = '/srv/hello_app'

Commit and upload the deploy recipe

Commit the deploy recipe to version control, and upload the cookbook to the Chef server.

APP=hello_app
git add cookbooks/$APP 
git commit -m "Add deploy recipe to $APP cookbook."
knife cookbook upload $APP

Add the deploy recipe to the webserver role

Edit roles/webserver.rb. Add the hello_app::deploy recipe to the webserver role, in the same way that you added the hello_app::webserver recipe to the webserver role.

I don’t usually run the deploy recipe on my development VM, because the application is running directly from my dev working directory. So I add the recipe only in the prod environment in roles/webserver.rb:

env_run_lists(
  "_default" => all_env,
  "prod" => all_env + ["recipe[hello_app::deploy]"],
  "dev" => all_env,
)

Note that this requires the db_master role to be specified before the webserver role when setting up the node, because the deploy recipe relies on database credentials set up by the db_master role. This should have been handled during provisioning, as described in part 2 of this tutorial.

Commit the role to version control:

git add roles
git commit -m 'Add hello_app::deploy recipe to webserver role.'

Upload the role to the Chef server:

knife role from file webserver.rb

Test the deployment

SSH into your EC2 instance and run sudo chef-client. This should cause the application to be deployed. Watch for any errors as chef-client runs.

  • Load the site in your browser. If you left the repository set to my hello_app repo at Github, the index page should say “Hello application!” if everything is working.
  • If you didn’t use your own repository already, edit cookbooks/hello_app/attributes/default.rb and change the repository to one of your own.
  • Commit a test file to your repository.
  • SSH into a node and run sudo chef-client
  • Load the test file in your web browser.

Closing remarks

You should now have a basic LAMP stack and a sample web application provisioned in a development VM and on a shared server in EC2. And more importantly, you should be able to deploy new configurations and provision new environments pretty easily.

We had to front-load a lot of work to get to this point, but now that it’s done it will hopefully save you a lot of time in the future. From here on out, chances are you’ll mostly be adding new applications, and tweaking the configuration of your existing environments.

If you got this far, I’d love to hear about how it works out for you. Any feedback about how this tutorial could be improved is always appreciated. Thanks!

11 thoughts on “Deploying a LAMP application with Chef, Vagrant, and EC2 (3 of 3)”

  1. Thanks! For writing, such kind of good blog.
    I am new in Chef I have few doubt such as
    Chef uses SHH (Linux) and winrm (WMI for Window) to configure, deployment and integration then what is use of chef-client ?
    Please let me know, how it will work in case of auto scaling etc.
    I cannot get how chef help to execute platform independent command such as ANT(used in application deployment )

    With Regards
    Siddharth Singh
    snghsiddh@yahoo.com

  2. Thanks for this epic series! I’ve worked my way through it three times with increasing levels of understanding and “using-my-own-project”ness each time. :)

    I believe I’ve spotted a typo in your code for cookbooks/hello_app/recipes/db_master.rb:

    block do
    %x[mysql -u root -p#{mysql_root_pass} -e "GRANT SELECT,INSERT,UPDATE,DELETE
    ON #{node[app_name]['db_name']}.* TO '#{node[app_name][:db_user]}'@'#{ip}' IDENTIFIED BY '#{app_secrets[node.chef_environment]['db_pass']}';"]
    end

    In the 3rd line, I believe it should be '#{node[app_name]['db_user']', not '#{node[app_name][:db_user]'.

  3. This was brilliant. I was wondering how to lay out Chef for a single VM instance with multiple apps, and you provided the whole solution, in a very detailed way.

    The only thing I think could be improved, perhaps, would be a way to generate the cookbook for new apps/sites, so you would provide the name of the app (and perhaps a few additional details) to a command line tool (perhaps made with Thor (https://github.com/wycats/thor), to avoid the whole work of copying, and editing the new cookbook.

    Alternatively, would it be possible to say, have a single cookbook for static sties and reuse it by several apps? (Sorry, still new to Chef)

    Cheers,

    -Marcelo.

  4. Hi.
    This is kind of off topic but I need some advice from an established blog.
    Is it very hard to set up your own blog? I’m not very technical but I can figure things out pretty fast. I’m thinking about making my own but I’m not sure where to begin. Do you have any ideas or suggestions? Cheers

    my web blog; Sale

  5. I am getting permission denied problem when deploying an app from a private repository. It seems that the ssh wrapper is not kicking in or something. Any ideas?

  6. Amazing work Jason! Thank you very much, it helped me big time.

    @philrugayan – check if user cloning the git app has proper rights to access the private SSH key – this was a problem in my case.

Leave a Reply to Siddharth Singh Cancel reply

Your email address will not be published. Required fields are marked *

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>