Deploying Isleward 2: The Dockering

2019-02-26

Last year roughly around this time I helped move Isleward from Heroku and set up the server infrastructure for it. A few months later I wrote about it.

A year later it’s time for another change and it’s a big one. Isleward is now running in Docker, making deployments and server maintenance much easier. It hasn’t been thoroughly stress tested and it’s only running on the test server for now, but it seems very promising.

Setting up and Maintaining the VMs

To provision and maintain the VMs, I am still using Ansible as it’s a great tool for this kind of job. You can read more about how Ansible works in the previous post. The playbook can still be found here.

As before, Ansible doesn’t do the actual docker container deployment, it only sets up the machine so it’s able to host those containers.

The number of roles used has been reduced as we don’t need to install as many things (like nodejs). Another big change is that the roles are not submoduled inside the playbook anymore but they’re pulled using ansible-galaxy.

Let’s go through the roles now:

isleward.users

This role is largely the same as before, except it sets up just one user, under which Docker runs. That user needs to have sudo privileges and has enabled passwordless sudo.

isleward.isleward

This role sets up misc stuff for Isleward and schedules an hourly database backup.

geerlingguy.docker

A role from geerlingguy that installs Docker and Docker Compose, sets up the user and does other neccessary docker-related stuff.

isleward.docker

This role just contains some config files, including a docker-compose.yml file to be templated by Ansible (meaning variables will be inserted into the configs).

isleward.sshd

Largely unchanged from before, this role secures sshd by changing the default port, disables ssh with passwords (public key authentication only) and disables ssh for the root user.


On the official servers, the isleward.docker role is slightly different as it contains some sensitive data related to discord channel notifications (more on that later), certbot/https configuration and a container enhanced with all the closed Isleward content (more on that also later).

Deploying the Isleward Container

Deploying Isleward itself is actually now less involved than it used to be and consists of two parts:

Docker Compose

The docker-compose.yml file defines the whole application stack and how each container depends on others. It also allows us to easily spin up the whole stack just by running docker-compose up.

nginx

A simple webserver that exposes the standard http ports. This is here primarily so we can easily use https (see below). If we just wanted the server to run on the standard http port 80, we could configure it and just rely on express server.

isleward

This is the container that runs the game server. To persist data, it uses a docker volume. By default this will be the public version of Isleward, but on the main servers (play.isleward.com and ptr.isleward.com), it is extended with additional closed source content.

ouroboros

This genius piece of software ensures that specified containers are always up to date by periodically checking for new versions and updating the containers. This makes our deployment process very smooth and easy to use even compared to the previous solution using stagecoach. In the private docker-compose.yml, it is also configured to send a notification to Discord.


There’s also one container that’s only configured in the private version of the docker-compose.yml and that’s certbot

certbot

The Certbot container makes using and renewing Let’s Encrypt’s SSL certificates a breeze. To make it easily work with our nginx container, I followed Nginx and Let’s Encrypt with Docker in Less Than 5 Minutes (credit where credit’s due).

Gitlab CI

This part is purely private, for the official Isleward servers, but I’ll try to describe it the best I can. The deployment process is actually triggered using Gitlab CI, that builds the private version of the container.

This trigger could be automatic but currently it’s manual so there’s more control over the deploy process.

Here’s what the (redacted) .gitlab-ci.yml looks like:

image: docker:stable-git
services:
  - docker:dind

stages:
  - build

before_script:
  - docker login -u gitlab-ci-token -p $CI_JOB_TOKEN $CI_REGISTRY  

build-ptr:
  stage: build
  variables:
    IMAGE_TAG: $CI_REGISTRY_IMAGE:$CI_COMMIT_REF_SLUG
  script:
    - git clone [SOME PRIVATE MODS]
    - docker build -t $IMAGE_TAG .
    - wget "[API ENDPOINT]"
    - echo "Waiting for 30 seconds"
    - sleep 30s
    - docker push $IMAGE_TAG
  only:
    - web

This means that GitLab CI will:

  1. Clone some private mods (Sorry, I can’t give you the addresses even if you can’t access them :)
  2. Build the Docker container.
  3. Call an API endpoint that’ll display a message ingame and save all players.
  4. Wait for 30 seconds, this is just a courtesy wait, as ouroboros checks periodically every 60 seconds. We don’t want to display the message and boot players before they’ve had the chance to read it.
  5. Push the built Docker image into the project’s private registry.

Here’s what the private Dockerfile looks like, in case you’d want to replicate our setup:

# Base image on the public, master, isleward image
FROM registry.gitlab.com/isleward/isleward:master

# Copy private files into isleward's folder
COPY src /usr/src/isleward/src/

After the Docker container is built and pushed, ouroboros will pick it up and update it, and send a notification to the official Discord server. All just after a press of a single button in Gitlab.

The public Isleward repo actually has a similar .gitlab-ci.yml file, that also runs npm audit and eslint on merge requests and commits to master, before building the public version of the container on commits to master and tags.


I hope you liked this insight into the operational side of Isleward. If you have any questions or comments regarding this, feel free to reach out to me through the links in the footer. Thanks :)

~ Vildravn