Skip to content

Production guide with Docker

Tuomas Airaksinen edited this page May 31, 2017 · 2 revisions

Production guide using Docker

Requirements

  • Machine that runs docker
  • Your own web server with SSL sertificates and associated domain name
  • Sendgrid email account for automatic sending emails. Your domain DNS settings need to be set up correctly for sendgrid too.
  • (optional) Sentry / sentry account

Docker environment file

Put environment variables in file serviceform-env.list:

PRODUCTION=1
# You can choose your credentials here. Initial database will be made according to these
# settings
POSTGRES_USER=serviceform
POSTGRES_DB=serviceform
POSTGRES_PASSWORD=django
# Django's secret key. Use generator such as this:
# http://www.miniwebtool.com/django-secret-key-generator/
SECRET_KEY=asdf
# API key to Sendgrid email sending service.
SENDGRID_API_KEY=asdf
# Sentry authentication. Leave this out if you don't have Sentry account.
RAVEN_DSN=https://asdf
# Your service will be at https://SERVICEFORM_HOST
SERVICEFORM_HOST=yourhost.com
ADMIN_NAME=Your Name
ADMIN_EMAIL=your.name@yourhost.com
SERVER_EMAIL=noreply@yourhost.com
# This code is used to generate unpredictable id, choose 5 random letters here
CODE_LETTERS=ABCDE
# Available: en, fi
LANGUAGE_CODE=fi
TIME_ZONE=Europe/Helsinki

For the following commands set first environment variable

export SERVICEFORM_ENV_FILE=/path_to/serviceform-env.list

External services

Docker commands to start external services needed by Serviceform

PostgreSQL:

docker run -d --name serviceform-db \
         --env-file $SERVICEFORM_ENV_FILE \
         --volume serviceform-db:/var/lib/postgresql \
         postgres:9.6.2

Redis:

docker run -d --name serviceform-redis \
         --volume serviceform-redis:/data \
         redis:3.2.8-alpine

Django services

Docker commands to start services bundled within serviceform docker image.

Build serviceform docker image first:

docker build -t tuomasairaksinen/serviceform:latest .

Or alternatively, pull it from the repository:

docker pull tuomasairaksinen/serviceform:latest

Initialization / upgrade.

This migrates database:

docker run --rm -u root \
        --link serviceform-db:db \
        --link serviceform-redis:redis \
        --env-file $SERVICEFORM_ENV_FILE \
        --volume serviceform-media:/code/media \
        --volume serviceform-celery-beat-store:/celery-beat-store \
        tuomasairaksinen/serviceform:latest upgrade

Command can be safely run multiple times.

Serviceform services

Celery:

docker run -d --name serviceform-celery \
         --link serviceform-db:db \
         --link serviceform-redis:redis \
         --env-file $SERVICEFORM_ENV_FILE \
         tuomasairaksinen/serviceform:latest celery

Celery-beat:

docker run -d --name serviceform-celery-beat \
        --link serviceform-db:db \
        --link serviceform-redis:redis \
        --volume serviceform-celery-beat-store:/store \
        --env-file $SERVICEFORM_ENV_FILE \
        tuomasairaksinen/serviceform:latest celery-beat

Task-processor:

docker run -d --name serviceform-task-processor \
         --link serviceform-db:db \
         --link serviceform-redis:redis \
         --env-file $SERVICEFORM_ENV_FILE \
         tuomasairaksinen/serviceform:latest task-processor

Send-emails:

docker run -d --name serviceform-send-emails \
        --link serviceform-db:db \
        --env-file $SERVICEFORM_ENV_FILE \
        tuomasairaksinen/serviceform:latest send-emails

Main app (HTTP server) x 2:

docker run -d --name serviceform-app-1 \
        --publish 8038:8080 \
        --link serviceform-db:db \
        --link serviceform-redis:redis \
        --env-file $SERVICEFORM_ENV_FILE \
        --volume serviceform-media:/code/media \
        tuomasairaksinen/serviceform:latest app

