[Docker] Going from Docker chaos to Docker-Compose

Over the past 5+ years or so, the primary public webserver for VHS has seen a bit of an unmanaged growth across all the services that it runs. I recently took on a project to bring a little bit more order into chaos.


For those who do not know about Docker, Docker is a security container technology that wraps a security around applications. This effectively isolates the application from the host as if they were a virtual machine, but without the overhead of a full virtual machine and instead separating the processes in the container from the host. (You can see the processes from the host, but you only see what’s exposed from within the container. The process can only access what’s exposed to the container and the world can only access what’s exposed from the container.)

To understand what I’ll be writing a little better, let me elaborate a little bit more on 2 important Docker concepts:

  • Containers are the actual running applications
  • Images are what gets executed

Think of images like a virtual OS distribution and containers of the running virtual OS. You can start containers from a single image and there is a rich ecosystem of people/companies that make images. The most widely used source for images is a service called Docker Hub.

Docker Compose is a solution to deploy sets of applications through configuration.


LetsEncrypt is an Internet initiative to provide free HTTPS/TLS certificate to the Internet at large.


For ease of understanding and writing, the primary public webserver has had a few iteration and now goes by the name of Santa. I’ll refer to it by that name.

The initial reason for migrating to Talk/Discourse was the fact that the previously hoster, who had graciously hosted both the public site and the mailing list for free, was sunsetting those systems and had asked us to migrate the VHS infrastructure off of their servers. The community settled on migrating from email to Discourse.

Talk/Discourse ran on a then relatively new technology called, Discourse was installed and VHS members migrated everything onto a general Docker infrastructure.

An integrated, monolithic Docker image was also created for the website.

Around that same time, VHS was also moving to a new location and this required more server infrastructure. (One of the new services was a service that allowed members to let themselves into the building using a pin.)

Over time, more services were added (isvhsopen, influxdb, grafana, api, some other test projects).

5 years later

As anyone who works in IT knows, temporary solutions are semi-permanent.

Letsencrypt also became a thing.

The challenges

The challenges that were now starting to become obstacles were:

  • Integrated/monolithic website image/container that integrated PHP and MySQL
  • Old version of PHP
  • Old version of MySQL
  • Common NGINX frontend for all web services, with hard links and custom configuration to host the website files
  • Software that could not be upgraded due to software dependencies
  • Plethora of custom scripts and hand built images and containers
  • Complex dependencies
  • Non-uniform configuration and deployment
  • Letsencrypt certificates were not easy to roll out

The solution

The solution was the following:

This let us upgrade PHP and MySQL easily and consequently, it also allowed us to upgrade other components.

Technically, we can’t hook Talk/Discourse into Docker Compose, but at least Discourse can be configured so nginx-proxy can automatically detect it and configure itself to provide proxy services for Talk.

There are 2 other containers that haven’t been migrated as of yet, but they’ll be handled in the future.

Docker Compose

In short, the repository has an “empty” docker-compose.yml file and includes the different service.yml definitions (following the docker-compose.yml format) from the services/ sub-directories through the COMPOSE_FILE directive in the .env file to provide a modular configuration.

Future services can easily be added by creating a new service directory/service.yml definition.

Then, upon updating the server repository, an admin would simply need to add the definition to the .env file and run docker-compose up -d to deploy the new service.

Admins can similarly test new services locally with a great amount of ease.


I’m really happy about the fact that this is now so much more cleaner and easier to manage. The custom scripts could really provide some challenges when certain services needed to be replace/upgraded, or when settings up new containers and trying to set up new certificates.