lcp-compose Configuration

lcp-compose specific configuration are managed via invoke's Config object and stored under the root key lcp_compose in the Config object.

>> ctx.config.lcp_compose.work_dir # ==> ".lcp-compose/"

Overriding Configuration

lcp-compose will initialize configuration with sane defaults. Then it will look for the file $work_dir/config.yml to load the user configurations. Finally, it will inspect ENV VARS, and core-args to update the configuration..

A core argument is a common argument to any lcp-compose command:

lcp-compose --core-arg=value <task name> [<task args> ...]

# The passed arguments can then be retrieved within a task using the ctx object.
>> ctx.config.lcp_compose.core_arg # ==> "value"

Am ENV VAR configuration is a prefixed environment variable with it's name describing the config key that the value should be set to. Nested config keys are represented by underscores. The program will intelligently handle config keys that contain underscores, if any.

export CONFIG_LCP_COMPOSE_SERVICES_DNS_RESOLVCONF_PATH=/etc/resolv.conf

# Environment variable is mapped to the correct config path and is updated.
>> ctx.config.lcp_compose.services.dns.resolvconf_path # ==> "/etc/resolv.conf"

Example:

$ cat /tmp/compose/config.yml
lcp_compose:
  log_dir: /var/lcp-compose-logs/
  some_arg: some_val
  other_config:
    deeply_nested: "unchanged"

$ export CONFIG_LCP_COMPOSE_OTHER_CONFIG_DEEPLY_NESTED = "changed!"
$ lcp-compose --work-dir=/tmp/compose --some-arg=diff_val <task name> [<task args>..]

# Then access the config value via the context object:
>> ctx.config.lcp_compose.work_dir # ==> "/tmp/compose"
>> ctx.config.lcp_compose.log_dir # ==> "/var/lcp-compose-logs"
>> ctx.config.lcp_compose.some_arg # ==> "diff_val"
>> ctx.config.lcp_compose.other_config.deeply_nested # ==> "changed!"

Default configuration

See lcp_compose/compose_program.py#L26

Dynamic configuration

Any configuration can be overridden by modifying the context object inplace before invoking a task.

@task
def my_task(ctx):
    print ctx.config.lcp_compose.some_config

ctx = Context()
ctx.config.lcp_compose.some_config = "changed"
my_task(ctx) # => "changed"

See lcp_compose.helpers.configured_for for an example of dynamic context configuration.

Persisting configuration

Runtime configuration can be persisted to $work_dir/config.yml using lcp_compose.tasks.control.update_application_config. The method should be invoked with a pre-configured context object.

Example:

@task
def update_log_dir(ctx, new_path):
    ctx.config.lcp_compose.log_dir = new_path
    update_application_config(ctx) # Persists the configuration

Resetting configuration

Use lcp-compose clean --config

Configuration structure

# .lcp-compose/config.yml
lcp_compose:
  project_name: ordersservice    # project name resolved by the cwd
  work_dir: .lcp-compose         # work dir, set by core args  
  log_dir: /var/log/lcp-compose  # log dir, set by `init` tasks `--log-dir` flag 
  services: 
    security:
      url: http://security
      image_config: 'build: ../../security/'  ### TRAILING SLASHES ARE IMPORTANT!! ###
    platform_core:
      url: http://platform_core
      image_config: 'build: ../../platform_core/'
    gateway:
      url: http://gateway
      image_config: 'build: ../../gateway/'
    orders:
      url: http://172.18.0.1:5000
  compose_file: docker-compose.yml
  configurations_dir: configurations
  network_name: ordersservice_default

Configuration templating

All templates in the project assume that the full app configuration (lcp_compose.*) is received as context.

Assume a template:

LOG_DIR={{ log_dir }}
SECURITY_URL={{ services.security.url }}
BUY_URL={{ services.buy.url }}

If when used with the config.yml from the "Configuration structure" section, the result will be:

LOG_DIR=/var/log/lcp-compose
SECURITY_URL=http://security
BUY_URL=

PS: Note that the undefined var sevices.buy.url was returned as blank.

Service Definition

Services are defined in the services section of the config.yml file. It's a dictionary of service_name to service definitions. The purpose of the service definition is for lcp-compose to generate a corresponding docker-compose.yml file to be used with docker-compose.

Service definition is a dictionary of key-values.

Service Configuration

Configurations for lcp-compose managed services should be stored in the source code repositories for the individual services and copied into the service docker images.

Service's configurations value is a list of service configuration definitions. Here's a typical example of such config:

services:
    ...
    buy:
        ...
        configurations:
            - container_path: /content/lcp-compose.env.j2
              local_path: ./{{ configurations_dir }}/buy.env
              type: envfile

A configuration should have at least the following keys:

As an example, here's the definition for orders_service:

orders:
    ...
    configurations:
    - local_path: ./{{ configurations_dir }}/orders/
        volume_path: /config
        type: volume
        container_path: /content/configuration/lcp-compose/
    - local_path: ./{{ configurations_dir }}/orders.env
        type: envfile
        container_path: /content/lcp-compose.env.j2

The generated docker-compose file will be like:

version: '2'
services:
    ...
    orders:
        env_file: ./configurations/orders.env
        volumes:
            - /config:./configurations/orders/