With the approach listed in step two, it’s easiest to manage the actual values via property files, stacked up in a layered approach. Here’s what we came up with:
Deployment environment overlay procedure
In our deploy scripts (Ant based remember), the first in is the first out (and properties are immutable):
deploy environment application on a specific machine – Is there a unique application ID needed for clustering?
deploy environment application specific – What is <appId>’s memory requirements for this deployment environment?
deploy environment machine specific – Are there any specifications that need to be made for a given machine in a given environment?
deploy environment specific (environment specific) – What is the database server associated with this environment?
application – How many connections to your db server should this application be defaulted to?
defaults-deploy-env - non-dev – Where is bash located?
general – What is the port you use to connect to a database server?
In development, this process is reversed. In this custom coded (but VERY simple) Maven plugin, we have the following order of precedence:
command line – Want to quickly tweak a setting for a single build?
settings.xml – Are you testing a new version of the app server software?
pom properties - What compiler configuration are you using?
defaults - dev – Where is your app server software installed?
general – (see above)
There are slight variations on which configuration layers exist and should take precedence over another (the reader’s situation may call for more or less layers in general). All layers aside from the general and the defaults levels are optional on both fronts. By no means is this an exhaustive list or the explicit ordering of configuration. Just what worked best for us.
In the deployment environment example above, each deployment environment has its own subdirectory which allowed us to assign unique privileges per stack to prevent accidental configuration of various QA, staging and production environments. The content of this project is regenerated with each build of the configuration project. There are some inherit compromises with this approach (a change to a QA environment re-bundles an unchanged production configuration for example), but build cycles are extremely short and painless and each one is given a fully fledged build number in the mainline (project branches are assigned a non-unique snapshot identifier).
Each deployable unit may be shipped to production with different configuration project versions, with a complete history of the changes included in each revision (made available via Hudson). For security reasons, none of the sensitive staging and production passwords are maintained by development or release engineering. The configuration values for those things are stubbed out in the respective property files and an operations managed process properly injects the correct passwords into the proper configuration files.
In the final installment, I’m going to cover how to share this configuration between developers and your deployment environments.