Zero Downtime Deployments with Docker and NGINX

Welcome to this comprehensive tutorial on zero downtime deployments with Docker and NGINX! Throughout this guide, I will explain each concept and step in detail, so even if you’re a beginner, you will be able to follow along and learn.

To learn more about Docker, check out Docker tutorials page.

Introduction to Docker, NGINX, and Zero Downtime Deployments

Docker

Docker is an open-source platform that allows developers to automate the deployment, scaling, and management of applications. It uses OS-level virtualization to deliver software in packages called containers. Containers are isolated from each other and bundle their own software, libraries, and configuration files; they can communicate with each other through well-defined channels.

NGINX

NGINX is a powerful open-source web server, load balancer, and reverse proxy. In this tutorial, we’ll be using NGINX as a load balancer to distribute network or application traffic across many servers.

Zero Downtime Deployments

Zero downtime deployment is a deployment method where the old version of the application and the new version can run simultaneously, without any disruption of service. It’s crucial for services that need to be available 24/7.

Setting Up Docker and NGINX

Before we proceed, you will need to have Docker and NGINX installed on your system. If you haven’t already done so, you can follow these steps to install them.

Docker

  1. Update your system’s package list: Run the command sudo apt-get update.
  2. Install Docker: Run the command sudo apt-get install docker-ce docker-ce-cli containerd.io.

NGINX

  1. Update your system’s package list: Run the command sudo apt-get update.
  2. Install NGINX: Run the command sudo apt-get install nginx.

You can verify the installation of both Docker and NGINX by running docker --version and nginx -v, respectively. If both commands return a version number, then you’ve successfully installed Docker and NGINX.

Creating a Basic Web Service

Now, let’s create a basic web service using Docker. Here, we’ll create a simple “Hello, World!” application using Node.js.

  1. Create a new directory: Run mkdir node-app && cd node-app.
  2. Create a new file named ‘app.js’: Run touch app.js.
  3. Open ‘app.js’ in your favorite text editor, and add the following code:
    const http = require('http');
    
    const requestListener = function (req, res) {
      res.writeHead(200);
      res.end('Hello, World!');
    }
    
    const server = http.createServer(requestListener);
    server.listen(8080, () => {
      console.log('Server is running...');
    });
    
  4. Create a Dockerfile in the same directory: Run touch Dockerfile.
  5. Open the Dockerfile in your text editor, and add the following:
    FROM node:14
    WORKDIR /usr/src/app
    COPY package*.json ./
    RUN npm install
    COPY . .
    EXPOSE 8080
    CMD [ "node", "app.js" ]
    

     

  6. Build the Docker image: Now that we have our Dockerfile ready, we can build our Docker image. Run the command docker build -t node-app . in the terminal. The -t flag allows us to tag the image with a name, in this case, “node-app”.
  7. Run the Docker container: After the image has been built, run the command docker run -p 8080:8080 -d node-app. The -p flag publishes the container’s port to the host. The -d flag runs the container in detached mode, meaning it runs in the background.

At this point, if you navigate to http://localhost:8080 in your web browser, you should see the text “Hello, World!” displayed.

Configuring NGINX for Load Balancing

We’ll use NGINX to manage traffic between two or more instances of our Node.js application. This is known as load balancing.

  1. Create a new NGINX configuration file: Create a new file in /etc/nginx/conf.d/ named load-balancer.conf. You might need to use sudo to create and edit files in this directory.
  2. Open ‘load-balancer.conf’ in a text editor, and add the following:
    http {
        upstream node-app {
            server localhost:8080;
            server localhost:8081;
        }
    
        server {
            listen 80;
    
            location / {
                proxy_pass http://node-app;
            }
        }
    }
    

    This configuration sets up a “node-app” upstream that consists of two Node.js app instances running on ports 8080 and 8081. All incoming traffic on port 80 is then forwarded to this upstream.

  3. Restart NGINX: Run the command sudo systemctl restart nginx to apply the new configuration.

Deploying with Zero Downtime

Now, we’re ready to demonstrate zero downtime deployments. The process consists of starting a new instance of the app, ensuring it’s running correctly, then stopping the old instance.

  1. Make a change to your app: Open ‘app.js’ and change ‘Hello, World!’ to ‘Hello, Docker!’.
  2. Build a new Docker image: Run docker build -t node-app:v2 ..
  3. Start a new instance of the app: Run docker run -p 8081:8080 -d node-app:v2.
  4. Update the NGINX configuration: Open ‘load-balancer.conf’ and comment out the line server localhost:8080;. Then restart NGINX with sudo systemctl restart nginx.
  5. Stop the old instance of the app: First, find the container ID of the old app with docker ps. Then, stop it with docker stop <container-id>.

If you navigate to http://localhost in your web browser, you should see the text “Hello, Docker!” displayed, showing that the new version of the app is running. The best part is, there was no downtime during this deployment process!

Troubleshooting Common Problems

If you encounter problems during this process, here are some common issues and their solutions:

  • If the Docker commands fail, make sure Docker is installed and running correctly. You can check Docker’s status with systemctl status docker.
  • If you can’t connect to your app via the browser, make sure the app is running and listening on the correct port. You can check which Docker containers are running with docker ps.
  • If NGINX fails to restart after changing the configuration, check the syntax of your configuration file with nginx -t. This command will tell you if there are any syntax errors in your configuration files.
  • If your load balancing isn’t working as expected, make sure that all your app instances are correctly listed in the NGINX configuration, and that they’re all running and accessible.
  • If you’re having trouble stopping a Docker container, ensure you’ve correctly identified the container ID with docker ps. If the container refuses to stop, you can use docker kill <container-id> to forcefully stop it.
  • If you’re seeing an older version of your app after deployment, it could be due to browser caching. Try clearing your browser’s cache, or use a different browser to confirm.

Final words

This concludes our tutorial on zero downtime deployments with Docker and NGINX. Now, you should have a good understanding of how to use these technologies to deploy web applications with no service interruptions. Remember, practice is key when it comes to learning new technologies, so don’t hesitate to experiment and build your own projects!