Supporting Multiple Environments

Supporting Multiple Environments(A guest post kindly written by EJ Ciramella)

One of the longest running debates I've watched in the Maven community over the years, is how to best support different configurations for different deployment environments (where "deployment environment" means a QA environment or staging environment - anything other than a local developer build). Some people argue simplicity over the complexity of some of the other options mentioned below.  Others don't have spare disk or time to burn building up complete and unique deployment artifacts.

In this first installment, I’m going to cover deploying my favorite deployment tool - Ant.

Packaging and Deployment

I tend to prefer using Ant as a deployment mechanism, forgoing perl or various shells because of the simplicity of the language.  Anyone can read and understand a well-written Ant script (Ant is inherently self-documenting).  One of the features I love is the "expandproperties" filterchain used in combination with a copy command.  If your resources are in directories that mirror where they will live in their final locations, then it's really easy to manage this with assembly descriptors (where the filtering can happen) and in the deploy script (if you'll play along and use Ant).  There are all kinds of little perks in using Ant, like being able to add a "-Dname=value" on the command line to override a known configuration setting, without having to rebuild your configuration.  Here's a very simple example of how I've configured applications in the past in a deploy script:

<copy todir="somelocation">
<fileset dir="templates" />
<filterchain>
<expandproperties/>
</filterchain>
</copy>

It is (or can be) as simple as that.

Assembly descriptors can be a bit trickier.  Initially, we used the stanzas to grab lists of wild-carded files, but this (obviously) won't fail if the descriptor can't find a file.  So we migrated (as much as we reasonably could) to using the individual file listings via the stanzas.  We also have three types of assembly descriptors: "dev" for local builds which has filtering set to true; "prod" for deployable artifacts which plucks files directly from the source tree and has filtering turned off; and a "common" component descriptor for grabbing everything that is uniform between dev and prod and requires no processing.

This approach has some pros and cons - obviously one major con is having to list out each file individually - but the giant upside is, if a file is missing because of relocation, the build will fail and you'll instantly be alerted.  Another downside is the fact that the assembly descriptors are essentially the same, with a difference in "outputDirectory" and filtering the only real differences.  One of the benefits is that you don't have to memorize where a template file lives in its final resting place.  A cursory glance at the resources directory gives you the exact target location.

Another implied concept here is deploying an exploded WAR/EAR (we don't need to digitally sign the artifacts as they are consumed internally).  While there may be some benefits to startup or load times of the archived file, but being able to slightly alter configuration and redeploy without repackaging is a greater benefit - why build a archive if you don't have to?

In the next installment, I’m going to cover the four cheap-fast ways I’ve seen discussed to generate configuration for your application.

(photo thanks to tacomabibleot)

DevOps New Zealand