<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: marcelkatz</title>
    <description>The latest articles on DEV Community by marcelkatz (@marcelkatz).</description>
    <link>https://dev.to/marcelkatz</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F461728%2Fb3eaafc7-959c-4def-8b52-aec2c44ec1f5.JPG</url>
      <title>DEV Community: marcelkatz</title>
      <link>https://dev.to/marcelkatz</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/marcelkatz"/>
    <language>en</language>
    <item>
      <title>Node.js and Redis deployed in Docker containers, using Docker Compose - then load-balancing the Node.js servers with Nginx</title>
      <dc:creator>marcelkatz</dc:creator>
      <pubDate>Fri, 24 Dec 2021 21:35:16 +0000</pubDate>
      <link>https://dev.to/marcelkatz/nodejs-and-redis-deployed-in-docker-containers-using-docker-compose-then-load-balancing-the-nodejs-servers-with-nginx-4omc</link>
      <guid>https://dev.to/marcelkatz/nodejs-and-redis-deployed-in-docker-containers-using-docker-compose-then-load-balancing-the-nodejs-servers-with-nginx-4omc</guid>
      <description>&lt;p&gt;This article contains two main stages:&lt;br&gt;
&lt;strong&gt;(1) Containerizing a Node.js server application and a Redis database instance into two separate Docker containers, using Dockerfile and Docker Compose, and showing how these two applications communicate with each other.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;(2) Load-balancing the Node.js server, using a containerized Nginx reverse-proxy.&lt;/strong&gt; &lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Let’s start with Stage 1:&lt;br&gt;
(1) Containerizing a Node.js server application and a Redis instance into two separate Docker containers, using Dockerfile and Docker Compose, and showing how these two applications communicate with each other&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Starting with a simple &lt;strong&gt;Node.js server&lt;/strong&gt; application (we’ll call it “&lt;em&gt;test-webapp&lt;/em&gt;”) that responds to an &lt;em&gt;HTTP GET&lt;/em&gt; request by displaying the “numbers of visits”. The numbering scheme below (i.e. (1.1), (1.2), (1.3) etc.), matches the numbering in the diagram below:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3yp6moj945jli4n6vfl4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3yp6moj945jli4n6vfl4.png" alt="Figure 1.a – Schematic diagram of the components"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Figure 1.a - Schematic diagram of the components&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In "&lt;strong&gt;Figure 1.a - Schematic diagram of the components&lt;/strong&gt;" above we have the following components:&lt;br&gt;
(&lt;strong&gt;1.1&lt;/strong&gt;) "&lt;em&gt;Docker Container 1&lt;/em&gt;" - container running the &lt;strong&gt;Node.js server&lt;/strong&gt; called "&lt;em&gt;test-webapp&lt;/em&gt;" that communicates with the browser on the left. Each time we refresh the URL &lt;code&gt;localhost:80&lt;/code&gt; i.e. we send a &lt;code&gt;GET&lt;/code&gt;command to the &lt;strong&gt;Node.js server&lt;/strong&gt; "&lt;em&gt;test-webapp&lt;/em&gt;", the server code increments the number of visits, then saves this value into the &lt;strong&gt;&lt;em&gt;Redis&lt;/em&gt;&lt;/strong&gt; database instance that runs on "&lt;em&gt;Docker Container 2&lt;/em&gt;", and also displays the value back in the browser.&lt;/p&gt;

&lt;p&gt;(&lt;strong&gt;1.2&lt;/strong&gt;) “&lt;em&gt;Dockerfile&lt;/em&gt;” - defines and controls the &lt;strong&gt;Node.js server&lt;/strong&gt; process in “&lt;em&gt;Docker Container 1&lt;/em&gt;”. &lt;/p&gt;

&lt;p&gt;(&lt;strong&gt;1.3&lt;/strong&gt;, &lt;strong&gt;1.3.1&lt;/strong&gt;, &lt;strong&gt;1.3.2&lt;/strong&gt;) “&lt;em&gt;&lt;a href="https://github.com/marcelkatz/test-docker-nodejs-redis-nginx/blob/main/docker-compose.yml" rel="noopener noreferrer"&gt;docker-compose.yml&lt;/a&gt;&lt;/em&gt;” – the &lt;strong&gt;Docker Compose&lt;/strong&gt; config file defines and controls both “&lt;em&gt;Docker Container 1&lt;/em&gt;” and “&lt;em&gt;Docker Container 2&lt;/em&gt;”. “&lt;em&gt;Docker Container 1&lt;/em&gt;” runs the &lt;strong&gt;Node.js server&lt;/strong&gt; process “&lt;em&gt;test-webap_p”. “_Docker Container 2&lt;/em&gt;” runs the &lt;strong&gt;&lt;em&gt;Redis&lt;/em&gt;&lt;/strong&gt; database instance.&lt;/p&gt;

&lt;p&gt;(&lt;strong&gt;1.3.3&lt;/strong&gt;) &lt;strong&gt;Docker Compose&lt;/strong&gt; establishes by default a communication network between “&lt;em&gt;Docker Container 1&lt;/em&gt;” and “&lt;em&gt;Docker Container 2&lt;/em&gt;” which allow the &lt;strong&gt;Node.js server&lt;/strong&gt; process “&lt;em&gt;test-webapp&lt;/em&gt;” to communicate with the &lt;strong&gt;&lt;em&gt;Redis&lt;/em&gt;&lt;/strong&gt; database instance, and exchange between them the “number of visits to the app/web server” (&lt;code&gt;numVisits&lt;/code&gt;) value.&lt;/p&gt;

