Build a basic Docker stack on Digital Ocean

As I'm getting more and more familiar with NodeJS and Docker, I'd like to Dockerize the few Webapps that run on this server so I can avoid to maintain different stacks.

I use Digital Ocean virtual hosting and I'm pretty happy with it.

Docker is straigtforward enough when it comes to run some containers for testing or development purposes but when you need to deal with High Availability or auto-scaling, it could become a real pain in the ass to configure a CoreOS cluster with all the layers that comes with it.
You'd need to setup fleet, a reverse proxy like vulcand and deal with etcd, etc. So much for a single machine but if you want to do it, start by reading this article.

Instead, I will simply use Docker on a single dropplet with a reverse proxy.

Setting up the dropplet

I'm used to Centos distros and I wanted build my stack on it but after a few tries, I could not manage to have Docker running properly on Centos 7.1. I tried with version 1.8.2 and 1.9.1, go figure...

I didn't give up and oriented myself to the pre-packaged Ubuntu 14.04 + Docker 1.9.1 dropplet. After a basic few tests (that were failing on Centos), I chose this dropplet to build my stack on. Furthermore, it really felt faster!

Create a new dropplet and when you come to choose an image, go in One-click Apps and pick Docker 1.9.1 on 14.04.

Finish to configure your dropplet, launch it and SSH to it.

Docker

Docker is already installed and running:

# docker version
Client:
 Version:      1.9.1
 API version:  1.21
 Go version:   go1.4.2
 Git commit:   a34a1d5
 Built:        Fri Nov 20 13:12:04 UTC 2015
 OS/Arch:      linux/amd64

Server:
 Version:      1.9.1
 API version:  1.21
 Go version:   go1.4.2
 Git commit:   a34a1d5
 Built:        Fri Nov 20 13:12:04 UTC 2015
 OS/Arch:      linux/amd64

Test it

For testing purposes, I will run my mirror HTTP server container:

# docker pull eexit/mirror-http-server
# docker run --rm -itp 80:80 eexit/mirror-http-server

From your host, make a GET request on the dropplet IP (I use HTTPie):

$ http {dropplet_ip}
HTTP/1.1 200 OK
Connection: keep-alive
Content-Length: 0
Date: Thu, 03 Dec 2015 13:00:07 GMT
Server: nginx/1.9.6
X-Powered-By: Express

Good, the mirror server responded. Next step.

Reverse proxy

Nothing too crazy, I could just install a Web server and manually configure it to act as a reverse proxy but let's face it: do you really want to update your proxy configuration every time you manipulate your container? Hell no!

The idea is to find a service that is simple to use and could act as a dynamic Docker container proxy without needing to change the proxy settings everytime you start/stop/restart your container.

For this, I quickly looked on Internet and found a reverse proxy that bundles a Nginx server as a Docker container. Awesome!

Let's go:

# docker pull jwilder/nginx-proxy
# docker run -dp 80:80 \
--volume=/var/run/docker.sock:/tmp/docker.sock:ro \
--name=nginx-proxy \
--restart=always \
jwilder/nginx-proxy

That's it, you have now a reverse proxy that can't wait to proxify other containers.

If you don't have a domain name that you could point to your dropplet, you can add - let's say - mirror.dev in your /etc/hosts file and mapping it to your dropplet IP.

If you request the domain, you should get this:

$ http mirror.dev
HTTP/1.1 503 Service Temporarily Unavailable
Connection: keep-alive
Content-Length: 212
Content-Type: text/html
Date: Fri, 04 Dec 2015 00:31:34 GMT
Server: nginx/1.9.6

<html>
<head><title>503 Service Temporarily Unavailable</title></head>
<body bgcolor="white">
<center><h1>503 Service Temporarily Unavailable</h1></center>
<hr><center>nginx/1.9.6</center>
</body>
</html>

To have the mirror-http-server container responding to mirror.dev domain, start the container and set the VIRTUAL_HOST=mirror.dev environment variable:

# docker run -d \
--restart=always \
-e VIRTUAL_HOST=mirror.dev \
--name=mirror-http-server \
eexit/mirror-http-server

Note: you don't need to specify the published port, the proxy will automatically use the container exposed port to map the requests to it.

You're all good now:

$ http mirror.dev
HTTP/1.1 200 OK
Connection: keep-alive
Content-Length: 0
Date: Fri, 04 Dec 2015 00:38:11 GMT
Server: nginx/1.9.6
X-Powered-By: Express

You can now run any Dockerized service on a single Digital Ocean dropplet and the only limitations are your dropplet size and the proxy configuration flexibility.

In a next article, I will tell you how to setup a private Docker Registry using Amazon S3.
Have fun!