CloudConfig
A library to modernise the way applications fetch configuration. Typically an application will use environment variables and settings files to store and retrieve configurations, but there are many issues with this approach. Often environment variables create a security risk and settings files hard code infrastructure dependencies into the code. Changing configuration settings will usually require redeploying large parts of the infrastructure and perhaps even need to go through the application deployment lifecycle.
A modern approach stores configuration remotely, often using key/value databases. Storing configurations in a single database, separately from the codebase reduces infrastructure dependency. Configuration updates can automatically sync with any application, without requiring redeployments. Security risk is greatly reduced, since configurations can be securely stored. Another goal with this approach is creating an environmentless codebase. The application no longer needs to know which environment it's running in, since all the configuration is handled by the infrastucture.
Another common problem is password rotation. A typical application will need to be restarted or even redeployed when the configuration settings change. CloudConfig can handle this elegantly, improving application uptime and resilience.
Installation
Install the gem and add to the application's Gemfile by executing:
$ bundle add cloud-config
If bundler is not being used to manage dependencies, install the gem by executing:
$ gem install cloud-config
Usage
CloudConfig can be configured to fetch keys from multiple providers. Since CloudConfig will need to know which provider has the correct key, all the keys will need to be preconfigured. Duplicate keys will be overriden with the latest provider. An example configuration may look like
CloudConfig.configure do
provider :aws_parameter_store, preload: { async: true } do
setting :db_url, cache: 60
setting :api_url
end
end
Fetch a setting with
url = CloudConfig.get(:api_url)
If caching has been configured, the cache can be reset using
url = CloudConfig.get(:api_url, reset_cache: true)
Configuration Options
CloudConfig.configure do
# Set the cache client
cache_client CloudConfig::Cache::InMemory.new
# Configure a provider. You can use the built-in providers (:in_memory, :aws_parameter_store, :yaml_file).
provider :in_memory do
end
# If you want to configure a custom provider, then please you will need to set the provider_class option.
provider :custom_provider, provider_class: CustomProvider do
end
# Set the preload option, to enable cache preloading for the provider
provider :in_memory, preload: true do
end
# Add parallelism for faster preloading
provider :in_memory, preload: { async: true } do
end
# Configure some keys for a provider
provider :in_memory do
setting :key1
setting :key2
setting :key3
end
# Configure the setting to be cacheable
provider :in_memory do
setting :key1, cache: 60 # 60 seconds
end
# If the datastore has configurable options
provider :aws_parameter_store do
setting :key1, with_decryption: true
end
end
Preloading
CloudConfig can preload all the keys configured for preload enabled providers. A cache client must also be configured, otherwise preloading won't do anything.
CloudConfig.configure do
cache_client CloudConfig::Cache::InMemory.new
provider :in_memory, preload: true do
setting :key1
end
end
Call preload to cache all the keys.
CloudConfig.preload
Custom Providers
CloudConfig comes equipped with a set of providers for fetching configuration from remote datastores. The limit set of providers will not be sufficient for most real world applications, so creating custom providers will be necessary. There is a very simple interface consisting of 3 methods necessary for creating a custom provider.
class CustomProvider
# Define initialize with a params argument.
def initialize(params = {}); end
# Define `get` for fetching keys from the remote datastore
def get(key, opts = {}); end
# Define `set` for storing keys in the remote datastore
def set(key, value); end
end
Specify the class when configuring the custom provider.
CloudConfig.configure do
provider :custom_provider, provider_class: CustomProvider do
end
end
Custom Cache
Defining a custom cache client will require an interface of 3 methods.
class CustomCache
# Define `key?` for checking whether the key exists in the cache client.
# This check allows nil values to be cached.
def key?(key); end
# Define `get` for fetching keys from the cache
def get(key); end
# Define `set` for storing keys in the cache
def set(key, value); end
end
Configure CloudConfig to use the cache in the usual way
CloudConfig.configure do
cache_client CustomCache.new
end
Connection Pooling
CloudConfig does not do any connection pooling. It is the responsibility of the application to handle connection pooling. For example, Rails handles its own connection pools, so CloudConfig will not attempt to interfere with the pool.
Examples
There are some example configurations in the examples folder. In the terminal, execute
$ examples/001_parameter_store.rb
These examples make use of AWS infrastructure, so make sure the AWS enviroment variables have been correctly configured.
$ export AWS_ACCESS_KEY_ID=
$ export AWS_SECRET_ACCESS_KEY=
$ export AWS_REGION=
Development
It's recommended to use Docker when working with this library. Assuming Docker is installed, run
$ docker-compose run config /bin/bash
Run bin/setup
to install dependencies. Then, run rake spec
to run the tests. You can also run bin/console
for an interactive prompt that will allow you to experiment.
To install this gem onto your local machine, run bundle exec rake install
. To release a new version, update the version number in version.rb
, and then run bundle exec rake release
, which will create a git tag for the version, push git commits and the created tag, and push the .gem
file to rubygems.org.
Documentation
Documentation is built using Yardoc. To build the docs, run
$ yardoc
To view the documentation, run
$ yard server -r
or using the docker service
$ docker-compose up yardoc
The documentation is viewable in the browser at http://localhost:8808
Contributing
Bug reports and pull requests are welcome on GitHub at https://github.com/hypernova2002/cloud-config. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the code of conduct.
License
The gem is available as open source under the terms of the MIT License.
Code of Conduct
Everyone interacting in the CloudConfig project's codebases, issue trackers, chat rooms and mailing lists is expected to follow the code of conduct.