&lt;p&gt;(&lt;strong&gt;1.3.4&lt;/strong&gt;) &lt;strong&gt;Docker Compose&lt;/strong&gt; maps local hosting machine Port 80 to “&lt;em&gt;Docker Container 1&lt;/em&gt;” Port 5000. Port 5000 is the port on which the &lt;strong&gt;Node.js server&lt;/strong&gt; “&lt;em&gt;test-webapp&lt;/em&gt;” listens and reacts to the &lt;code&gt;GET&lt;/code&gt;commands sent by the browser.&lt;/p&gt;

&lt;p&gt;(&lt;strong&gt;1.4&lt;/strong&gt;) Connecting to the shell of “&lt;em&gt;Docker Container 2&lt;/em&gt;” and then to the client command line of the &lt;strong&gt;&lt;em&gt;Redis&lt;/em&gt;&lt;/strong&gt; database instance via “&lt;code&gt;redis-cli&lt;/code&gt;” we can see that the value of &lt;code&gt;numVisits&lt;/code&gt; (which represents the number of times the browser issued a &lt;code&gt;GET&lt;/code&gt;command to the &lt;strong&gt;Node.js server&lt;/strong&gt;) is in sync with the value displayed in the browser by the &lt;strong&gt;Node.js server&lt;/strong&gt; – thus showing that inter-process communication occurs between the processes “&lt;em&gt;test-webapp&lt;/em&gt;” in “&lt;em&gt;Docker Container 1&lt;/em&gt;” and the &lt;strong&gt;&lt;em&gt;Redis&lt;/em&gt;&lt;/strong&gt; process in “&lt;em&gt;Docker Container 2&lt;/em&gt;”.&lt;/p&gt;

&lt;p&gt;(&lt;strong&gt;1.5&lt;/strong&gt;) This step illustrates the &lt;code&gt;restart&lt;/code&gt; directive and capability in &lt;strong&gt;Docker Compose&lt;/strong&gt; (specified in config file “&lt;em&gt;docker-compose.yml&lt;/em&gt;”) – when connecting to the Linux shell of “&lt;em&gt;Docker Container 1&lt;/em&gt;”, we can &lt;code&gt;kill -9&lt;/code&gt; the &lt;strong&gt;Node.js server&lt;/strong&gt; process, but the &lt;strong&gt;Node.js server&lt;/strong&gt; process will be restarted automatically by &lt;strong&gt;Docker Compose&lt;/strong&gt; – illustrating the automatic recovery provided by &lt;strong&gt;Docker Compose&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;And now let’s describe the steps and the flow of this scenario. The numbering scheme in the description below (i.e. (1.1), (1.2), (1.3) etc.), matches the numbering in “&lt;strong&gt;Figure 1.a – Schematic diagram of the components&lt;/strong&gt;”.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;(1.1) File structure:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frm92ysovtnnq9azlunop.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Frm92ysovtnnq9azlunop.png" alt="Figure 1.b – File structure for Stage 1"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Figure 1.b – File structure for Stage 1&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Node.js files for process ‘test-webapp’:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The contents of directory “&lt;em&gt;test-webapp&lt;/em&gt;”, where the source code for the &lt;strong&gt;Node.js server&lt;/strong&gt; “&lt;em&gt;test-webapp&lt;/em&gt;” resides:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjqed4cw6m1mpm1upws9m.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fjqed4cw6m1mpm1upws9m.png" alt="Node.js files for process 'test-webapp'"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;(&lt;strong&gt;1.2&lt;/strong&gt;) The &lt;em&gt;Dockerfile _containerizes and controls the &lt;strong&gt;Node.js application&lt;/strong&gt; by downloading the “_node:alpine&lt;/em&gt;” image from &lt;a href="https://hub.docker.com/" rel="noopener noreferrer"&gt;Docker Hub&lt;/a&gt;, installing &lt;strong&gt;Node.js&lt;/strong&gt; on the container, copying to the container the &lt;a href="https://github.com/marcelkatz/test-docker-nodejs-redis-nginx/tree/main/test-webapp" rel="noopener noreferrer"&gt;source files&lt;/a&gt; – then launching the &lt;strong&gt;Node.js server&lt;/strong&gt; web app (see source code in file “&lt;a href="https://github.com/marcelkatz/test-docker-nodejs-redis-nginx/blob/main/test-webapp/server.js" rel="noopener noreferrer"&gt;&lt;em&gt;server.js&lt;/em&gt;&lt;/a&gt;”).&lt;/p&gt;

