Application Configuration

Introduction

There are many ways to provide configuration to containerized applications.

There is no "best way" — it depends on factors like:

  • configuration size,

  • mandatory and optional parameters,

  • scope of configuration (per container, per app, per customer, per site, etc),

  • frequency of changes in the configuration.

Command-line parameters

docker run jpetazzo/hamba 80 www1:80 www2:80
  • Configuration is provided through command-line parameters.

  • In the above example, the ENTRYPOINT is a script that will:

    • parse the parameters,

    • generate a configuration file,

    • start the actual service.

Command-line parameters pros and cons

  • Appropriate for mandatory parameters (without which the service cannot start).

  • Convenient for "toolbelt" services instanciated many times.

    (Because there is no extra step: just run it!)

  • Not great for dynamic configurations or bigger configurations.

    (These things are still possible, but more cumbersome.)

Environment variables

docker run -e ELASTICSEARCH_URL=https://es42:9201/ kibana
  • Configuration is provided through environment variables.

  • The environment variable can be used straight by the program,
    or by a script generating a configuration file.

Environment variables pros and cons

  • Appropriate for optional parameters (since the image can provide default values).

  • Also convenient for services instanciated many times.

    (It's as easy as command-line parameters.)

  • Great for services with lots of parameters, but you only want to specify a few.

    (And use default values for everything else.)

  • Ability to introspect possible parameters and their default values.

  • Not great for dynamic configurations.

Baked-in configuration

FROM prometheus
COPY prometheus.conf /etc
  • The configuration is added to the image.

  • The image may have a default configuration; the new configuration can:

    • replace the default configuration,

    • extend it (if the code can read multiple configuration files).

Baked-in configuration pros and cons

  • Allows arbitrary customization and complex configuration files.

  • Requires to write a configuration file. (Obviously!)

  • Requires to build an image to start the service.

  • Requires to rebuild the image to reconfigure the service.

  • Requires to rebuild the image to upgrade the service.

  • Configured images can be stored in registries.

    (Which is great, but requires a registry.)

Configuration volume

docker run -v appconfig:/etc/appconfig myapp
  • The configuration is stored in a volume.

  • The volume is attached to the container.

  • The image may have a default configuration.

    (But this results in a less "obvious" setup, that needs more documentation.)

Configuration volume pros and cons

  • Allows arbitrary customization and complex configuration files.

  • Requires to create a volume for each different configuration.

  • Services with identical configurations can use the same volume.

  • Doesn't require to build / rebuild an image when upgrading / reconfiguring.

  • Configuration can be generated or edited through another container.

Dynamic configuration volume

  • This is a powerful pattern for dynamic, complex configurations.

  • The configuration is stored in a volume.

  • The configuration is generated / updated by a special container.

  • The application container detects when the configuration is changed.

    (And automatically reloads the configuration when necessary.)

  • The configuration can be shared between multiple services if needed.

Dynamic configuration volume example

In a first terminal, start a load balancer with an initial configuration:

$ docker run --name loadbalancer jpetazzo/hamba \
  80 goo.gl:80

In another terminal, reconfigure that load balancer:

$ docker run --rm --volumes-from loadbalancer jpetazzo/hamba reconfigure \
  80 google.com:80

The configuration could also be updated through e.g. a REST API.

(The REST API being itself served from another container.)

Keeping secrets

Ideally, you should not put secrets (passwords, tokens...) in:

  • command-line or environment variables (anyone with Docker API access can get them),

  • images, especially stored in a registry.

Secrets management is better handled with an orchestrator (like Swarm or Kubernetes).

Orchestrators will allow to pass secrets in a "one-way" manner.

Managing secrets securely without an orchestrator can be contrived.

E.g.:

  • read the secret on stdin when the service starts,

  • pass the secret using an API endpoint.