Hello there
We use several services, built in several languages by different people, and have tried several approaches, with different success and pain points :
Build a Docker image by environment (ie your build script select the right config for the given environment)
- pros: only what you need in the image, and just run the image on the host
- cons: you have several images, you need to keep them in sync, you need to rebuild the each images as soon as some commit is done, and the config cannot be changed without building the image again (ie: PITA)
Build a single image, with a default config, and override some settings with environment variables at runtime
- pro: single image, you don't loose the container benefits, easy to setup
- cons: works well with a small simple of per-environment settings, scales not to nicely (makes environment configs complicated)
Build a single image with all the config for the various environments/flags and set the environment (or a given flag) from the environment variable
- pro: single image, easy to setup, works well even with large/complex configs
- cons: you need to rebuild the image for the smallest config change
- caveat: make sure the resource required in a given envrionment are not accessible in another environment. As an example, in the case of a web server, the config changes should change the root of the served files and configs, and any details for dev should not be accessible if the current setup is prod (and vice-versa). Do not have config-dev.json, config-prod.json in the same folder and set the name of the file in an environment variable, if the other file would still be accessible from the outside.
(The environment var could either set he root of the config paths, or set a few variables that will feed a template, like you could do super easily in scala/akka with application.conf and reference.conf)
Build a single image with a default config for all environment, from a template, and use some key/value agent to live-update the config/templates. We've used this to easily update NGINx configs without requiring any new image build or restart. Have a Consul agent running on each instance, and using consul template, we could easily set complex key/values on a given stack and automatically applies these update in the config files (regenerated on the fly in the image)
- pros: single image, the same everywhere. Works very well even with large/complex configs, no new image build required on config change, not even an image restart needed (unless you need to restart it to load the config)
- cons: more work to set it up, and requires a key/value store and a templating engine
These are the ones we tried, and there's many more variations. But that should help you getting started. If I were you, I would start trying to list my config management requirements:
- how often the config will change?
- how different the configs are from one stack to another?
- how much resources I can invest in managing this?
This would give you the pointers to select the most appropriate solution for your use-case.
Hope this helps,