views:

118

answers:

1

Problem

Your organization has many separate applications, some of which interact with each other (to form "systems"). You need to deploy these applications to separate environments to facilitate staged testing (for example, DEV, QA, UAT, PROD). A given application needs to be configured slightly differently in each environment (each environment has a separate database, for example). You want this re-configuration to be handled by some sort of automated mechanism so that your release managers don't have to manually configure each application every time it is deployed to a different environment.

Desired Features

I would like to design an organization-wide configuration solution with the following properties (ideally):

  • Supports "one click" deployments (only the environment needs to be specified, and no manual re-configuration during/after deployment should be necessary).
  • There should be a single "system of record" where a shared environment-dependent property is specified (such as a database connection string that is shared by many applications).
  • Supports re-configuration of deployed applications (in the event that an environment-specific property needs to change), ideally without requiring a re-deployment of the application.
  • Allows an application to be run on the same machine, but in different environments (run a PROD instance and a DEV instance simultaneously).

Possible Solutions

I see two basic directions in which a solution could go:

  1. Make all applications "environment aware". You would pass the environment name (DEV, QA, etc) at the command line to the app, and then the app is "smart" enough to figure out the environment-specific configuration values at run-time. The app could fetch the values from flat files deployed along with the app, or from a central configuration service.
  2. Applications are not "smart" as they are in #1, and simply fetch configuration by property name from config files deployed with the app. The values of these properties are injected into the config files at deploy-time by the install program/script. That install script takes the environment name and fetches all relevant configuration values from a central configuration service.

Question

How would/have you achieved a configuration solution that solves these problems and supports these desired features? Am I on target with the two possible solutions? Do you have a preference between those solutions? Also, please feel free to tell me that I'm thinking about the problem all wrong. Any feedback would be greatly appreciated.

A: 

We've all run into these kinds of things, particularly in large organizations. I think it's most important to manage your own expectations first, and also ask whether it's really necessary to tell every system and subsystem on a given box to "change to DEV mode" or "change to PROD mode". My personal recommendation is as follows:

  1. Make individual boxes responsible for a different stage - i.e. "this is a DEV box", and "this is a PROD box".

  2. Collect as much of the configuration that differs from box to box in one location, even if it requires soft links or scripts that collect the information to then print out.

    A. This way, you can easily "dump this box's configuration" in two places and see what differs, for example after a new deployment.

    B. You can also make configuration changes separate from software changes, at least to some degree, which is a good way to root out bugs that happen at release time.

  3. Then have everything base its configuration on something/somewhere that is not baked-in or hard-coded - just make sure to collect and document it in that one location. It almost doesn't matter what the mechanism is, which is a good thing, because some systems just don't want to be forced to use some mechanisms or others.

Sorry if this is too general an answer - the question was very general. I've worked in several large software-based organizations before, and this seemed to be the best approach. Using a standalone server as "one unit of deployment" is the most realistic scenario (though sometimes its expensive), since applications affect each other, and no matter how careful you are, you destabilize a whole system when you move any given gear or cog.

The alternative gets very complex very quickly. You need to start rewriting the applications that you have control over in order to have them accept a "DEV" switch, and you end up adding layers of kludge to the ones you don't have control over. Usually, the ones you don't have control over at least base their properties on something defined on a system-wide level, unless they are "calling the mothership for instructions".

It's easier to redirect people to a remote location and have them "use DEV" vs "use PROD" than it is to "make this machine run like DEV" vs "make this machine run like PROD". And if you're mixing things up, like having a DEV task run together on the same box as a PROD task, then that's not a realistic scenario anyways: I guarantee that eventually you will be granting illegal DEV-only access to somebody on PROD, and you'll have a DEV task wipe out a PROD database.

Hope this helps. Let me know if you'd like to discuss more specifics involved.

eruciform
@eruciform - thanks for the feedback. I understand your concerns, but I'm currently still leaning towards the "environment aware" approach, where we have our applications use a standard library to access configuration, and that library is able to fetch the environment-specific configuration at application start-up time. It would be possible with this approach (but not required) that we restrict a particular box to be "only DEV" or "only PROD" as you suggest (although we do have some use cases for running different applications in different envs on the same machine). I'll post my findings.
Stuart Lange
@stuart - you might consider a hybrid approach, then. if it is a small system and you have control over most pieces, you can implement what you're talking about. (though i'd still suggest trying to separate dev/prod by machine anyways.) you can always make one of the settings that is in the "standard location" a simple PHASE=DEV or PHASE=PROD environment variable or something. this would mean that you could continue to write the code as you desire, but it won't be as problematic in the future if you need to expand to the above. let me know the results.
eruciform