Sure, I'd like to spend my days and nights writing Ruby and cap deploy ing it to success, but I have to face the facts.
I Still Have PHP Apps To Maintain.
I have no one to blame but myself. I wrote them. And I still work where they were written. There's no escape. After using Capistrano more than one time, you'll be completely spoiled.
But Capistrano is only for crazy Rails apps right? Nope. Its simply a platform for automation. It just so happens that deployment usually requires quite a bit of steps. Hmmm...lots of steps...automation... a match made in heaven. So sure, Capistrano was thought up with Rails in mind, but created openly so you're able to use it any way you'd like.
Capistrano's power is in its remoting features. You tell it what to do on that other server, and it does it. Beauty. So, if your PHP deployment process requires an svn export combined with a few other repetitive steps you have to do every time, Capistrano is here to help you too.
Without going into all the details of Capistrano (following the link will give you a nice overview), it uses a deploy script (recipe) to understand your deployment environment and required tasks.
Ok ok ok, Lets Get On With It
So, we have a PHP app that we need to deploy to server X. It needs to be sucked out of its repository, its version symlinked to a doc_root, and then a shared directory symlinked into the site. This is a pretty common deployment scenario, so lets go with this.
First, we need a Capistrano recipe. Currently, it can only be auto generated for a Rails app, so psst, here it is. Download this and create a directory at the root of your PHP app and name it config.
mkdir config
cd config
wget http://simplisticcomplexity.com/images/deploy.rb
Capistrano wants its recipe to be in the config directory, so do as it likes. Now lets open it up and make it work with us. Once again, a complete description of the Capistrano recipe file is bit out of scope for this little post, so please read up.
We'll edit all the normal items
set :application, "php_app" set :repository, "http://code.phpdevelopers.com/#{application}/trunk"
We only deploy to one server, so edit...
role :web, "phpsite.com"
Now you need to add the directory you want to deploy to. Add..
set :deploy_to, "/home/www/#{application}"
Capistrano defaults to checkout when pulling from subversion. I prefer an export, if you do too, then add..
set :checkout, "export"
Ok, so if you're familiar with Capistrano, you know exactly what we did. If you're not, the most important thing to know is that Capistrano is going to suck your code from the repository defined, do everything it's told to do in /home/www/php_app on your deployment server, phpsite.com.
Set'r Up
Believe it or not, we're half way done. Next, lets let Capistrano get the directory we just defined ready for its magic.
cap setup
If you look on your deployment server, you should see 2 directories that were just created.
drwxrwxr-x 2 user group 4096 Aug 16 01:48 releases
drwxr-sr-x 4 user group 4096 Aug 16 01:48 shared
WOW! We're already saving time! releases is where your app will be sucked down to. Capistrano exports your PHP app into a directory named after the current date/time. Each version you deploy will be kept in this directory. Shared is where you can keep files like uploaded assets or images that aren't kept in your repository, but need to be around every time you export from subversion. If your users upload files all day long, and you redeploy your PHP app from subversion, all your uploaded files will be gone. So we keep those in here.
Here's the deployment rub. Every time you deploy, you have to go symlink these directories from your /shared directory, into your current version of your PHP app. And a small bit of math can calculate the complexity when you start adding 2,3, or 6 asset folders. Yuck.
That's where Capistrano helps ya out.
Capistrano, Take Me Away
Ok, so our deploy directory is set up and ready to get our files. Now we need to tell Capistrano exactly what to do when we deploy. Get it? Recipe...
Define a new task called deploy
desc "This will deploy the app" task :deploy do end
Inside the block we'll just tell Capistrano exactly what it needs to do in order to deploy our app.
desc "This will deploy the app" task :deploy do run "svn --quiet #{checkout} #{repository} #{release_path}" run "ln -nfs #{release_path} #{current_path}" run "ln -nfs #{shared_path}/photos #{current_path}/photos" end
Ok, lets walk through exactly what this does. First, Capistrano uses subversion to suck your app out of the repository and into the releases directory. That releases_path is just a nice convenient variable for /home/www/php_site/releases/200608162012. Next, it will create a current symlink to that version of your app in the releases directory. Then we told it to symlink the directory photos from shared into the current version of the application.
And since you're hosting a PHP app with Apache (a 99% guess), there's no need to restart any servers. You're done. You're new version will be deployed safely and linked. The IMPORTANT thing to note, is that your new doc_root for your site will be /home/www/php_app/current.
Deploy!
Now, all ya gotta do to redeploy your site is...
cap deploy
Capistrano will go on to do everything you told it to do, on your deployment server. When its done, your directory should look like this...
lrwxrwxrwx 1 user group 42 2006-08-16 01:32 current -> /home/www/php_site_/releases/200608162012
drwxrwxr-x 4 user group 4096 2006-08-16 01:31 releases
drwxr-xr-x 4 user group 4096 2006-06-24 02:08 shared
And there you have it. Automated PHP deployment, with one simple command. Peering inside the current directory, you'll see where the photos directory has been symlinked into it.
The moral is, Capistrano isn't just for Rails deployment. Its powerful remote execution can be exploited to do anything you want. While our Rails apps get a lot for free when it comes to recipes, creating your own isn't complicated. Especially if its replacing repetitive tasks you've done over and over and over and over and over again.
You'll see the payoff the minute you get this set up. Especially on a Friday night at 5:30p when you're walking out the door. And its not just for Rails!
Popularity: 64% [?]




