Just about everyone who works at Opscode comes from a heavy web operations background. Those who work in webops know that getting an Apache server configured and ready to run applications with various languages and frameworks can be a difficult task. Not only do we have a plethora of languages
to choose from, there's a variety of frameworks within each of those, and they all bring their own Apache configuration directives. Chef makes it easier to configure servers consistently in general, and now a new recipe in the Opscode Chef cookbook makes it easier to deploy application configuration as well.
Whether you're running PHP (or Drupal), Python (er, Django) or Ruby (that is, Rails), you can use the new Apache 'web_app' define to deploy a new application-site vhost configuration template, then kick back with a latté and watch your server logs. Lets take a look at the actual configuration. We'll use a simple Rails example. Note that we're using Passenger to provide "mod_rails", with the Passenger cookbook that Mike Hale and Joshua Sierles wrote.
To get started, we first update to the latest Opscode cookbooks from github. In particular, the Apache2, Passenger and Rails cookbooks are needed. Assuming a local clone of opscode/cookbooks in ~/chef-repo/cookbooks (from using Working With Git wiki doc):
git pull –rebase
Next we create a new Rails project in /srv/myproj. We're sure you'll want to deploy your app, though.
cd /srv
sudo rails myproj
Test that it runs with /srv/myproj/script/server and pointed our browser at http://hostname:3000/. Use 'hostname' instead of the 'fqdn' because we're still testing. Now we need to configure Apache+Passenger with Chef. From our local chef-repo, we have a site-cookbook, myproj.
cat ~/chef-repo/site-cookbooks/myproj/recipes/default.rb
include_recipe "rails"
include_recipe "passenger"
web_app "myproj" do
docroot "/srv/myproj/public"
template "myproj.conf.erb"
server_name node[:fqdn]
server_aliases [node[:hostname], "myproj"]
rails_env "production"
end
Now we need the Apache vhost template, myproj.conf.erb, which is, for example:
cat ~/chef-repo/site-cookbooks/myproj/templates/default/myproj.conf.erb
<VirtualHost *:80>
ServerName <%= @params[:server_name] %>
ServerAlias <% @params[:server_aliases].each do |a| %><%= "#{a}" %> <% end %>
DocumentRoot <%= @params[:docroot] %>
RailsBaseURI /
RailsEnv <%= @params[:rails_env] %>
RailsAllowModRewrite on
PassengerMaxPoolSize <%= @node[:rails][:max_pool_size] %>
<Directory <%= @params[:docroot] %>>
Options FollowSymLinks
AllowOverride None
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>
After running rake install[1], Chef is ready! Add the myproj recipe to the node in the chef-server webui, and run the client:
sudo chef-client
[… copious output from chef configuring everything snipped …]
Then, point the web browser at http://hostname/ and the Rails app is available! (note lack of port :3000). Or, if you've updated your DNS settings, you can go to http://fqdn/.
So how does this work? Quite simply, the web_app define copies the template via Chef's template resource. It then calls apache_site to enable the site in the Apache configuration. Because definitions in Chef don't prototype all the parameters (none by default, in fact), you can pass any arbitrary parameters you want to use. Then, in the web_app define, these are copied to the template via the variables attribute:
variables :params => params
Each param in the example for myproj above is available as @param[:parameter_name], as seen in the template.
The web_app definition can be used for other web application frameworks as well. Just pass parameters to web_app, and you can use them in your template. For more information about this, see README.rdoc in the Apache cookbook.
[1] This assumes you have a Rakefile with an install task that will put your cookbooks and site-cookbooks into a location for your server to use.