Load Balance using Nginx

Other posts in this series:  Docker for developers

Let's take the example forward by load balancing the Node.js application.

Checkout the commit
$ cd nginx-and-nodejs-on-docker
$ git checkout 2e3a77e
.env File

The container names are changed:

docker-compose.yml

A new service called node_server_2 is created and the initial server is renamed to node_server_1.

web/server.js

This is an optional change. x-powered-by header that defaults to EXPRESS is disabled, and a new header X-Server is added to find out which container served the request.

Rebuild & Recreate containers

As usual, rebuild using docker-compose build followed by docker-compose up -d. Once the containers are up, you should be able to browse to http://192.168.99.100:81/users & http://192.168.99.100:82/users. Check the headers using Chrome inspect tool. Notice the X-Server header.

Add Nginx for load balancing

Nginx is super light and a great fit for reverse proxy scenarios like this one. If you are unfamiliar with Nginx, you may want to read my book Nginx: From Beginner to Pro. It is extremely simple and straightforward to use it with Docker.

Let's Dive in

Step 1: Change your directory and checkout the commit

$ cd nginx-and-nodejs-on-docker
$ git checkout bd9e91f

OR view the differences online.

Review the following files:

.env file

It now contains the information about NGINX

# Project Information
COMPOSE_PROJECT_NAME=node-nginx-seed
TAG=1.0

# Database Information
DATABASE_VERSION=mongo:3.4.8
DATABASE_CONTAINER_NAME=mongodb

# NodeJS Information
NODE_VERSION=node:6.11.3
NODE_CONTAINER_NAME_1=node_server_1
NODE_CONTAINER_NAME_2=node_server_2

# Nginx Information
NGINX_VERSION=nginx:1.13.3
NGINX_CONTAINER_NAME=nginx
docker-compose.yml file
version: '2'

services:
  database:
    image: ${DATABASE_VERSION}
    networks:
      - backend
    container_name: ${DATABASE_CONTAINER_NAME}
    volumes:
      - mongo-data:/data/db
      - ./docker/scripts:/scripts
      - ./docker/data:/data

  node_server_1:
    environment:
      - NODE=${NODE_CONTAINER_NAME_1}
    container_name: ${NODE_CONTAINER_NAME_1}
    image: ${NODE_VERSION}
    build:
      context: ./web
      dockerfile: node.dockerfile
    networks:
      - backend
    volumes:
      - ./web:/web
    depends_on:
      - database

  node_server_2:
    environment:
      - NODE=${NODE_CONTAINER_NAME_2}
    container_name: ${NODE_CONTAINER_NAME_2}
    image: ${NODE_VERSION}
    build:
      context: ./web
      dockerfile: node.dockerfile
    networks:
      - backend
    volumes:
      - ./web:/web
    depends_on:
      - database

  nginx:
    container_name: ${NGINX_CONTAINER_NAME}
    image: ${NGINX_VERSION}
    build:
      context: ./nginx
      dockerfile: nginx.dockerfile
    networks:
      - backend
    ports:
      - 80:80
    depends_on:
      - node_server_1
      - node_server_2
      - database

networks:
  backend:
    driver: bridge

volumes:
  mongo-data:

Notice the following changes:

  • ports key has been removed from individual node servers. This is to ensure that you can't reach the Node.js application directly. It avoids exposing your application to the end users.
  • depends_on key is added to imply dependencies between services.
    • docker-compose up starts services in dependency order.
    • docker-compose up SERVICE_NAME will automatically include SERVICE’s dependencies.
  • nginx service sets the context to the nginx directory and refers to the nginx.dockerfile for its image. It is connected to the backend network so that it is able to talk to the Node.js apps and maps external port 80 to the internal port 80.
nginx.dockerfile file
FROM nginx:1.13.3
MAINTAINER  rahul soni Soni < rahul soni@xxxx.com>

# Copy the Nginx configuration
COPY nginx.conf /etc/nginx/nginx.conf

# Expose website on port
EXPOSE 80

CMD ["nginx", "-g", "daemon off;"]

To avoid the container being shutdown, you tell Nginx to run as a foreground process and listen to the requests.

Rebuild & Recreate containers

Rebuild again using docker-compose build followed by docker-compose up -d. Once the containers are up, you should be able to browse to http://192.168.99.100/users. Check the headers using Chrome inspect tool. Notice the X-Server header. You should see it switch values between node_server_1 and node_server_2 if you refresh the page.

What next?

Well, stay tuned for upcoming articles. You may contact us at contact@attosol.com for your software and consultancy requirements.

© 2023, Attosol Private Ltd. All Rights Reserved.