Load Balancing with Docker Compose and NGINX

Load Balancing with Docker Compose and NGINX

This post will demonstrate how we deployed our four simple Node.js backend applications into a load-balanced setup using Nginx. We utilized Docker images for this and connected all five containers via a Docker network.

Next, we’ll simplify the process by using Docker Compose, making everything shorter and easier. Let’s take a look at the Dockerfiles we created earlier:

1: The Dockerfile we created for our backend service:

FROM node:19-alpine  

WORKDIR /usr/src/app  

COPY package*.json ./  

RUN npm install  

COPY . .  

EXPOSE 5050  

CMD [ "node", "index.js" ]

2: Nginx web server we use for load balancing

FROM nginx:stable-alpine  

COPY nginx.conf /etc/nginx/conf.d/default.conf  

EXPOSE 80  

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

3: Configuration file for Nginx

upstream backend {  
    server backend-1:5050;  
    server backend-2:5050;  
    server backend-3:5050;  
    server backend-4:5050;  
}  

server {  
    listen 80;  

    include /etc/nginx/mime.types;  

    location / {  
        proxy_pass http://backend/;  
    }  
}

As shown in the configuration above, we define four backend servers under the upstream directive. Nginx, by default, uses the Round Robin load balancing algorithm. Since we haven’t specified any other algorithm, Nginx will use this one. These four servers will be on the same Docker network, so any request to localhost:80 will be forwarded to one of the four servers based on the Round Robin algorithm.

Now let’s create the docker-compose file to create the necessary containers.

version: '3'  
services:  
    backend_1:  
        build: ../server  
        environment:  
            - PORT=5050  
        networks:  
            - loadbalancing  
    backend_2:  
        build: ../server  
        environment:  
            - PORT=5050  
        networks:  
            - loadbalancing  
    backend_3:  
        build: ../server  
        environment:  
            - PORT=5050  
        networks:  
            - loadbalancing  
    backend_4:  
        build: ../server  
        environment:  
            - PORT=5050  
        networks:  
            - loadbalancing  

    nginx:  
        build: ../nginx  
        ports:  
            - "80:80"  
        networks:  
            - loadbalancing  
        depends_on:  
            - backend_1  
            - backend_2  
            - backend_3  
            - backend_4

networks:
    loadbalancing:

We’ve created four virtual backend servers as specified in the nginx.conf file, as seen in the Docker Compose file above. Let’s go over the parameters they take, in order:

  • build: This points to the project directory image mentioned earlier. The Docker Compose file is located in a folder named docker. From there, we access the Dockerfile in the server folder and use it to build the image.
  • environment: This is where we specify the environment variables needed by the container at runtime. In our example, we defined the PORT variable to specify the port on which the backend server will run. Our backend will be accessible on port 5050.
  • networks: This parameter creates a virtual network in Docker, allowing containers with the same network value to communicate with each other. Since the Nginx web server needs to reach the backend servers on port 80, we place all containers on the same network. We’ve named this network loadbalancing.

Now that all our operations are complete, we can set up our four virtual servers and one Nginx web server with the following command:

docker-compose up -d

After the command runs, the image on docker desktop will look like this:

Now when we send a request from localhost:80 to the web server, we will see a response from the servers.

So, is it possible to simplify the docker-compose file a bit more?

Yes, it’s possible to modify our Docker Compose file without creating a new service for each server we want to set up. Let’s take a look at the following example:

version: '3'  
services:  
    backend:  
        build: ../server  
        environment:  
            - PORT=5050  
        deploy:  
            replicas: 4  
        networks:  
            - loadbalancing  

    nginx:  
        build: ../nginx  
        container_name: nginx  
        ports:  
            - "80:80"  
        networks:  
            - loadbalancing  
        depends_on:  
            - backend  

networks:  
    loadbalancing:

In the Docker Compose file above, instead of creating a separate service for each backend server, we used the deploy key to streamline the process. By setting the replicas parameter, we specify how many instances of the relevant service should be running when the Compose file is executed. However, the process doesn’t end there. We’ll also need to make some adjustments to the nginx.conf file. The updated configuration file should look like this:

upstream backend {  
    server backend:5050;  
}  

server {  
    listen 80;  

    resolver 127.0.0.11 valid=5s;  

    include /etc/nginx/mime.types;  

    location / {  
        proxy_pass http://backend/;  
    }  
}

Once you’ve completed these operations, you can restart the services using the docker-compose up -d command and proceed with running your tests.

Share

Tags:

Comments

One response to “Load Balancing with Docker Compose and NGINX”

  1. Farhan Khan

    Great guide! The setup is clear and simple, and the use of Docker Compose and NGINX for load balancing is well-explained.

Leave a Reply

Your email address will not be published. Required fields are marked *