PHP Deployment: rsync

This is an article that is based off of a talk I did covering various deployment mechanisms.  The slides can be found at Slideshare

The first one that we're going to look at is rsync.  What rsync does is maintain synchronization between an individual machine and another master machine.  Updates are made by checking the differences between the files on the local machine and the files on the remote server and copying the changes over.  It's relatively easy to use.

The first thing you need to do is set up your server.  So say you have your application deployed on your staging server, or some kind of production mirror that holds the standard by which the production servers are going to be.  You will need to add the following lines to your /etc/rsyncd.conf file, which may or may not exist.

comment = Our Org
path = /var/www/application
list = yes
uid = nobody
gid = nobody

Set the path to the directory where your application resides.  Rsyncd runs using xinetd so you will need to edit your /etc/xinetd.d/rsync file by "disable = no" and restarting the xinetd service.

Then on the production machine, once you are ready to deploy your code run the following command

rsync -av --delete testing::shares /var/www/application

"testing" is the name of the server.  "shares" is the name of the, well, share. –av first sets it into verbose mode (so you can see what you're doing) and then uses the -a option, for archive.  Archiving will transfer symlinks, permissions, time stamps, user and group ownership and any device data, and will do so recursively.  It's really nice and easy.

There are a couple of drawbacks.  Rsync does not natively have the ability to run post deployment scripts.  You will need to run that your self.  Also, if you need to roll back any changes you will need to roll back the source server.  Rsync does not understand versioning.

But while those are limitations of rsync, there are ways around them.  Shawn Stratton emailed me after the webinar giving me a bit of (deserved) grief for not addressing the workarounds.  I agree with Shawn's remarks, but due to time and the fact that I had 3 other deployment mechanisms I needed to go through I had opted for a simpler explanation of rsync.  However, the email that Shawn wrote had a lot of really good details that I would like to share with you.  There is some conversational stuff that I have removed but here is Shawn's response to me.

Your rsync command used the r flag which does not preserve timestamps/permissions/etc but more importantly does not transfer symlinks which is a big part of a deployment process using rsync.  Let me show you a directory sample of how I mean that:

current -> releases/v1.0.1
next    -> releases/v1.0.2
prev    -> releases/v1.0.0a
maint  -> maintenance/

This setup allows me keep multiple versions of the application on the remote server (disk space is cheap,) which I can change by simply changing a symlink.  Primarily the process for deployment would be: 

  1. export/build a tag from your vcs/dvcs system
  2. rsync -az –delete from a deployment box (local machine, dev utility server, etc) to the production server/servers
  3. alter next symlink from current value (in my case if nothing is staged next points to maintenance)
  4. proceed to test at a staging level (Apache vhosts in my case are setup as staging = next, production = current, and previous is a vhost that only links to a entry in my host file)
  5. remove prev symlink, move current symlink to maint, move maint symlink to current (maintenance being optional along with the next 3 steps).
  6. rsync -az –delete from a deployment box (local machine, dev utility server, etc) to the production server/servers, which changes the symlink, at this point your website is in "Maintenance Mode."
  7. do a database backup
  8. clear caches
  9. make database changes.
  10. swap current and next, rsync up.

Granted, most of these steps for me are scripted out in bash script and in the past we had setup a build system to do all the work up to step 5. because we felt it was better if human hands handled the finalization of deployment.  But there are several problems doing a deployment using rsync like this fixes, first it allows for a fast transition using symlinks (deployment on a 3 node cluster of the symlinks takes < 1 second,) second it can ensure that multiple servers are in complete sync (nothing worse than one server being out of sync on one file and one file only or worse permissions be off on one server) and lastly I can roll back rapidly.  I generally use migrations but the database backup exists also because it creates a snapshot of the database just prior to release and I can tell you from experience that little code changes can adversely affect database entries in ways that are not easily repaired without a dump.

There you have it.  If you have any additional comments do leave them below and come back soon since I have 3 more deployment options I need to write up.

Leave a Reply

Your email address will not be published.