&lt;p&gt;(&lt;strong&gt;1.3&lt;/strong&gt;) Going one directory above, we see the "&lt;em&gt;&lt;a href="https://github.com/marcelkatz/test-docker-nodejs-redis-nginx/blob/main/docker-compose.yml" rel="noopener noreferrer"&gt;docker-compose.yml&lt;/a&gt;&lt;/em&gt;" file that organizes the containerization and sets up the architecture of all the components. (File &lt;br&gt;
“&lt;em&gt;&lt;a href="https://github.com/marcelkatz/test-docker-nodejs-redis-nginx/blob/main/docker-compose-nginx.yml" rel="noopener noreferrer"&gt;docker-composer-nginx.yml&lt;/a&gt;&lt;/em&gt;” will be presented and explained in &lt;strong&gt;Stage 2&lt;/strong&gt; of this article)&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftqtlkv6v7vams8x3xq9d.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftqtlkv6v7vams8x3xq9d.png" alt="'docker-compose.yml' file for process 'test-webapp'"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Purge all images and containers:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;We run command &lt;code&gt;docker system prune -a&lt;/code&gt; to clear all Docker images and containers and start with a clean slate.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;C:\test-docker\test-redis&amp;gt;docker system prune -a                                          
WARNING! This will remove:                                                                                                
- all stopped containers                                                                                                
- all networks not used by at least one container                                                                       
- all images without at least one container associated to them                                                          
- all build cache                                                                                                                                                                                                                             
Are you sure you want to continue? [y/N] y
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;(1.3) Build and run the 'test-webapp' image with Docker Compose&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Use command &lt;code&gt;docker-compose -f &amp;lt;config-filename&amp;gt; build&lt;/code&gt; to build containers and the applications that will be running in each container:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;C:\test-docker\test-redis&amp;gt;docker-compose -f docker-compose.yml build&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;See the results below of the built Docker image:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;C:\test-docker\test-redis&amp;gt;docker images                                                                                                                     
REPOSITORY               TAG       IMAGE ID       CREATED         SIZE                                                                                                                     
test-redis_test-webapp   latest    e8145bea0fec   4 minutes ago   175MB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Run the 'test-webapp' and 'redis' containers with 'docker-compose':&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Let’s launch both “&lt;em&gt;test-webapp&lt;/em&gt;” and “&lt;em&gt;redis&lt;/em&gt;” services, as described in config file &lt;br&gt;
“&lt;em&gt;&lt;a href="https://github.com/marcelkatz/test-docker-nodejs-redis-nginx/blob/main/docker-compose.yml" rel="noopener noreferrer"&gt;docker-compose.yml&lt;/a&gt;&lt;/em&gt;”, using the &lt;code&gt;docker-compose -f &amp;lt;config-filename&amp;gt; up&lt;/code&gt; command.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F66ukw6kmm4djhk2nzxsa.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F66ukw6kmm4djhk2nzxsa.PNG" alt="docker-compose -f docker-compose.yml up"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;We can see from the output above, that both the “&lt;em&gt;redis&lt;/em&gt;” container (“&lt;em&gt;test-redis_1&lt;/em&gt;” – corresponding to “&lt;em&gt;Docker Container 2&lt;/em&gt;” in &lt;strong&gt;Figure 1.a&lt;/strong&gt;) and the “&lt;em&gt;test-webapp&lt;/em&gt;” container (“&lt;em&gt;test-webapp_1&lt;/em&gt;” corresponding to “&lt;em&gt;Docker Container 1&lt;/em&gt;” in &lt;strong&gt;Figure 1.a&lt;/strong&gt;) are running and printing to stdout in the command line window where we launched &lt;strong&gt;Docker Compose&lt;/strong&gt; to run these two containers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;View the 'test-webapp' and 'redis' running containers:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;C:\test-docker\test-redis\test-webapp&amp;gt;docker ps                                                                                        
CONTAINER ID   IMAGE                    PORTS                
NAMES                                         
928b8b07415d   test-redis_test-webapp   0.0.0.0:80-&amp;gt;5000/tcp   test-redis_test-webapp_1                      
a8756127bff5   redis:alpine             6379/tcp               test-redis_test-redis_1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;(&lt;strong&gt;1.3.1&lt;/strong&gt;, &lt;strong&gt;1.3.2&lt;/strong&gt;) The two containers above match the containers “&lt;em&gt;Docker Container 1&lt;/em&gt;” and “&lt;em&gt;Docker Container 2&lt;/em&gt;” in the &lt;strong&gt;Figure 1.a&lt;/strong&gt; above. Note the “&lt;em&gt;CONTAINER ID&lt;/em&gt;” column whose values we will use below to perform operation on each individual running container. &lt;/p&gt;

&lt;p&gt;(&lt;strong&gt;1.3.4&lt;/strong&gt;) Port 5000 in the &lt;strong&gt;Node.js server&lt;/strong&gt; "&lt;em&gt;test-webapp&lt;/em&gt;" container is mapped to local (hosting) Port 80, so when one connects in the local (hosting) browser to URL &lt;strong&gt;&lt;a href="http://localhost:80" rel="noopener noreferrer"&gt;http://localhost:80&lt;/a&gt;&lt;/strong&gt;, for each refresh, the &lt;strong&gt;Node.js process&lt;/strong&gt; in the “&lt;em&gt;test-webapp&lt;/em&gt;” container increments the number of visits in variable &lt;code&gt;numVisits&lt;/code&gt; which is set and saved in the &lt;strong&gt;&lt;em&gt;Redis&lt;/em&gt;&lt;/strong&gt; in variable &lt;code&gt;numVisits&lt;/code&gt; -- and this value is also send back and displayed in the browser. &lt;/p&gt;

