Skip to content

Production Deployment

Bill Glover edited this page Feb 28, 2020 · 9 revisions

Overview

Hosting has been provided by Digital Ocean. We use GitHub Actions to execute workflows required to deploy to a staging and a production environment.

Hosting

A single host was created for both staging and production environments using the following command. You will need to authenticate using a personal access token to execute these.

doctl auth init --context=cb
doctl --context=cb compute droplet create backend --enable-backups --enable-monitoring --image=docker-18-04 --region=sfo2 --size=s-1vcpu-1gb --ssh-keys=26664376 --tag-names=v3

A new user has been created to run the applications. The password is long, complex and is not known. It should not be needed.

adduser cb
usermod -aG docker cb

The firewall needs to be opened up.

ufw allow http
ufw allow https

Application

Our Django application is packaged as a Docker image. It is deployed as a service using Docker Compose. It listens on port 8000 on the container network. This port is not exposed outside the container network as all inbound requests come from the web server. No volumes are mounted as all code and dependencies are contained within the image.

The table below outlines the environment variables that need to be set. Environment variables shows as **** are set through GitHub secrets.

Environment Variable Value Description
DATABASE_URL **** database connection string
EMAIL_HOST localhost email provider
DJANGO_SETTINGS_MODULE config.settings.production which Django settings to use
DJANGO_SECRET_KEY **** the Django secret key
DJANGO_ADMIN_URL admin the Django admin URL
`DJANGO_ALLOWED_HOSTS **** the Django allowed hosts
`DJANGO_SECURE_SSL_REDIRECT True force redirect to SSL

Reverse Proxy

A reverse proxy sits in front of the Django application. We are using Traefik. It is deployed as a service using Docker Compose and exposes port 80 and 443 on the host network. It listens to Docker for new services being deployed (app_staging and app_prod) and sets up inbound routes appropriately. It also handles the provision and renewal of LetsEncrypt certificates.

The reverse proxy needs to be deployed manually. Ensure the DO_AUTH_TOKEN environment variable is set and run the following command as the cb user.

docker-compose -f docker-compose-proxy.yaml up -d

You should now be good to trigger GitHub Actions.

Domains

Domains and DNS are handled by Digital Ocean. Records were created as shown below. The IP address used is the address of the droplet hosting the Django application.

  • api.codebuddies.org
  • api-staging.codebuddies.org
doctl --context=cb compute domain records create codebuddies.org --record-name=api --record-data=165.227.21.195 --record-type=A
doctl --context=cb compute domain records create codebuddies.org --record-name=api-staging --record-data=165.227.21.195 --record-type=A

Database

We are using a managed instance of PostgreSQL. We have created the following database type.

  • Memory: 1 GB RAM
  • Compute: 1vCPU
  • Disk: 10 GB
  • Failover: Primary only
  • Region: SFO2
  • DB: PostgreSQL 11

Pipeline

Environments

Workflows

  • Test - execute tests - triggered on all PRs
  • Stage - build and tag container image, push to staging - triggered on merge to master
  • Deploy - deploy existing container image to production - triggered on release

Secrets

A number of GitHub Secrets have been defined to allow the GitHub Actions Workflows to inject credentials where necessary. These are documented below, but secrets have been masked for obvious reasons.

Environment Variable Value Description
DO_AUTH_TOKEN **** DigitalOcean access token for DNS updates
DO_SSH_KEY **** DigitalOcean SSH key for copying files
DO_SSH_USER cb DigitalOcean system user
DO_SSH_PASSPHRASE **** Pass-phrase for SSH key
DO_PRODUCTION_HOST api.codebuddies.org DigitalOcean production droplet name
DO_PRODUCTION_SSH_PORT 22 SSH port for production droplet
DO_PRODUCTION_DB_URL **** Database connection string for production
PRODUCTION_ALLOWED_HOSTS api.codebuddies.org Django allowed hosts for production
PRODUCTION_DJANGO_SECRET_KEY **** Django secret key for production
DO_STAGING_HOST api-staging.codebuddies.org DigitalOcean staging droplet name
DO_STAGING_SSH_PORT 22 SSH port for staging droplet
DO_STAGING_DB_URL **** Database connection string for staging
STAGING_ALLOWED_HOSTS api-staging.codebuddies.org Django allowed hosts for staging
STAGING_DJANGO_SECRET_KEY **** Django secret key for staging

Edge Cases