Skip to main content

Common docker-compose recipes

Development

Key points for docker-compose in development:

  • Provide a database image
  • Use webpack-dev-server for the client
  • Use nodemon for the server
  • Run the migrations on starting the server container
  • Run seed scripts on starting the server container so that you save time (instead of creating new items through the UI)
  • Provide default values for everything - you should be able to bring the app up with no environment variables
  • Mount folders that include your code changes as volumes. eg. changes to the app folder should trigger hot reloading in the client services and changes to the server folder should trigger nodemon in the server service

Common package.json for both client and server

Check the Dockerfile recipes for what Dockerfile-development could look like. If all dependencies are within the same package.json file, then we build an image with all the dependencies and reuse it for both the client and the server.

# docker-compose.yml

version: "3"

services:
client:
build:
context: .
dockerfile: ./Dockerfile-development
command: ["node_modules/.bin/coko-client-dev"]
ports:
- ${CLIENT_PORT:-4000}:${CLIENT_PORT:-4000}
environment:
- NODE_ENV=development
- CLIENT_PORT=${CLIENT_PORT:-4000}
- SERVER_PROTOCOL=http
- SERVER_HOST=localhost
- SERVER_PORT=${SERVER_PORT:-3OOO}
volumes:
- ./app:/home/node/app/app

server:
build:
context: .
dockerfile: ./Dockerfile-development
depends_on:
- db
entrypoint:
[
"node_modules/.bin/wait-for-it",
"db:5432",
"--",
"sh",
"scripts/docker/setupDevServer.sh",
]
command:
[
"node_modules/.bin/nodemon",
"startServer.js",
"--watch",
"server",
"--watch",
"config",
"--ext",
"js,graphql",
]
ports:
- ${SERVER_PORT:-3000}:${SERVER_PORT:-3000}
environment:
- NODE_ENV=development
- POSTGRES_HOST=db
- POSTGRES_PORT=5432
- POSTGRES_DB=${POSTGRES_DB:-pg_db}
- POSTGRES_USER=${POSTGRES_USER:-pg_user}
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-pg_pass}
- PUBSWEET_SECRET=${PUBSWEET_SECRET:-ps_secret}
- SERVER_PORT=${SERVER_PORT:-3000}
- CLIENT_PROTOCOL=${CLIENT_PROTOCOL:-http}
- CLIENT_HOST=${CLIENT_HOST:-0.0.0.0}
- CLIENT_PORT=${CLIENT_PORT:-4000}
volumes:
- ./config:/home/node/app/config
- ./server:/home/node/app/server

db:
image: postgres:10-alpine
ports:
- ${POSTGRES_PORT:-5432}:5432
environment:
- POSTGRES_DB=${POSTGRES_NAME:-pg_db}
- POSTGRES_USER=${POSTGRES_USER:-pg_user}
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD:-pg_pass}

Your entrypoint script for the server service could look something like this:

#!/bin/sh
set -x

# This is run through docker. Its CWD will be the root folder.

node_modules/.bin/pubsweet migrate

node scripts/setupAdminUser.js
node scripts/seedUsers.js
node scripts/seedManuscripts.js

exec "$@"

Production

Key points:

  • Serve a static bundle of the client with an image like nginx (see related Dockerfile recipe)
  • Do not provide default values for variables
  • Do not provide a database at all. It is up to the sysadmin to provide the environment variables to connect to a working db. (eg. self-hosted, a db deployment on AWS etc)
# docker-compose.production.yml

version: "3"

services:
client:
build:
context: .
dockerfile: ./Dockerfile-production-client
args:
- server_protocol=${SERVER_PROTOCOL}
- server_host=${SERVER_HOST}
- server_port=${SERVER_PORT}
ports:
- ${CLIENT_PORT}:80

server:
build:
context: .
dockerfile: ./Dockerfile-production-server
ports:
- ${SERVER_PORT}:${SERVER_PORT}
environment:
- NODE_ENV=production
- POSTGRES_HOST=${POSTGRES_HOST}
- POSTGRES_PORT=${POSTGRES_PORT}
- POSTGRES_DB=${POSTGRES_DB}
- POSTGRES_USER=${POSTGRES_USER}
- POSTGRES_PASSWORD=${POSTGRES_PASSWORD}
- PUBSWEET_SECRET=${PUBSWEET_SECRET}
- SERVER_PORT=${SERVER_PORT}
- CLIENT_PROTOCOL=${CLIENT_PROTOCOL}
- CLIENT_HOST=${CLIENT_HOST}
- CLIENT_PORT=${CLIENT_PORT}