&lt;p&gt;“Docker-compose” sets-up by default a network with both “&lt;em&gt;test-webapp&lt;/em&gt;” container (“&lt;em&gt;Docker Container 1&lt;/em&gt;” in &lt;strong&gt;Figure 1.a&lt;/strong&gt;) and “&lt;em&gt;redis&lt;/em&gt;” container (“&lt;em&gt;Docker Container 2&lt;/em&gt;” in &lt;strong&gt;Figure 1.a&lt;/strong&gt;) within this network, and both containers are reachable by each other via this network. &lt;/p&gt;

&lt;p&gt;The local browser communicates with the &lt;strong&gt;Node.js server&lt;/strong&gt; container. When refreshing the connection in the browser, the server callback is invoked which responds to the browser with the updated number of visits.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feuscx0msi6am2kz9tk7j.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Feuscx0msi6am2kz9tk7j.png" alt="1.3.4 Browser - localhost - number of visits 8"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;(&lt;strong&gt;1.4&lt;/strong&gt;) We are using the &lt;code&gt;docker exec -it&lt;/code&gt; command that allows us to connect to a running container while the &lt;code&gt;-it&lt;/code&gt; option allows us to capture the stdin/stdout of that container. Then we specify the CONTAINER ID &lt;em&gt;a8756127bff5&lt;/em&gt; obtained from &lt;code&gt;docker ps&lt;/code&gt; command above, followed by the shell (&lt;strong&gt;&lt;em&gt;sh&lt;/em&gt;&lt;/strong&gt;) that we want to launch as we enter the container. &lt;/p&gt;

&lt;p&gt;&lt;code&gt;C:\test-redis\test-webapp&amp;gt;docker exec -it a8756127bff5 sh&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Then, once we are inside the container’s shell, we connect to the &lt;strong&gt;&lt;em&gt;Redis&lt;/em&gt;&lt;/strong&gt; database using the &lt;code&gt;redis-cli&lt;/code&gt; command. At the &lt;strong&gt;&lt;em&gt;Redis&lt;/em&gt;&lt;/strong&gt; prompt we use &lt;code&gt;get numVisits&lt;/code&gt; to obtain the value of the variable “&lt;strong&gt;numVisits&lt;/strong&gt;” inside “&lt;em&gt;redis&lt;/em&gt;”. We can see that the “&lt;em&gt;redis&lt;/em&gt;” instance communicates with the “&lt;em&gt;test-webapp&lt;/em&gt;” process in its respective container and the variable “&lt;em&gt;numVisits&lt;/em&gt;” in the &lt;strong&gt;&lt;em&gt;Redis&lt;/em&gt;&lt;/strong&gt; database instance is in sync with its value in the browser. In this case both have the value “&lt;strong&gt;8&lt;/strong&gt;”, because we refreshed 8 times the “&lt;strong&gt;localhost:80&lt;/strong&gt;” URL thus issuing a &lt;code&gt;GET&lt;/code&gt; command in the browser that is intercepted by the *&lt;em&gt;Node.js server *&lt;/em&gt; which increments the “number of visits” (&lt;code&gt;numVisits&lt;/code&gt;) variable. The “number of visits” value is sent back to the browser by the “&lt;em&gt;test-webapp&lt;/em&gt;” process which also saves the value in the “&lt;em&gt;redis&lt;/em&gt;” database in variable &lt;code&gt;numVisits&lt;/code&gt;).&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/data # redis-cli                                                                                                                                                     
127.0.0.1:6379&amp;gt; get numVisits                                                                                                                                      
"8"                                                                                                                                                                    
127.0.0.1:6379&amp;gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;From within the “&lt;em&gt;redis-cli&lt;/em&gt;” in the “&lt;em&gt;redis&lt;/em&gt;” container (“&lt;em&gt;Docker Container 2&lt;/em&gt;”) we can also set in &lt;strong&gt;&lt;em&gt;Redis&lt;/em&gt;&lt;/strong&gt; manually the “&lt;em&gt;numVisits&lt;/em&gt;” variable to a random value of let’s say “&lt;strong&gt;342&lt;/strong&gt;”…&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3snsztp8x4gcgco7t7ec.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F3snsztp8x4gcgco7t7ec.png" alt="1.4 - redis - set num visits 342"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;…the &lt;code&gt;numVisits&lt;/code&gt; variable is updated in the “test-webapp” &lt;strong&gt;Node.js server&lt;/strong&gt; (running in “&lt;em&gt;Docker Container 1&lt;/em&gt;”), and therefore in the browser (due to the fact that in order to invoke the &lt;em&gt;callback&lt;/em&gt; in the &lt;strong&gt;&lt;a href="https://github.com/marcelkatz/test-docker-nodejs-redis-nginx/blob/main/test-webapp/server.js" rel="noopener noreferrer"&gt;Node.js server&lt;/a&gt;&lt;/strong&gt;, one needs to refresh the connection to “&lt;strong&gt;localhost:80&lt;/strong&gt;”, the number of visits increases by &lt;strong&gt;1&lt;/strong&gt;, thus &lt;strong&gt;342&lt;/strong&gt; + 1 = &lt;strong&gt;343&lt;/strong&gt;. This shows that we have two-way inter-process communications between the processes running in “&lt;em&gt;Docker Container 1&lt;/em&gt;” and “&lt;em&gt;Docker Container 2&lt;/em&gt;”.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foapryvdzrnppyzztuxfn.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Foapryvdzrnppyzztuxfn.png" alt="1.4 Browser - localhost - number of visits 343"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;(&lt;strong&gt;1.5&lt;/strong&gt;) A useful feature provided by &lt;strong&gt;Docker Compose&lt;/strong&gt; is the capability to specify in “&lt;em&gt;docker-compose.yml&lt;/em&gt;” a “&lt;a href="https://docs.docker.com/config/containers/start-containers-automatically/#use-a-restart-policy" rel="noopener noreferrer"&gt;restart&lt;/a&gt;” option. &lt;br&gt;
This will allow us when connecting to the shell of “&lt;em&gt;Docker Container 1&lt;/em&gt;”, to “kill” the &lt;strong&gt;Node.js server&lt;/strong&gt; process, but the &lt;strong&gt;Node.js server&lt;/strong&gt; process will be restarted automatically by the &lt;strong&gt;Docker Compose&lt;/strong&gt; “&lt;em&gt;restart&lt;/em&gt;” directive.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;C:\test-docker\test-redis&amp;gt;docker ps
CONTAINER ID   IMAGE                      PORTS                    NAMES
c675ff6c0464   test-redis_nginx           0.0.0.0:80-&amp;gt;80/tcp       test-redis_nginx_1
3137d1468ec7   test-redis_test-webapp-2   0.0.0.0:3009-&amp;gt;5000/tcp   test-redis_test-webapp-2_1 
57d399295421   redis:alpine                                        test-redis_test-redis_1
b30635f44151   test-redis_test-webapp-1   0.0.0.0:3008-&amp;gt;5000/tcp   test-redis_test-webapp-1_1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Connect to the Docker container whose ID is &lt;em&gt;928b8b07415d&lt;/em&gt; and invoke the shell (&lt;strong&gt;&lt;em&gt;sh&lt;/em&gt;&lt;/strong&gt;). &lt;/p&gt;

