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:
- We share Docker images all the time, but don’t have a good way of sharing the multi-service applications that use them
- 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:
- Make Compose-based applications shareable on Docker Hub and DTR
- 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.