Three releases last week – at this rate I’ll need to rename this blog series. For the most part, the releases were a non-event. Quite quick and painless. One thing about releasing software in these small increments – frequent releases get easier, not harder.
One thing that is constant about each release is change: change (obviously) to the application logic, change to the database, or change to the environment that we are deploying into. All of these changes should be scripted. The last thing that you want to have to remember during the pressure of deployment is a set of extra manual steps required for just this release.
To deploy the application, we have a simple shell script that downloads the latest pinned build from our automated integration server and deploys it into the app server. We use JetBrain’s TeamCity as our integration server to consistently build and package the latest code into a WAR. As for the app server, we’re running Glassfish, which is nicely scriptable – at least as far as Java applications servers go.
To deploy database changes, we’re using Bering, a lightweight, Rails-derived migration framework that uses Groovy as it’s scripting language. Deploying with this level of frequency, I consider a database migration framework to be absolutely essential — the last thing that you want to have to be dealing with right before a release is doing database diffs. A database migration framework makes database changes simple, automated and continuous. Database migrations are automatically applied to our test and production environments with each deploy. We also try to ensure that all database migrations are reversible (they have a corresponding “down” script) so that changes can be rolled back if necessary.
Deploying environment and configuration changes tends to be a bit more of a manual effort at this point. Glassfish configuration changes can be scripted and this is something that we are starting to take advantage of. These types of changes seem to happen infrequently enough that it still tends to be ad hoc. But anything like this can be easily forgotten during during a push. It would be ideal to have something similar to a migrations framework for applying configuration changes, and we should take a closer look at something like Capistrano for achieving this. We have all of our production configuration files in subversion (subject of a future post), so these can be pushed out using an ‘svn up‘. Most applications also require a restart or a kill signal to reload their configuration. As far as system installs, patches or upgrades are concerns, these also tend to be manual. There is support for OS-level patching from our host provider.
While I feel that our existing deployment process is quite simple and quick (as it needs to be to support weekly — or more frequent — releases), there is still ample room for improvement and further automation. I’ll continue to blog about enhancements to this process as we make them.
80% technical, 20% social change. This blog is dedicated to finding ways to sustainably release software more frequently.