&lt;p&gt;&lt;code&gt;C:\test-redis\test-webapp&amp;gt;docker exec -it 928b8b07415d sh&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Inside the container, at the shell prompt, show all process id’s using &lt;code&gt;ps -al&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/usr/src/app # ps -al
PID   USER     TIME  COMMAND
1     root     0:00  npm start
19    root     0:00  node server.js
30    root     0:00  sh
36    root     0:00  ps -al
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Proceed with “killing” the “&lt;em&gt;node server.js&lt;/em&gt;” process by issuing a &lt;code&gt;kill -9 &amp;lt;process-id&amp;gt;&lt;/code&gt; command:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;/usr/src/app # kill -9 19&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;In the command line window that is running &lt;strong&gt;Docker Compose&lt;/strong&gt; we can see how the “&lt;em&gt;test-webapp&lt;/em&gt;” receives a “kill signal” (&lt;code&gt;SIGKILL&lt;/code&gt;), exited with code ‘&lt;strong&gt;1&lt;/strong&gt;’, and then restarted automatically.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7m25v5kmnu9zlbobgqgf.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F7m25v5kmnu9zlbobgqgf.PNG" alt="npm ERR command sh -c node server.js"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In &lt;strong&gt;Stage 1&lt;/strong&gt; of this example we showed how &lt;strong&gt;Docker Compose&lt;/strong&gt; allows us to easily establish independent environments that communicate with each other, and also the automatic fault-tolerance (restart on failure) capability of Docker Compose.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Let’s continue with Stage 2:&lt;br&gt;
(2) Load-balancing the Node.js server, with the help of a containerized Nginx reverse-proxy&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The diagram in “&lt;strong&gt;Figure 2.a – Schematic diagram of the components for Stage 2&lt;/strong&gt;” describes an architecture similar to the one described earlier in “&lt;strong&gt;Figure 1.a – Schematic diagram of the components&lt;/strong&gt;” but with the changes described below.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F02s6wkco89eaeu00ezxu.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F02s6wkco89eaeu00ezxu.png" alt="Figure 2.a – Schematic diagram of the components for Stage 2"&gt;&lt;/a&gt;&lt;br&gt;
&lt;em&gt;Figure 2.a – Schematic diagram of the components for Stage 2&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;In “&lt;strong&gt;Figure 2.a – Schematic diagram of the components for Stage 2&lt;/strong&gt;” we have the following components:&lt;/p&gt;

