JTI - Production

Goals

In the previous exercises, you have learned how to develop your application locally. Now, it's time to take the next step and push the code to production. This includes:

  1. Setting up the infrastructure.
  2. Creating production versions of your Docker and Compose files.
  3. Setting up a pipeline for CI/CD that deploys the application on a staging and production server.

Prerequisites

By now, you should have an application with Docker and Docker Compose files in a repository at gitlab.lnu.se.

Ensure you watch or follow along in the previous exercise.

1. Setting up the infrastructure

For this application to work on a server in Open Stack we need to have Docker (runtime) and Nginx (reverse proxy) installed.

Here is our cloud-init installation script for Docker (docker-install-cloud-init.yaml).

This script has already been run on the servers you will be using, so you do not need to take any active steps with it. The information below is solely for your knowledge and understanding of how the infrastructure has been set up.

2. Docker and Docker Compose

Now, switch to the application project.

You have already created Docker and Docker Compose files. However, these are optimized for local development and not production. Now, you need to:

  • Create a Dockerfile for production
  • Create a Docker Compose structure for production and development

2.1 Dockerfile

Create a new Dockerfile named Dockerfile.production and make it production-ready.

The main differences between Dockerfile and Dockerfile.production:

  • npm ci --omit=dev to not install dev dependencies.

  • Start by: CMD ["node", "src/server.js"]

2.2 Docker Compose

Docker Compose files are composable. You can provide many files and they will all merge together where the last file has the highest priority. Because of this, create two new files:

  • docker-compose.development.yaml
  • docker-compose.production.yaml

In the original docker-compose file, include everything that is common in both development and production. This includes:

  • For the mongodb service
    • The container name
    • The image beeing useed
  • For the just-task-it service
    • The container name
    • build context
    • environment variables
    • depends on mongodb
    • port mapping

In the docker-compose-development.yaml file, specify:

  • volumes for development
  • use .env-file for evironment variables

In the docker-compose-production.yaml file, specify:

  • volume for MongoDB in production (no need for volumes for taskit).
  • NODE_ENV=production
  • That you want to use Dockerfile.production when building taskit.

Example project - Dockerized Web Application

Environment variables

For convenience, most of the environment variables are defined in the docker.compose.yaml file. However, for development purposes, we choose to specify some in the .env file. Later, these will be set in GitLab for staging and production environments.

See Example project - docker.compose.yaml for reference.

In our .env-file, we need to specify at a minumum:

Confirm production files

You can test your production files by executing them locally but instructing Docker to run them at your staging server.

Docker will look for the environment variable DOCKER_HOST. If found, Docker will execute its commands against that host. You should be able to:

MacOS and Linux

Windows

...where you need to change the IP to the IP of your staging server. In this case, you also need to add your private SSH key to the SSH agent using the ssh-add command.

Don't proceed until you get everything to work. (It's a slower process to troubleshoot using the a GitLab pipeline.)