About
Mmm, Del.icio.us
Excellent! I've heard rumors of people using Capistrano to deploy non-Rails apps, but this is the first write-up I've seen. Thanks for putting this together.
Thanks for the article, it's just the motivation I needed to get capistrano managing my php projects.
Note that capistrano allows you to define before_TASKNAME or after_TASKNAME tasks.
Also note that deploy delegates to the update_code and symlink tasks.
Considering those two facts, you could define your own after_update_code to add the additional symlinks and not worry about redefining the deploy task.
eg.
task :after_update_code, :roles => [:app, :db, :web] do run <<-CMD ln -nfs #{shared_path}/static_content/private #{release_path}/private && ln -nfs #{shared_path}/static_content/images #{release_path}/public/images CMD endAlso, the file at http://www.simplisticcomplexity.com/files/destroy.rb is returning 404
Umm, the file should be deploy.rb not destroy.rb. (The example in the code says 'destroy.rb', as Lee points out.)
M.T.
Whooops. That file got lost in the great 0.5 > 0.6 Mephisto upgrade.
Its all fixed now.
I tried the same thing in June, so I do not know whether it works with newer versions of capistrano.
The only things different to your approach were:
- I did not place the deploy.rb into 'config', but renamed it to 'capfile' and placed it into the project's root dir. So if you do not want to create a 'config' dir...
- I did not redefine the deploy task, but those, that would not work in my PHP app:
* migrate
* restart
* spinner
For me they are defined as:
desc "Preventing migrate."
task :migrate do
puts
puts "Preventing migrate."
puts
end
desc "Preventing restart."
task :restart do
puts
puts "Preventing restart."
puts
end
desc "Preventing spinner."
task :spinner do
puts
puts "Preventing spinner."
puts
end
Of course one could insert other code there (for example my rails-like migrations for php).
I played with it today and it is a nice tool. Thanks for the info about php projects, it was the kick I needed to really look into it.
Great writeup!
This ought to be obvious, but... make sure you have svn installed on your target machine. If not capistrano will quietly fallback to cvs and then fail.
Cheers,
Luke
Awesome - you just saved me a hell of a lot of time.
Thanks alot for the instructions. A great time-saver.
Thanks for your post! I have a PHP site and I've just used capistrano to deploy on my Debian Server!!
Great post, many thanks. It saved my day :)
One thing I would like to add:
If you create deploy task the way it's in the example, revisions.log is not created and you loose ability to rollback (and use few extra tasks).
Using predefined 'update_code' worked for my application, although it generated few errors for Rails specific path creation/linking (ugly, temporary solution).
Ideally you will roll out your own update_code task based on original from Capistrano gem (task in progress ;)
This is a very useful post. It was exactly what I was looking for. Just a note to others...I got stuck on a couple of places.
Before you run 'cap setup', make sure that you're not in the 'config' directory; cd to the parent of 'config'. Also, make sure that your target machine allows remote logins.
For the run "svn ..." command I actually had to put the full path to svn in order for it to work...so, put the path to the remote machine's svn. In my case on OS X it was /usr/local/bin/svn.
That's it.
Thanks, this is fantastic. I set up an svn post-commit hook to run deploy.rb whenever I commit to the repo. To do this, there are 3 steps:
1) create a file named post-commit in the hooks directory of your repository
2) give it something like the following:
cap -f /home/username/config/deploy.rb deploy
(note, the url really ought to be absolute, and svn will give you some useful variables such as the url of the repository that was committed to if you want to trick it out. Its worth taking a look at those tmpl files in your hook directory for examples)
3) put on a sombrero and get yourself a margarita, cause you never have to use FTP again.
Thanks again :)
What are you using as a solution for updating your database schema? Capistrano with Rails will use ActiveRecord::Migrations to allow you to modify your database schema as part of your deployment, an exceptionally useful thing. I would love to be able to do the same thing for my PHP web apps, but I can't find a similar tool for PHP...
Look into LiquiBase.
Thanks Jon,
Deployment is a bit of a chore and I was jealous of Capistrano and Rails folk until I read this :)
Seriously deployed a PHP web applicatoin with "capistrano." OF course, true ability would not be possible with out rails. This post takes it to the limit even better. I never blog about it without help. Respect.
a young php project can deploy php applications on a web server(linux/windows)
you can find it here -> http://code.google.com/p/fredistrano
The link to the sample deploy.rb seems to be broken again. Would you be able to fix?
Thanks.
Ahh, sorry. It got lost when I migrated this blog over recently. The deploy.rb link has been repaired. Thanks.
[...] had been a brief conversation about using capistrano with drupal and there are several blog posts (like this one) about using it with PHP. So today, tired of resolving folders full of uploaded files, I decided to [...]
hi...
wonderful...
After deploying everything by hand this looks awsome thanks !
Thanks a lot for this article. I am now able to deploy my cakephp code using capistrano :)
This is interesting, and I agree that this beats manual deployment hands down.
That said, I wonder if there's really any motivation for using a Ruby app to deploy PHP code, in preference to using Phing, which was designed for the job, and does it well.
I'm in the same situation as you, having to maintain both rails and php applications. Your write-up is great, I could follow it and deal with my own little specialties (mainly tunneled ssh for svn and having to install svn on the server first) without a hitch, thanks a million.
Hint hint: While you've updated the linked up deploy.rb (to http://simplisticcomplexity.com/images/deploy.rb), you forgot to update the wget code snippet 4 lines below.
I'm a little puzzled by the benefits of using Capistrano over shell scripts for deployment? Anyone care to comment?
I think there's roughly 3 reasons for Capistrano, and not all of them apply at all times.
1) Uniformity: As this is the-way-to-deploy for Rails apps, you might like to use the same set of commands for your PHP apps. Saves a lot of explaining when you're introducing a new team member to your tools.
2) You don't actually have to write your shell scripts. Helps when someone doesn't know much about the dark magic of that.
3) Maybe your scripts do that, too, but with Capistrano you can roll back and forth between deployed versions, just in case something went wrong.
Saying that, I haven't even had a proper look at Capistrano, so maybe there's something in there that makes it unique. I just find it very quick and comfortable to set up and use.