&lt;p&gt;(&lt;strong&gt;2.1.1&lt;/strong&gt;, &lt;strong&gt;2.1.2&lt;/strong&gt;) “&lt;em&gt;Docker Container 1&lt;/em&gt;” and “&lt;em&gt;Docker Container 2&lt;/em&gt;” – two identical containers whose source code reside in directories “&lt;em&gt;&lt;a href="https://github.com/marcelkatz/test-docker-nodejs-redis-nginx/tree/main/test-webapp-1" rel="noopener noreferrer"&gt;test-webapp-1&lt;/a&gt;&lt;/em&gt;” and “&lt;em&gt;&lt;a href="https://github.com/marcelkatz/test-docker-nodejs-redis-nginx/tree/main/test-webapp-2" rel="noopener noreferrer"&gt;test-webapp-2&lt;/a&gt;&lt;/em&gt;” (as shown in “&lt;strong&gt;Figure 2.b – File structure for Stage 2&lt;/strong&gt;” below), that are almost identical copies of the application “&lt;em&gt;test-webapp&lt;/em&gt;” that was described earlier in &lt;strong&gt;Stage 1&lt;/strong&gt;. This time we are using two &lt;strong&gt;Node.js server&lt;/strong&gt; processes that will serve the client browser from the local host machine, scaling up and load-balancing the original one-server configuration from &lt;strong&gt;Stage 1&lt;/strong&gt;. These two containers are defined and controlled each by their respective “&lt;em&gt;Dockerfile&lt;/em&gt;” (&lt;strong&gt;2.1.1.1&lt;/strong&gt;) and (&lt;strong&gt;2.1.1.2&lt;/strong&gt;). Each &lt;strong&gt;Node.js server&lt;/strong&gt; “&lt;em&gt;Docker Container 1&lt;/em&gt;” and “&lt;em&gt;Docker Container 2&lt;/em&gt;” counts the number of visits coming from the local host browser. Then it saves the number of visits into the &lt;strong&gt;&lt;em&gt;Redis&lt;/em&gt;&lt;/strong&gt; database, and it also responds back to the browser with the number of visits and with which specific &lt;strong&gt;Node.js server&lt;/strong&gt; served each individual &lt;em&gt;HTTP GET&lt;/em&gt; request coming from the browser, by sending back to the browser a message of type: &lt;br&gt;
“&lt;strong&gt;test-webapp-1&lt;/strong&gt;: Number of visits is: ”, or &lt;br&gt;
“&lt;strong&gt;test-webapp-2&lt;/strong&gt;: Number of visits is: ”&lt;br&gt;
…thus highlighting the load-leveling nature of this stage.&lt;/p&gt;

&lt;p&gt;(&lt;strong&gt;2.1.3&lt;/strong&gt;) “Docker Container 3” – the container running the &lt;strong&gt;&lt;em&gt;Redis&lt;/em&gt;&lt;/strong&gt; database instance, identical to the one described in &lt;strong&gt;Stage 1&lt;/strong&gt;, storing the “number of visits” performed by the localhost machine browser to “&lt;strong&gt;localhost:80&lt;/strong&gt;”. The number of visits is stored by the &lt;strong&gt;Node.js server&lt;/strong&gt; processes “&lt;em&gt;test-webapp-1&lt;/em&gt;” and “&lt;em&gt;test-webapp-2&lt;/em&gt;” in the &lt;strong&gt;&lt;em&gt;Redis&lt;/em&gt;&lt;/strong&gt; variable &lt;code&gt;numVisits&lt;/code&gt; whose value is transmitted by each &lt;strong&gt;Node.js server&lt;/strong&gt; to the &lt;strong&gt;&lt;em&gt;Redis&lt;/em&gt;&lt;/strong&gt; database on each refresh on the local host browser.&lt;/p&gt;

&lt;p&gt;(&lt;strong&gt;2.2&lt;/strong&gt;) “&lt;em&gt;&lt;a href="https://github.com/marcelkatz/test-docker-nodejs-redis-nginx/blob/main/docker-compose-nginx.yml" rel="noopener noreferrer"&gt;docker-compose-nginx.yml&lt;/a&gt;&lt;/em&gt;” – the main &lt;strong&gt;Docker Compose&lt;/strong&gt; config file defines and controls: (I) “&lt;em&gt;Docker Container 1&lt;/em&gt;” running &lt;strong&gt;Node.js server&lt;/strong&gt; “&lt;em&gt;test-webapp-1&lt;/em&gt;”,  (II) “&lt;em&gt;Docker Container 2&lt;/em&gt;” running &lt;strong&gt;Node.js server&lt;/strong&gt; “&lt;em&gt;test-webapp-2&lt;/em&gt;”, (III) “&lt;em&gt;Docker Container 3&lt;/em&gt;” running &lt;strong&gt;&lt;em&gt;Redis&lt;/em&gt;&lt;/strong&gt;, and (IV) “&lt;em&gt;Docker Container 4&lt;/em&gt;” running &lt;strong&gt;&lt;em&gt;Nginx&lt;/em&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;(&lt;strong&gt;2.3&lt;/strong&gt;) “&lt;em&gt;Docker Container 4&lt;/em&gt;” running “&lt;em&gt;Nginx&lt;/em&gt;” – This is an additional container introduced in &lt;strong&gt;Stage 2&lt;/strong&gt;, defined and controlled by its own &lt;em&gt;Dockerfile&lt;/em&gt; (&lt;strong&gt;2.3.1&lt;/strong&gt;), that runs an “&lt;em&gt;nginx&lt;/em&gt;” instance, and acts a as reverse-proxy that routes the &lt;em&gt;HTTP GET&lt;/em&gt; requests coming from the local host browser. The “&lt;strong&gt;&lt;em&gt;Nginx&lt;/em&gt;&lt;/strong&gt;” process in “&lt;em&gt;Docker Container 4&lt;/em&gt;” routes the &lt;em&gt;HTTP GET&lt;/em&gt; requests coming from local host browser “&lt;strong&gt;localhost:80&lt;/strong&gt;”, in a &lt;strong&gt;round-robin&lt;/strong&gt; manner (&lt;strong&gt;(2.3.3)&lt;/strong&gt; and &lt;strong&gt;(2.3.4)&lt;/strong&gt;), to either the “&lt;em&gt;test-webapp-1&lt;/em&gt;” &lt;strong&gt;Node.js server&lt;/strong&gt; in “&lt;em&gt;Docker Container 1&lt;/em&gt;” or to “&lt;em&gt;test-webapp-2&lt;/em&gt;” &lt;strong&gt;Node.js&lt;/strong&gt; server in “&lt;em&gt;Docker Container 2&lt;/em&gt;”. The “&lt;strong&gt;&lt;em&gt;nginx&lt;/em&gt;&lt;/strong&gt;” process in “&lt;em&gt;Docker Container 4&lt;/em&gt;” is defined and controlled by the &lt;strong&gt;_Nginx _&lt;/strong&gt;config file “&lt;em&gt;&lt;a href="https://github.com/marcelkatz/test-docker-nodejs-redis-nginx/blob/main/nginx/nginx.conf" rel="noopener noreferrer"&gt;nginx.conf&lt;/a&gt;&lt;/em&gt;” which is copied by &lt;strong&gt;&lt;em&gt;Nginx&lt;/em&gt;&lt;/strong&gt; container’s &lt;em&gt;Dockerfile&lt;/em&gt; to the “&lt;em&gt;Docker Container 4&lt;/em&gt;” environment file “&lt;em&gt;/etc/nginx/conf.d./&lt;strong&gt;default.conf&lt;/strong&gt;&lt;/em&gt;” (this is a standard &lt;strong&gt;&lt;em&gt;Nginx&lt;/em&gt;&lt;/strong&gt; setup). The “&lt;em&gt;nginx&lt;/em&gt;” instance distributes the incoming traffic from the local host browser, thus scaling up and load- balancing the single-container web/app server architecture presented in &lt;strong&gt;Stage 1&lt;/strong&gt;. &lt;/p&gt;