docker run -d --name serviceform-app-2 \
        --publish 8039:8080 \
        --link serviceform-db:db \
        --link serviceform-redis:redis \
        --env-file $SERVICEFORM_ENV_FILE \
        --volume serviceform-media:/code/media \
        tuomasairaksinen/serviceform:latest app

With this configuration serviceform will listen HTTP connections to ports 8038 and 8039. Now you need to set up your web server (https) to redirect connections to these ports:

upstream serviceformapp {
   server 127.0.0.1:8038;
   server 127.0.0.1:8039;
}

server{
    listen 80;
    charset utf-8;
    client_max_body_size 2M;
    server_name yourserver.com;
    location / {
        return 302 https://yourserver.com$request_uri;
    }
}

server {
    listen      443;
    ssl on;
    ssl_certificate  /path/to/fullchain.pem;
    ssl_certificate_key /path/to/privkey.pem;

    server_name yourserver.com;
    charset     utf-8;

    client_max_body_size 2M;


    location / {
      proxy_pass         http://serviceformapp;
      proxy_redirect     off;

      proxy_set_header   Host              $host;
      proxy_set_header   X-Forwarded-For   $proxy_add_x_forwarded_for;
      proxy_set_header   X-Forwarded-Proto $scheme;
    }
}

With two app instances running simultaneously it is easy to do zero-downtime upgrades by performing upgrade, restartin first 1 and then second instance, one at a time.

Upgrading system

Simple upgrade procedure:

docker pull tuomasairaksinen/serviceform:latest
docker stop serviceform-app-1 serviceform-send-emails serviceform-task-processor \
serviceform-celery-beat serviceform-celery

Run upgrade command. If that is fine, we can remove old containers:

docker rm serviceform-app-1 serviceform-send-emails serviceform-task-processor \
          serviceform-celery-beat serviceform-celery

Then run all docker run again all services.

Finally stop and remove app-2:

docker stop serviceform-app-2
docker rm serviceform-app-2

and then run it again with new image.

Shutting down and starting (system reboot procedures)

Shutting down:

docker stop serviceform-app-1 serviceform-app-2 serviceform-send-emails \
            serviceform-task-processor serviceform-celery-beat serviceform-celery \
            serviceform-redis serviceform-db

Starting again (set this into your system startup). Notice order.:

docker start serviceform-db serviceform-redis serviceform-celery serviceform-celery-beat \
             serviceform-task-processor serviceform-send-emails serviceform-app-1 \
             serviceform-app-2

Troubleshooting / shell access

To investigate problems these shell commands might prove usefull.

Django shell:

docker run --rm -it \
        --link serviceform-db:db \
        --link serviceform-redis:redis \
        --env-file $SERVICEFORM_ENV_FILE \
        tuomasairaksinen/serviceform:latest shell

Postgresql root shell:

docker exec -it -u postgres serviceform-db psql

Same with Django's credentials:

docker run --rm -it \
        --link serviceform-db:db \
        --link serviceform-redis:redis \
        --env-file $SERVICEFORM_ENV_FILE \
        tuomasairaksinen/serviceform:latest dbshell

Bash shell (to investigate/edit volumes etc.):

docker run --rm -it -u root \
        --link serviceform-db:db \
        --link serviceform-redis:redis \
        --volume serviceform-media:/code/media:ro \
        --env-file $SERVICEFORM_ENV_FILE \
        tuomasairaksinen/serviceform:latest bash

Dumping/loading production data as/from sql

Dump current data

Run:

docker exec -u postgres serviceform-db pg_dump serviceform > backup.sql

Load data from file.

First you need to destroy current database from PostgreSQL shell:

DROP DATABASE serviceform;
CREATE DATABASE serviceform;

Alternatively, you can stop database, remove volume:

docker stop serviceform-db
docker rm serviceform-db
docker volume rm serviceform-db

and then start database server (see external).

And then:

docker exec -i -u postgres serviceform-db psql serviceform < backup.sql
Clone this wiki locally