Automatic Deployment via git 4
If you're using git to manage your homepage / blog / little web application, it is relatively easy to add automatic deployment functionality to simplify your work flow. Deploying a new version can then be a simple git push!
For this article, I'll use a Ruby on Rails application as the example. It should be easy enough to adapt this approach to other situations. You can even do more complex actions such as compiling a deployment archive as long as no manual intervention is required.
Let's assume you want to install your RoR application in /srv/web/my_app, and you have a bare git repository on the same server, in /srv/gitosis/repositories/my_app.git. All you need to do is create a clone from the repository in the deployment location, adjust the permissions of the log and tmp directories, configure the database connection if required and then you are done.
Applying updates with git in such an environment is already simple: develop and test on your local machine, eventually push your changes to the server and finally pull the changes into the deployment directory. For example:
client $ git commit ... client $ git push client $ ssh server server # cd /srv/web/my_app server # git pull server # touch tmp/restart.txt
This way, your local configuration is also protected by git and will be merged if possible (commit any local changes).
To further automate this, we can use the post-receive hook. In our example this is located at /srv/gitosis/repositories/my_app.git/hooks/post-receive. I have this hook call a script called update-rails.sh with the application name (my_app) as the parameter.
update-rails.sh looks like this:
#!/bin/sh
name=$1
if [ -z "$name" ] ; then
echo "need to give name of checkout dir on command line"
exit 1
fi
dir=/srv/web/$name
if [ ! -d $dir ] ; then
echo "the directory $dir does not exist"
exit 1
fi
cd $dir
env -i git pull
rake db:migrate
touch $dir/tmp/restart.txt
As you can see, this script will also run any required DB migrations.
Simple, isn't it?
Trackbacks
Use the following link to trackback from your own site:
http://blog.mobalean.com/trackbacks?article_id=6

I think this is great when you are in rapid development mode as it cuts down many steps to achieve just seeing your code running live.
However, I can imagine this can be dangerous if discipline for testing is not strict enough. One thing I did not see mentioned is whether or not your git repository is structured with branches?
If so then the master branch could be for development / testing with a merge into some production / deployment branch and your deployment server would only pull from this production / deployment branch. This extra road bump would be good as a lightweight check against deploying something that wasn’t meant to be.
Well, adding branches to the whole setup doesn’t change the way the automatic deployment works. You can use the same mechanism to update the testing server and production server if you want.
But having different branches will of course affect your work flow. I’m actually planning to setup such an environment for our stuff, and I’ll post my results here of course :-)
If you’ve not seen it, Capistrano takes not too much more set-up, but will pull from a git or svn repo.
My Rails deployments are along the lines of: * git push * cap deploy
One of the other advantages is you’re not overwriting your deployment every time, so if you need to rollback to an earlier deployment, you can without having to find out what version of your app is good and trying to pull that in.
Nathan,
I agree with you if we are talking about anything bigger than a simple blog or a web presence running on one server. Especially if you’re dealing with multiple servers, a more sophisticated approach is the way to go.
In my previous company, we were using cfengine to manage our server clusters - these days I would probably choose Capistrano as well.
Nevertheless, I think it is good practice to either tag everything that goes on production or to have a stable branch, so that there is never a question about what was running before an update.