Creating a Docker Swarm at DigitalOcean using Terraform

Since version 1.12 of Docker, it has become fairly easy to create a Docker Swarm.

While many excellent blog articles deal very well with using the Swarm, they usually create them using VirtualBox. While this is simple enough to play and learn, it is not very satisfactory since that's not something we'd do in real.

I'm a long-time user of DigitalOcean and while I could have setup a Docker Swarm on this cloud manually, I wanted to automate the whole process, because, well, this is my job.

I chose to use Terraform because it is very easy to setup and to learn, and it has a decent support for the Digital Ocean API.

Warning - this is a success story, I manage to create a Docker Swarm on Digital Ocean, but I still have several concerns, see at the end of this article.

Enough talking, let's get this ready.

Prerequisites

Install Terraform on your machine.

First of all, you of course an account on Digital Ocean and you must create an API token. When done, export this token as an environment variable:

export TF_VAR_do_token="yourtoken"

Then, you need to create a SSH key pair for registration in Digital Ocean (the digitalocean_ssh_key provider does not allow to create them, only to register them):

ssh-keygen -t rsa -f ./do-key -N ""

This will create, in your current directory:

  • a do-key file for your private key
  • a do-key.pub file for your public key

Important: do not disclose your private key anywhere!

Terraform files

Get the Terraform files from GitHub:

git clone https://github.com/dcoraboeuf/blog-do-swarm.git

Configuration

The variables.tf defines all default values for the different configuration parameters. In particular:

  • swarm_master_count defines the number of master nodes and defaults to 1
  • swarm_agent_count defines the number of agent nodes and defaults to 2
  • do_agent_size defines the image size to use on Digital Ocean and defaults to 2 GB

Feel free to change any of those values.

Warning: Digital Ocean is a paying cloud platform so running this tutorial will generate some costs. The first hour is counted as a whole, so if you stay under one hour, the total cost for one master and two agents should be around 0.09 USD.

Create the swarm

In your current directory (where the SSH keys have been generated, just run:

terraform apply

After a few minutes, according to your settings, the following machines will have been generated on Digital Ocean:

You can see the IP of the Swarm master in the console:

or you can get it using:

terraform output swarm_ip

Note that this IP is a Floating IP which is used to point to the first master created.

Create your first service

Deploy your first service using the connect.sh utility script. I like the docker-swarm-visualizer for its simplicity:

./connect.sh docker service create \
  --name=visualizer \
  --publish=8081:8080/tcp \
  --constraint=node.role==manager \
  --mount=type=bind,src=/var/run/docker.sock,dst=/var/run/docker.sock \
  manomarks/visualizer

You can monitor the status of the deployment by running:

./connect.sh docker service ls

The deployment is finished when 1/1 appears in the REPLICAS column:

ID            NAME        REPLICAS  IMAGE                 COMMAND
9l1ot9hrcbyz  visualizer  1/1       manomarks/visualizer  

The visualiser is now available at http://ip:8081 where ip is the IP of your Docker Swarm as seen above.

On MacOS, just run:

open http://`terraform output -no-color swarm_ip`:8081

You should see:

Now, deploy another container, like my favourite application:

./connect.sh docker service create \
  --name=ontrack \
  --publish=8082:8080/tcp \
  nemerosa/ontrack:2.26.2

After a while, the service is deployed:

./connect.sh docker service ls
ID            NAME        REPLICAS  IMAGE                    COMMAND
9l1ot9hrcbyz  visualizer  1/1       manomarks/visualizer     
cjyou0d5mank  ontrack     1/1       nemerosa/ontrack:2.26.2  

and visible in the Swarm:

and the Ontrack application is available at:

open http://`terraform output -no-color swarm_ip`:8082

Connecting to the swarm

The Docker Swarm daemon is not made available directly in this scenario and we have to connect only through SSH. Hence the use of the connect.sh script, which does not do anything more than using the local key pair to run a remote SSH command:

#!/usr/bin/env bash
SWARM_IP=`terraform output -no-color swarm_ip`
SWARM_USER=`terraform output -no-color swarm_user`
ssh \
    -o StrictHostKeyChecking=no \
    -o NoHostAuthenticationForLocalhost=yes \
    -o UserKnownHostsFile=/dev/null \
    -i do-key \
    ${SWARM_USER}@${SWARM_IP} \
    $*

Docker Swarm mysteries

Et voilĂ ! You have a running Swarm.

Now, this is not, and by far, useable for a production-like story.

Why?

  • integration with a secret database, like Vault, should be done to protect the SSH keys and generated tokens
  • HTTPS proxies are missing
  • monitoring and logging are missing - see the excellent blogs here and here about putting this in place

And above all, there is no plan for persistent and resilient storage. For example, the Ontrack application deployed above needs a file system. If the container shuts down or the corresponding node fails, the container will be redeployed on another node by Swarm, but its data, local to the container or the node, will be gone. Not good!

Solutions like Flocker, Convoy or GlusterFS do exist, but so far, I had no success making them work with Digital Ocean Block Storage option.

Any help or suggestion is actually welcomed here ;)

All must disappear

When you're done with the tutorial, you can get rid of all the resources you've created on Digital Ocean by running:

terraform destroy

Type yes and all's gone!