Test driving the Docker Universal Control Plane

The Docker Universal Control Plane (UCP) is the commercial management solution for containerised applications inside a public cloud or on-premise. It is built on top of Docker Swarm. All UCP components are also running as containers.

This post will guide you through the installation of UCP and the integration of Interlock to dynamically configure HAProxy as a load balancer.


Docker provides an ucp tool to install the required components. The ucp tool runs via Docker and launches the appropriate containers.  It comes with subcommands such as “install”, “join” or “uninstall”. For an overview of all possible commands, use:

docker run --rm -it docker/ucp  --help

There is an interactive installation method which guides you through the process, launch it like this.

docker run --rm -it -v /var/run/docker.sock:/var/run/docker.sock --name ucp docker/ucp install -i --host-address

As we use vagrant for this setup `--host-address` is used to supply the installer with an accessible host address. In this case the static assigned IP address of the bridged interface ( To be able to manage your host containers from within a container you need to mount the Docker socket into the container.

The command will pull several images and will prompt for values it needs to complete the installation. When it completes, the command prompts you to login into the UCP GUI.

INFO[0015] Login as "admin"/(your admin password) to UCP at

To add a controller replica for high availability,  run the UCP tool on another server with the “--replica” flag. To achieve high availability you need at least 2 replicas.

docker run --rm -it -v /var/run/docker.sock:/var/run/docker.sock --name ucp docker/ucp join --replica -i --host-address

Now add an Engine node to the UCP cluster:

docker run --rm -it -v /var/run/docker.sock:/var/run/docker.sock --name ucp docker/ucp join -i --host-address

The UCP cluster is now up and running, let’s see what we can do with it.


We’ll deploy a container via the GUI therefore navigate to Containers and Deploy Container


Test driving the Docker Universal Control Plane


Fill out the form to start the container with the desired values


Test driving the Docker Universal Control Plane


Press “Run Container” on the right and the container will be started. This container is accessible on port 8080. If everything went well, you’ll see:

Test driving the Docker Universal Control Plane

You can test this by:

curl -i
(out)HTTP/1.1 200 OK
(out)X-Powered-By: Express
(out)Content-Type: text/html; charset=utf-8
(out)Content-Length: 12
(out)ETag: W/"c-8O9wgeFTmsAO9bdhtPsBsw"
(out)Date: Thu, 18 Feb 2016 11:04:35 GMT
(out)Connection: keep-alive
(out)Hello world

It will just return a simple “Hello world”.
The same can be achieved via the CLI. Connect to one of the nodes and run:

docker run -d -p 8081:8080 --name hello-world-cli-v1 muellermich/nodejs-hello

You’ll see the container running using:

docker ps 
(out)CONTAINER ID        IMAGE                      COMMAND                  CREATED             STATUS              PORTS                     NAMES
(out)13d9f6710e48        muellermich/nodejs-hello   "npm start"              3 seconds ago       Up 3 seconds>8080/tcp    hello-world-cli-v1
(out)6d69aa8e1a7d        muellermich/nodejs-hello   "npm start"              4 minutes ago       Up 4 minutes>8080/tcp    hello-world-gui-v1

Or the GUI:

Test driving the Docker Universal Control Plane

To verify that the application is running, access the container from outside by identifying the node and port that the container is running on.

Let's add a load balancer to the setup and service discovery so containers get automatically registered.

We will use HAProxy as the load balancer, also running in a container. For service discovery, we use Interlock from Docker employee Evan Hazlett. Interlock is described as “Dynamic, event-driven Docker plugin system using Swarm”. It makes use of the event stream of Docker Swarm  and the Docker API. This allows interlock to listen for container events like starting and stopping and take action based on them.

It uses the Docker API to fetch some attributes about the started or stopped containers, such as service name, hostname, host IP and port. Based on this information, a new HAProxy configuration is deployed.
We'll use docker-compose to launch interlock on the UCP Cluster. That way, interlock will also show up as new application in UCP. The compose file looks like this:

version: "2"
    image: ehazlett/interlock:latest
    command: "--swarm-url tcp:// --swarm-tls-ca-cert /data/ca.pem --swarm-tls-cert /data/cert.pem --swarm-tls-key /data/key.pem --plugin haproxy start"
    restart: always
      - "affinity:container==ucp-swarm-manager"
      - "80:80"
      - "/var/lib/docker/volumes/ucp-swarm-node-certs/_data:/data:ro"

On the master, we just have to issue:

docker-compose up -d

This will bring up a container with HAProxy running. You can access the stats page of HAProxy by accessing: ``

pic5Test driving the Docker Universal Control Plane

In the GUI under the application tab, you’ll now find the newly created application.

Test driving the Docker Universal Control Plane

Now let's start a new container from the CLI and register this container with our newly created HAProxy:

docker run -d -P -e INTERLOCK_DATA='{"hostname":"cli","domain":"ucp-ha.demo"}' --name hello-world-ha-cli muellermich/nodejs-hello

`-P` publishes all exposed ports inside the container to random ports on the host. We also pass an environment variable `-e INTERLOCK_DATA='{"hostname":"cli","domain":"ucp-ha.demo"}'` to tell interlock that this container will have the URL `http://cli.ucp-ha.demo/`.

The HAProxy config is automatically recreated, which you can see on the status page of HAProxy:

Test driving the Docker Universal Control Plane

The application inside the container we just launched can be access via the browser or via curl. It will just prompt “Hello World”:

Test driving the Docker Universal Control Plane

Below you can see how interlock works and recreates the HAProxy configuration.

Test driving the Docker Universal Control Plane

The same can be achieved via the GUI: You need to enter the container details like above, add the environment variable for interlock and select to automatically expose all ports.

Test driving the Docker Universal Control Plane

This again will generate the corresponding HAProxy config

Test driving the Docker Universal Control Plane

You can now easily scale your application up using the GUI. Navigate to your container and click on the sliders icon. Then navigate to the right top to “scale”. Enter the number you want to scale up e.g.: 10 and this will spin up 10 new containers and reconfigure HAProxy.

Test driving the Docker Universal Control Plane

Closing thoughts

The setup of a cluster for Docker containers is simple and straightforward. With the addition of interlock, it’s a good starting point for a container infrastructure.


But there is still work to do: Rescheduling is missing even though there is now basic support for it in Docker swarm 1.1 (experimental). I couldn’t find a way to convince UCP to start Docker Swarm in experimental mode, but I’m pretty sure this will be added in one of the next releases.

If you want to know more about rescheduling in Docker Swarm, please read the article Rescheduling containers on node failures with Docker Swarm 1.1 by Maximilian Schoefmann.

Leave your Comment