Whenever we deploy something we should make sure that the target environment is compatible with these changes. In this post I want to focus on making sure expected configuration settings are where they are supposed to be.

More or less every application deployed on a server needs some sort of configuration settings. You may call them settings, properties, adjustment or flags - but they all fulfill the same purpose: To configure details of an application.

Let’s take a database connection string as an example: If our application requires a database for storage, we don’t just have “the” database. There is a dedicated database for the production system, a dedicated database for the test system and most likely a dedicated databae on your local machine where you’re doing the development.

The exact location of that database is something you don’t want to put in your application code itself - you want to configure your application from the outside with a location.

We follow the twelve-factor app concepts which tells us to keep the configuration in the environment. The environment is something you configure in your runtime and that is passed to your application.

Within the application you request the value to use from the environment:

database_url = ENV['DATABASE_URL']
puts "Connecting to database at: #{database_url}"
connect(database_url)

How do you know which environment settings you need to provide to your application? How can you verify whether the runtime is setup correctly?

We have specified the Servicefile for that. A Servicefile is a machine-readable file stored inside the repository of a service that we want to deploy.

Let’s take a simple version of a Servicefile as example:

version: "2.0"
service-name: "case-cs-search"
runtime:
  env:
    - name: "ELASTICSEARCH_URL"
      description: "The URL of the Elasticsearch server to which the events will be written"
    - name: "JWT_PUBLIC_KEY"
      description: "The public key to decode incoming JWTs"
    - name: "JWT_VALIDATION_ALGORITHM"
      description: "The algorithm to be used to decode the JWTs"

Through the Servicefile the service itself specifies the following things:

  • It’s named case-cs-search (following our naming convention)
  • It expects three environment variables to be defined in the runtime: ELASTICSEARCH_URL, JWT_PUBLIC_KEY and JWT_VALIDATION_ALGORITHM.

When deploying a new application version from within the build process of our Continuous Integration we build the application artifact and automatically deploy the artifact to the test environment (in certain cases we also deploy to the production system but that’s not the scope of this post).

What we do as final step before actually sending the artifact to the runtime is to validate the runtime configuration.

The Servicefile is machine readable (YAML). It defines three environment variables. The build process can read the file and extract the relevant information (the required environment variables).

The build process also knows how to read the existing environment variables from the target runtime (in our case Heroku).

All that’s left to do is to compare these two: Check whether all the environment variables declared in the service file are already configured in the target environment.

If they are: everything is fine.

If they are not we stop the build process and get notified by the CI server so that we can prepare the target environment and make sure that when we have a deployment the required settings are in place.

All in all it’s a small step in our deployment process but one that helps us to fail early and to detect errors in our configuration early, giving us more time to focus on what we actually want to do: Deliver cool features.