Crane is a Docker orchestration tool similar to Docker Compose with extra features.
For example, it offers ultra-fast, dependency-free bind-mounts for Docker on Mac, with a speed boost of at least 10x!

Advanced Usage

Prefixing

By default, services, networks and volumes are prefixed with the project folder (the folder where the configuration file is located).

However, it is also possible to set a different prefix via the global CLI --prefix flag (or CRANE_PREFIX environment variable). The specified prefix is simply appended without any modification. A common use case for this feature is to launch a set of services in parallel, e.g. for CI builds.

Another option is to set a permanent prefix in the configuration itself. This can be done via the top-level setting prefix: "foo". It is also possible to disable prefixing altogether with prefix: false.

Hooks

In order to run certain commands before or after key lifecycle events of containers, hooks can be declared in the configuration. They are run synchronously on the host where Crane is installed, outside containers, via an exec call. They may interrupt the flow by returning a non-zero status. If shell features more advanced than basic variable expansion is required, you should explicitly spawn a shell to run the command in (sh -c 'ls *').

Hooks are declared at the top level of the configuration, under the hooks key. See YAML example below:

services:
  service1:
    image: busybox
    detach: true
    command: ["sleep", "50"]
  service2:
    image: busybox
    detach: true
    command: ["sleep", "50"]
  service3:
    image: busybox
    detach: true
    command: ["sleep", "50"]
groups:
  foo:
    - service1
    - service2
  bar:
    - service2
    - service3
hooks:
  foo:
    post-start: echo container from foo started
  bar:
    post-stop: echo container from bar stopped
  service3:
    post-stop: echo container service3 stopped

Hooks can be defined on a group level (foo, bar) so that they apply to all services within that group, or directly on a container (service3). At most one hook can be registered per container and per event. When more than one hook is found for a given container and a given event, the following rules apply:

  • Container-defined hooks have priority over group-defined ones, so in the example above, only "container service3 stopped" will be echoed when stopping service3.
  • A fatal error will be raised at startup when 2 group-inherited hooks conflict. This is not the case in the previous example; even though foo and bar both contain service2, the hooks they declare are disjoint.

The following hooks are currently available:

  • pre-build: Executed before building an image
  • post-build: Executed after building an image
  • pre-start: Executed before starting or running a container
  • post-start: Executed after starting or running a container
  • pre-stop: Executed before stopping, killing or removing a running container
  • post-stop: Executed after stopping, killing or removing a running container

Every hook will have the name of the container for which this hook runs available as the environment variable CRANE_HOOKED_CONTAINER.

A typical example for a hook is waiting for some service to become available:

until `docker exec postgres-build psql -c 'select now()' 1>/dev/null 2>/dev/null`
  do echo Waiting for Postgres to start ...
  sleep 1
done

Parallelism

By default, Crane executes all commands sequentially. However, you might want to increase the level of parallelism for network-heavy operations, in order to cut down the overall run time. The --parallel/-l flag allows you to specify the level of parallelism for commands where network can be a bottleneck (namely provision and up). Passing a value of 0 effectively disable throttling, which means that all provisioning will be done in parallel.

Override image tag

By using a the --tag flag, it is possible to globally overrides image tags. If you specify --tag 2.0-rc2, an image name repo/app:1.0 is treated as repo/app:2.0-rc2. The CRANE_TAG environment variable can also be used to set the global tag.

Generate command

The generate command can transform (part of) the configuration based on a given template, making it easy to re-use the configuation with other tools. --template is a required flag, which should point to a Go template. By default, the output is printed to STDOUT. It can also be written to a file using the --output flag. If the given filename contains %s, then multiple files are written (one per container), substituting %s with the name of the container. For each container, an object of type ContainerInfo is passed to the template. If one file is generated for all targeted containers, a list of containers is located under the key Containers. This feature is experimental, which means it can be changed or even removed in every minor version update.

YAML alias/merge

YAML gives you some advanced features like alias and merge. They allow you to easily avoid duplicated code in your crane.yml file. As a example, imagine you need to define 2 different services: web and admin. They share almost the same configuration except the cmd declaration. And imagine you also need 2 instances for each one for using with a node balancer. Then you can declare them as simply:

services:
  web1: &web
    image: my-web-app
    link: ["db:db"]
    ...
    cmd: web
  web2: *web

  admin1: &admin { <<: *web, command: admin }
  admin2: *admin

As a summary, &anchor declares the anchor property, *alias is the alias indicator to simply copy the mapping it references, and <<: *merge includes all the mapping but let you override some keys.

Variable Expansion

Basic environment variable expansion (${FOO}, $FOO) is supported throughout the configuration, but advanced shell features such as command substitution ($(cat foo), `cat foo`) or advanced expansions (sp{el,il,al}l, foo*, ~/project, $((A * B)), ${PARAMETER#PATTERN}) are not as the Docker CLI is called directly. Use $$ for escaping a raw $.

A use case for this is to pass an environment variable from the CLI to the container "at runtime". If your configuration contains env: ["FOO=$FOO"], then FOO=hello crane run ubuntu bash has access to $FOO with the value of hello.

Copyright © 2020 Michael Sauter