Making Compose Easier to Use with Application Packages

Docker Compose is wildly popular with developers for describing an application. In fact, there are more than 300,000 Docker Compose files on GitHub. With a set of services described in a docker-compose.yml file, it’s easy to launch a complex multi-service application (or a simple, single-service app) on Docker by running a single command. This ease of use makes Docker Compose perfect for development teams striving for a quick way of getting started with projects.

Over time Compose has evolved, adding lots of features which help when deploying those same applications to production environments, for example specifying a number of replicas, memory resource constraints or a custom syslog server. But those attributes can become specific to your own environment. There are a number of different strategies for trying to address this situation, but the most common is relying on copy and paste. It’s fairly common to maintain multiple Compose files for the same application running in different environments for example. This leads to two problems:

  1. We share Docker images all the time, but don’t have a good way of sharing the multi-service applications that use them
  2. It’s hard to collaborate between developers and operators around a Compose file. This waters down one of the key advantages of describing your applications in code – the opportunity for developers and operators to share a single description, and catch configuration issues before they hit production.

Introducing docker-app

One way to address this is by building a tool that is additive to Compose, to make it even easier to use for sharing and collaboration. Note that this is experimental and very much work-in-progress, but we’d like to get feedback and input from early adopters. This will:

  1. Make Compose-based applications shareable on Docker Hub and DTR
  2. Support a stronger separation of concerns between the application description and per-environment settings

The implementation consists of some additional metadata files and a small command line tool. Let’s show a quick example.

Take the following Compose file. It launches an HTTP server which prints the specified text when hit on the configured port.

version: '3.6'
services:
  hello:
    image: hashicorp/http-echo
    command: ["-text", "hello world"]
    ports:
      - 5678:5678

With docker-app installed let’s create an Application Package based on this Compose file:

$ docker-app init --single-file hello
$ ls
 docker-compose.yml
 hello.dockerapp

The application package is just a text file (or alternatively a directory), in this case called hello.dockerapp. This package contains three YAML documents

  • Some metadata
  • the Compose file
  • Some settings for the application

It should look like this:

# This section contains your application metadata.
version: 0.1.0
name: hello
description: ""
maintainers:
- name: yourusername
  email: ""
targets:
  swarm: true
  kubernetes: true

--

# This section contains the Compose file that describes your application services.
version: '3.6'
services:
  hello:
    image: hashicorp/http-echo
    command: ["-text", "hello world"]
    ports:
      - 5678:5678

--

# This section contains the default values for your application settings.
{}

 

Let’s edit the settings section (replace the {}) and add the following default values for our application:

port: 5678
text: hello development
version: latest

Then modify the Compose file section, adding in some variables:

version: '3.6'
services:
  hello:
    image: hashicorp/http-echo:${version}
    command: ["-text", "${text}"]
    ports:
      - ${port}:5678

Finally you can test everything is working, by rendering the Compose file with the provided default values.

$ docker-app render
version: "3.6"
services:
  hello:
    command:
    - -text
    - hello development
    image: hashicorp/http-echo:latest
    ports:
    - mode: ingress
      target: 5678
      published: 5678
      protocol: tcp

 

Note that the variables have been replaced by the settings values. You can then use that Compose file like any other. You could save it to disk or pipe it straight to docker stack or docker-compose to launch the application for instance.

$ docker-app render | docker-compose -f - up

This is where it gets interesting. We can override those settings at runtime, using the --set option. Let’s specify different option and run render again:

$ docker-app render --set version=0.2.3 --set port=4567 --set text="hello production"
version: "3.6"
services:
  hello:
    command:
    - -text
    - hello production
    image: hashicorp/http-echo:0.2.3
    ports:
    - mode: ingress
      target: 5678
      published: 4567
      protocol: tcp

Note the changes to the port and version in the resulting Compose file.

If you prefer you can create a standalone configuration file to store those settings. Let’s create `prod.yml` with the following contents:

version: 0.2.3
text: hello production
port: 4567

You can then show the Compose file with that configuration file like so:

$ docker-app render -f prod.yml

This makes it easy to have separate settings files for different environments, reducing the need to duplicate the entire Compose file.

We have a few more advanced examples as well in the repository if you’d like to move beyond just hello world.

You can implement something similar to the above using the environment variable support in Docker Compose, although you would need to write your own tooling to provide a nice user interface. With the above conventions in place however we can build more interesting things on top. For instance we can build quite interesting introspection tools like the one below and we have plans to move beyond simple variable substitution into more complex templating.

Inspecting and deploying Application Packages

docker-app doesn’t just provide a way of rendering a Compose file with different settings. It also comes with some useful utilities for interacting with them. For example if someone hands you a .dockerapp you can easily discover information about it, in particular finding out what settings are available at runtime without having to read any of the package code.

$ docker-app inspect
hello 0.1.0
Maintained by: gareth

A hello world example of a Docker application package.

Setting Default
------- -------
port    8080
text    hello world
version latest

Once you’re ready to deploy a version of the application you can do so with the deploy subcommand. This works in exactly the same way as the docker stack deploy command so should be familiar to many of you. For instance if you’re using Docker Desktop or Docker EE you could deploy the application to Kubernetes, while overriding some of the exposed settings.

$ docker-app deploy --set port=4567 --orchestrator=kubernetes

docker-app has more useful tools built in which you can find in the built-in help information, or by wait for a follow up blog post.

Status?

We’re releasing docker-app today as an experimental utility for all Docker users. We’re looking to iterate quickly based on early user feedback, and work with people in the Docker community who may want to contribute code or ideas. This is not intended to replace docker-compose or the docker stack commands today.

We have lots of ideas we want to explore with docker-app. We have support for sharing applications on Docker Hub already, but have lots of ideas for expanding that. Self-contained application installers are also an interesting avenue to explore, which could for instance support offline installation use cases. We have some support in the tool for more complex templating options though we’ve not yet made that available in the released version. The accompanying metadata also provides lots of opportunities for auto-generating various user interfaces: from installation and management tools to documentation and testing utilities. Do let us know what you would like to see.

Interested?

If you’re interested then head over to the GitHub repository at https://github.com/docker/app. You’ll find basic documentation and several examples, as well as instructions for downloading the latest release (for Windows, macOS or Linux) and the application source code. Please open issues in the repository with any questions, ideas, issues reports or feature requests.

If you’re a Docker EE customer and interested in managing Compose-based applications, or addressing workflow issues between developers and operators, please get in touch via your sales representative. docker-app works with Docker EE today and we’re actively looking at other interesting integration opportunities.

Learn more:

  • Register to access the beta when it’s available and download the current version of Docker Desktop for macOS or Windows 10 today, including the option to use Kubernetes.