&lt;p&gt;And now let’s describe the steps and the flow of this scenario. The numbering scheme in the description below (i.e. (2.1), (2.2), (2.3) etc.), matches the numbering in “&lt;strong&gt;Figure 2.a – Schematic diagram of the components for Stage 2&lt;/strong&gt;”.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;(2.1) File structure:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8v7qndptehh545sknesh.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8v7qndptehh545sknesh.png" alt="Figure 2.b – File structure for Stage 2"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The file structure described in “&lt;strong&gt;Figure 2.b – File structure for Stage 2&lt;/strong&gt;” is almost identical to the files structure described earlier in “&lt;strong&gt;Figure 1.b – File structure for Stage 1&lt;/strong&gt;” with the following changes:&lt;/p&gt;

&lt;p&gt;(&lt;strong&gt;2.1.1&lt;/strong&gt;, &lt;strong&gt;2.1.2&lt;/strong&gt;) The files from directory “&lt;em&gt;test-webapp&lt;/em&gt;” from &lt;strong&gt;Stage 1&lt;/strong&gt; were copied into directories “&lt;em&gt;test-webapp-1&lt;/em&gt;” and “&lt;em&gt;test-webapp-2&lt;/em&gt;”.&lt;/p&gt;

&lt;p&gt;(&lt;strong&gt;2.2&lt;/strong&gt;) Going one directory above, we see the "&lt;em&gt;&lt;a href="https://github.com/marcelkatz/test-docker-nodejs-redis-nginx/blob/main/docker-compose-nginx.yml" rel="noopener noreferrer"&gt;docker-compose-nginx.yml&lt;/a&gt;&lt;/em&gt;" config file that organizes the containerization and sets up the architecture of all the components:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F23ztsgagx0fthaktnn3n.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F23ztsgagx0fthaktnn3n.png" alt="'docker-compose-nginx.yml' file"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Purge all images and containers:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;As in &lt;strong&gt;Stage 1&lt;/strong&gt;, we run command &lt;code&gt;docker system prune -a&lt;/code&gt; to clear all Docker images and containers and start with a clean slate.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;(2.3) Build and run the 'test-webapp-1',  'test-webapp-2', ‘redis’, and ‘nginx’ images with Docker Compose&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Build with Docker Compose:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;C:\test-docker\test-redis&amp;gt;docker-compose -f docker-compose-nginx.yml build&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Run with Docker Compose:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;C:\test-docker\test-redis&amp;gt;docker-compose -f docker-compose-nginx.yml up&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;In the command line window where we issue the &lt;code&gt;docker-compose -f docker-compose-nginx.yml up&lt;/code&gt; command, &lt;strong&gt;Docker Compose&lt;/strong&gt; replies with:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxi20q9vn6kp7m67olqst.PNG" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxi20q9vn6kp7m67olqst.PNG" alt="4 containers running"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;...showing that all 4 Docker containers have started successfully and are up and running: “&lt;em&gt;test-redis_1&lt;/em&gt;” corresponds to the &lt;strong&gt;&lt;em&gt;Redis&lt;/em&gt;&lt;/strong&gt; process running in “&lt;em&gt;Docker Container 3&lt;/em&gt;”, “&lt;em&gt;test-webapp-2_1&lt;/em&gt;” corresponds to the &lt;strong&gt;Node.js server&lt;/strong&gt; process running in “&lt;em&gt;Docker Container 2&lt;/em&gt;”, “&lt;em&gt;test-webapp-1_1&lt;/em&gt;” corresponds to the &lt;strong&gt;Node.js server&lt;/strong&gt; process running in “&lt;em&gt;Docker Container 1&lt;/em&gt;”, and “&lt;em&gt;nginx_1&lt;/em&gt;” corresponds to the &lt;strong&gt;&lt;em&gt;Nginx&lt;/em&gt;&lt;/strong&gt; server running in “&lt;em&gt;Docker Container 4&lt;/em&gt;”.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;View the 'test-webapp-1', ‘test-webapp-2’, 'redis', and ‘nginx’ running containers:&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;C:\test-docker\test-redis&amp;gt;docker ps 
CONTAINER ID   IMAGE                       PORTS       NAMES                                            c675ff6c0464   test-redis_nginx            0.0.0.0:80-&amp;gt;80/tcp        test-redis_nginx_1                               
3137d1468ec7   test-redis_test-webapp-2    0.0.0.0:3009-&amp;gt;5000/tcp   
test-redis_test-webapp-2_1                       
57d399295421   redis:alpine                                                                         test-redis_test-redis_1                          
b30635f44151   test-redis_test-webapp-1    0.0.0.0:3008-&amp;gt;5000/tcp   test-redis_test-webapp-1_1
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The four containers above match containers “&lt;em&gt;Docker Container 1&lt;/em&gt;” through “&lt;em&gt;Docker Container 4&lt;/em&gt;” in “&lt;strong&gt;Figure 2.a – Schematic diagram of the components for Stage 2&lt;/strong&gt;”&lt;br&gt;
above. Note the “&lt;em&gt;CONTAINER ID&lt;/em&gt;” column whose values we will use below to potentially perform operations on each individual running container.&lt;/p&gt;

