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
- All application specific configuration are nested under the key
lcp_compose
. - All relative paths are assumed to be relative to the
work_dir
# .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.
url
: required. What is the url for this service. e.g.,http://platform_core
orudp://dns
if the service is not a web service, leave it blank (''
).image_config
: required. This maps to eitherimage
orbuild
in thedocker-compose
file. e.g.,image: dev-docker.points.com/buy:latest
orbuild: ../..
. Keep in mind that relative path starts within.lcp-compose
folder.service_type
: eithercore
,pluggable
, orinfrastructure
.managed
: whether the service is managed bylcp-compose
or not.configurations
: defines how the service should be configured. See the next section for details.depends_on
: what other services does this service depend on. This maps directly to thedepends_on
key in the corresponding section for the service in thedocker-compose
file.docker_compose_config
: otherdocker-compose
configuration. Here you can put anything you want to appear in the corresponding section for the service in the finaldocker-compose
file.
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:
container_path
: Where is the config template stored in the container. In the above example, the config template is stored in the container at/content/lcp-compose.env.j2
.local_path
: Where the final config should reside. In the above example, it will be stored at.lcp-compose/configurations/buy.env
.type
: The type of this config file. There are two types of config so far:envfile
andvolume
.- When the type is
envfile
, thelocal_path
will be inserted asenv_file: FILE_PATH
in the corresponding service section of the finaldocker-compose
file. - When the type is
volume
, an extra keyvolume_path
is required. The corresponding service section of the generateddocker-compose
file will have avolumes
declaration of$volume_path:$local_path
.
- When the type is
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/