One-Step Symlink Switch
When I deploy an application, which is almost invariably a PHP application, I like to put a whole new version of the code alongside the existing one that is in use, and when everything is in place, simply switch between the two. As an added bonus, if the sky falls in when the new version goes live, the previous version is uploaded and ready to be put back into service. In order to be able to do this, I have my document root pointing at a symlink, let’s say it is called “current”. (disclaimer: I have no knowledge of non-linux operating systems, this post is linux-specific)
When it is time to deploy, I place the new code onto the server, and create two new symlinks, one called “previous” which points to the same location as the “current” symlink does (bear with me) and one called “next” which points to the location of the new code. To deploy, all I need is this:
mv -fT next current
The f forces mv to overwrite the target if needs be, and the T directs mv to consider the second argument as a normal file, rather than as a directory to copy in to. The neat thing about doing it this way is that it happens in a single move, no weird results for people who manage to hit your site while you are typing the new symlink command or during the code updating. It is also just as simple to roll back from this, since you have a symlink pointing to the previously used code version.
I thought I’d share this snippet as it is a handy inclusion in deployment scripts/strategies. What are your tips for managing code deployment?
I use phing and generally have a staging directory on the server where I can verify the changes. Then I run ‘phing deploy’ when it’s ready to go. This handles changing the .htaccess file to point at a “website is down” page, runs the db migration script and pushes out the new code.
Definitely going to have to remember the symlink trick though.
this is a great tip. i normally just use Capistrano do the deployments for me, which does something similar.
I use capistrano because it’s easier for me, and I needed an excuse to learn ruby :).
This is very interesting and helpful tip. I just felt its quite similar to adding a new node to link list in C and moving pointer to next :)
Nice to see a post about this. :-) 100% of our deploys are done using symlinks.
We copy our releases into revision-specific folders (which are rev123, rev124, etc.).
Deploy is done using:
cd /software-revisions-folder
ln -sf rev124 current
To revert: ln -sf rev123 current
This means you might need to cleanup old releases from your production server though.
This is a convenient way to upgrade, and is certainly a good thing for development / testing environments. On a busy site there might be a slim risk this technique could be problematic. Although the file system is updated in an atomic transaction, a web browser could still read from both the old and new versions of the site.
For example an unfortunate user might request a JavaScript file from the “current” release, because an HTML document from the previous “current” release referenced it. If this is a concern, steps could be taken to make the JavaScript code backwards compatible.
Also a resource removed by the “next” release, may result in an HTTP 404 error. Whether that actually breaks anything depends entirely how your website works though.
i also move the current, so in case of non working result, i can easily move it back.
mv -fT current fallback;
mv -fT next current;
[geshi lang=sh ln=n]
Thanks for this tip, Lorna. It really helped us to come up with a release procedure that switches releases instantaneously.
It would be really useful to see an example of this technique in your post. This is what we came up with using the release date and an integer to label each release:
Move to the host directory:
$ cd /path/to/hosts
Check what the next release number should be:
$ ls -al releases
Prepare code from staging to be the next release:
$ rsync -a –exclude=.svn /path/to/hosts/staginghost/ /path/to/hosts/releases/example.com-YYYYMMDDVV
Sanity check that the new release is ready:
$ ls -al releases
Prepare a symlink to the next release:
$ ln -s releases/example.com-YYYYMMDDVV example.com_next
Switch symlinks to make new release live:
$ mv -fT example.com_next example.com
[/geshi]
disclaimer: I am not underestimating the universe’s ability to produce idiots, the point I’m trying to make is that I haven’t managed to make any deploy mistakes using this approach. Yet. Once upon a time, a long time ago, I went onto a conference sta
Thanks for this Lorna!
I played around with a couple different strategies, and I settled on doing the following:
Create “prev” and “next” directories that both contain code, with “www” being a symlink which Apache points to as the DocumentRoot
– Use the “next” folder:
[code]ln -fns next www[/code]
– Use the “prev” folder:
[code]ln -fns prev www[/code]
Works pretty well – thanks for the catalyst :)
So this is a great method for deploying, apart from one thing.. PHP’s opcache may catch you out. This happened to me in real life and as a temporary fix we had to restart Apache on deployment (I can’t remember what we did as a permanent fix..)
Anyway, please read more here if you’re using this symlink switching for deployment: http://codinghobo.com/opcache-and-symlink-based-deployments/