Docker development to production workflow.

Docker development to production workflow.

Assume you are building a microservices system that comprises a Node JS server, Mongo database, and nginx for load balancing.

version: "3"
services:
  nginx:
    image: nginx:stable-alpine
    volumes:
      - ./nginx/default.conf:/etc/nginx/conf.d/default.conf:ro
    depends_on:
      - veezo

  veezo:
    build: .
    image: veestram.azurecr.io/levelupjs-backend_veezo

    environment:
      - PORT=4000 # this is the port our node app will be listening to in the docker container, so if we direct traffic here, our node app will be accessed
    depends_on:
      - mongo

  mongo:
    image: mongo:4.4.18

    volumes:
      - mongo-db:/data/db #here we are saying we want to persist this data. the path is where data is stored

volumes:
  mongo-db:

Your base docker-compose file might look something like the above.

Then you’d have a production docker-compose file as shown below.


version: "3"
services:
  nginx:

    ports:
      - "80:80"
      - "443:80"
  veezo:
    build:
      context: .
      args:
        NODE_ENV: production
    environment:
      - NODE_ENV=production

      - AZURE_CONNECTION_STRING=${AZURE_CONNECTION_STRING}
      - MONGO_USERNAME=${MONGO_USERNAME}
      - MONGO_PASSWORD=${MONGO_PASSWORD}
      - MONGO_IP=${MONGO_IP}
      - MONGO_PORT=${MONGO_PORT}
      - MONGO_DATABASE=${MONGO_DATABASE}
    command: node index.js
  mongo:
    environment:
      - MONGO_INITDB_ROOT_USERNAME=${MONGO_INITDB_ROOT_USERNAME}
      - MONGO_INITDB_ROOT_PASSWORD=${MONGO_INITDB_ROOT_PASSWORD}

One possible development to production workflow would be.

Pushing the code to GitHub, logging in to your production server, and pulling the code changes from Github, rebuilding the image.

However, this is not a good practice. Your production server shouldn’t waste any CPU and memory in building images. It's a bad practice to build images in your production server.

A better approach would be building the image on the local machine, pushing it to a container registry, and pulling the image into the production server. For that, we have to make some changes in our docker-compose.yml.

veezo:
    build: .
    image: veestram.azurecr.io/levelupjs-backend_veezo

Add the image property specifying the name of the image from your container registry. I have used the Azure container registry.

Here are the steps for building the image locally and pushing it to the registry.

docker-compose -f docker-compose.yml -f docker-compose.prod.yml build veezo
docker login veestram.azurecr.io #login to your registry
docker image tag image:tag veestram.azurecr.io/image:tag # tag the image with your account info
docker push veestram.azurecr.io/image:tag #push the image to the registry

After the image is pushed to the registry, log in to your production server and pull the image, then restart the container.


docker-compose -f docker-compose.yml -f docker-compose.prod.yml pull
 docker-compose -f docker-compose.yml -f docker-compose.prod.yml up -d --no-deps  veezo

That way, our server does not use up CPU and memory in building images.

Â