How Do You Optimize a Website’s Performance That Is Running Nginx as a Load Balancer in a Docker Container?

Problem scenario
You want web page refreshes to happen more quickly for your website when a user clicks "Reload" in her web browser.  The website you manage is powered by Nginx configured as an HTTP load balancer (aka a reverse proxy).  This Nginx configuration is in a Docker container too. The rule you want is that clients' inbound connection requests from a specific IP address should be relayed to the same Nginx server every time that client reloads the web page in the web browser. You have an Nginx server configured as a reverse proxy (aka invisible landing page or pass-through router) distributing traffic to different Nginx web servers on the back-end.  You want to build an affinity based on specific IP addresses of the client workstations and relay them to the same Nginx page that serves the web pages.  This way from the front-end a user can click "refresh" or "reload" from her web browser and she will get the HTML pages from the same Nginx server each time she clicks that.  You know that client refreshes will happen much faster if this Nginx tuning is implemented. What do you do to achieve this improved performance?

Solution
You will want traffic to be routed based on the IP address of the client and not the round-robin technique.  You will not want to use the "route to server with fewest active connections" rule either (via the least_conn directive). 

If the client's machine changes its external IP address, this solution will not work. Normally during a web browsing session, a workstation's external IP address will not change.  When creating the Docker container that will serve as the HTTP load balancer, do not assign it a port-mapping, a subnet, nor an IP address.    

1.  Run a command like this to create the Docker container for the distributor (or HTTP load balancer) Nginx instance:

docker run --name docker-nginxbalancer --net=host nginx

2.  Use the command docker ps -a to find the Docker ID of the container created by the above command.

3.  Start the Docker container (e.g., with docker start abcd1234 where abcd1234 is the container ID).

4.  Enter the Docker container with a command like this:  docker exec -it docker-nginxbalancer bash

5.  Once inside the container, use this command to enable text-editing capabilities: apt-get update; apt-get -y install vim

6.  Modify the default.conf file.
a) vi /etc/nginx/conf.d/default.conf
b) Comment out in the server {} section these lines under the "location / {" section like this:

# root /usr/share/nginx/html;
# index index.html index.htm;

c)  Do not comment out the "location / {" stanza itself.  Do add a line under this stanza near the two commented-out lines (as seen above) with this content indented the same way as the original lines above were indented:

proxy_pass http://backend;

d) At the very bottom of the file, add these lines (but replace the IP addresses below with the Nginx web servers' FQDNs or their IP addresses directly):

upstream backend {
   ip_hash;
   server 10.10.0.1;
   server 10.10.0.2;
   server 10.10.0.3;
}

7.  Stop the Docker container and restart it. If it does not come back, are you sure you did not create the Docker container with a user-defined network and an IP address?  Using "docker run" and signifying an --ip flag and --network flag with a user-defined network can make the Docker container never start again if the ip_hash directive is used in the "upstream backend" block of the default.conf file.  Such configuration (with a user-defined network and ip address) is appropriate for Docker containers with regular Nginx web servers.  Nginx as a load balancer should not be in a Docker container with a user-defined network or an assigned IP address.

8.  Test it by going to the external IP address of the Docker server in a web browser.  Click refresh and everytime you should be getting the web page from the same Nginx server.  If you are used to Nginx in Docker containers on an EC-2 (AWS) instance, you should notice that the  refresh happens much faster!

Closing Tip
If you created the Docker container with Nginx with a subnet mask and IP address, it will not work as the HTTP balancer.  Such containers are fine for supporting Nginx web servers that can participate in an HTTP load balancer.  They are not acceptable as the distributor/balancer Nginx instance itself. 

FFR
If you want to need to troubleshoot problems with your Nginx load balancer, see this link.

Leave a comment

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