&lt;p&gt;Let’s run first two instances of the browser on the hosting machine, and point them to URL “&lt;strong&gt;localhost:80&lt;/strong&gt;”:&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F42dwmonlt8jn07ifovp0.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F42dwmonlt8jn07ifovp0.png" alt="2.3 Browser - test-webapp-2 - number of visits 7"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd06t4jutlz9c47pd5po8.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fd06t4jutlz9c47pd5po8.png" alt="2.3 Browser - test-webapp-1 - number of visits 8"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Notice how due to the &lt;strong&gt;round-robin&lt;/strong&gt; routing mechanism employed by the &lt;strong&gt;&lt;em&gt;Nginx&lt;/em&gt;&lt;/strong&gt; reverse-proxy, the “&lt;em&gt;GET localhost:80&lt;/em&gt;” request is routed once to “&lt;em&gt;test-webapp-1&lt;/em&gt;” &lt;strong&gt;Node.js server&lt;/strong&gt;, and once to the “&lt;em&gt;test-webapp-2&lt;/em&gt;” &lt;strong&gt;Node.js server&lt;/strong&gt;, achieving the scaling-up and load balancing that we intended to demonstrate. &lt;/p&gt;

&lt;p&gt;Let’s connect to the container that is running &lt;strong&gt;&lt;em&gt;Redis&lt;/em&gt;&lt;/strong&gt;, to its &lt;strong&gt;&lt;em&gt;sh&lt;/em&gt;&lt;/strong&gt; (shell) environment:&lt;/p&gt;

&lt;p&gt;&lt;code&gt;C:\test-docker\test-redis&amp;gt;docker exec -it 57d399295421 sh&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;Then, inside the container, let’s connect to &lt;strong&gt;&lt;em&gt;Redis&lt;/em&gt;&lt;/strong&gt; itself using “&lt;em&gt;redis-cli&lt;/em&gt;”:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;/data #
/data # redis-cli
127.0.0.1:6379&amp;gt; 
127.0.0.1:6379&amp;gt; get numVisits
"8"
127.0.0.1:6379&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note how the &lt;code&gt;get numVisits&lt;/code&gt; command in &lt;strong&gt;&lt;em&gt;Redis&lt;/em&gt;&lt;/strong&gt; returns the expected value of “number of visits” that is communicated to the “&lt;strong&gt;&lt;em&gt;redis&lt;/em&gt;&lt;/strong&gt;” container from the containers that are running the &lt;strong&gt;Node.js app servers&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conclusion&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;In &lt;strong&gt;Stage 2&lt;/strong&gt; of this example we showed how &lt;strong&gt;Docker Compose&lt;/strong&gt; allows us to easily establish multiple containers with their independent environments that communicate with each other, and also how scaling and load-balancing achieved with Nginx.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Source code:&lt;/strong&gt;&lt;br&gt;
&lt;a href="https://github.com/marcelkatz/test-docker-nodejs-redis-nginx" rel="noopener noreferrer"&gt;https://github.com/marcelkatz/test-docker-nodejs-redis-nginx&lt;/a&gt;&lt;/p&gt;

</description>
      <category>docker</category>
      <category>node</category>
      <category>redis</category>
      <category>nginx</category>
    </item>
  </channel>
</rss>
