Continuous Delivery for React application using Docker (part 2 of 2)

Ralabs
May 21 · 5 min read

Author – Roman Rodomansky, CTO of Ralabs.

In the previous part of the article, we figured out how to build a Docker image locally and run it on a remote AWS EC2 server. In this chapter, in turn, we’re be pushing an image through a remove CI server and make this image run and update automatically.

So before going into the reading, be sure to check part 1 of the article.

Continuous Integration Through CircleCI

CircleCI is a great Continuous Integration tool that helps you automate the process of building your project’s artifacts, along with any other delivery process.

Besides, CircleCI provides free 1000 minutes/month, and it’s completely enough for any project. We regularly use CircleCI in our web, mobile, and IoT projects.

In one of our IoT projects containing a web part, we had 3 sub-projects: API (Node.js), Web (React.js/Next.js), and Admin (React.js). The average build time for React app tool is approximately 4 seconds. So, with a free tier, you can run up to 15k builds per month, which is a reasonably huge number :)

Sample usage of CircleCI for building Web, API, and Admin sub-projects.

You need to create .circleci/config.yml, which will include configurations for the CircleCI server. As you may remember, we completed a manual process in the previous part of the article. So in this case, we just need to automate all steps from the manual flow, including the login, the build docker image, the tagging, and the pushing.

So, the result on .circleci/config.yml will look like the following:

version: 2
jobs:
build:
working_directory: ~/repo
machine: true
branches:
only:
- master
steps:
- checkout
- run: docker login repo.treescale.com -u $DOCKER_USER -p $DOCKER_PASS
- run:
name: build docker image
command: |
echo "deploying to development environment"
docker build -t my-app .
docker tag my-app repo.treescale.com/ralabs/my-app-dev:latest
docker push repo.treescale.com/ralabs/my-app-dev:latest

To explain, this configuration will perform the following functions:

  1. Watching changes on themaster branch.
  2. Logging in the Docker repository treescale.com.
  3. Building an image.
  4. Tagging this image.
  5. Pushing this image to remove the Docker repository on treescale.com.

As you can see, these are the same steps that we went through in the previous article in the manual mode. All these steps are now run inside Virtual Machine, which is managed by CircleCI.

That’s it! Try to push .circleci/config.yml to themaster branch and then push any changes that occur to trigger the CircleCI new job.

Automate the Updates

After we become able to build images automatically and run the containers on the remote AWS EC2 servers (check “AWS EC2 Quick Setup” in the previous article), we’re up to a new challenge: How can we make the downloading and restarting new images on a remote server automatic?

The good and easy solution to this issue is Watchtower. Watchtower can be run as a Docker container on a remote server and has zero-configuration. Also, Watchtower supports Slack notifications from the box, which is definitely a benefit!

$ docker run \
-d \
--name watchtower \
-e REPO_USER=xxx -e REPO_PASS=xxx \
-v /var/run/docker.sock:/var/run/docker.sock \
containrrr/watchtower \
--debug \
--label-enable \
--cleanup \
--notifications slack --notification-slack-hook-url https://hooks.slack.com/services/...

Let’s explain what each element means more in-depth:

  • REPO_USER and REPO_PASS are the credentials to authenticate into treescale.com;
  • --debug is an argument to run Watchtower on debug-mode so that you can see more detailed logs;
  • --label-enable will run Watchtower with monitoring containers with a specific label only. It’s helpful when you have run other containers on the server or just a number of particular containers should be monitored;
  • --cleanup is a perfect attribute that will help to keep effective performance and storage on a remote server;
  • --notifications is used to set up the notification bridge between Watchtower and Slack.

In other words, Watchtower monitors all the running containers for new images. In the case of a new image appearing, it’s downloaded, and the previous container stops running, with a new container starting to run instead.

To check the logs, you can run $ docker logs -f <container-id> . To get to know the container ID of Watchtower’s container, run $ docker ps .

You can find Watchtower on the Docker process list.

Why You May Need NGINX

NGINX is essential when you have multiple running containers on a single server. The challenge implies that you need to forward the traffic to a specific container.

Let’s imagine you have a single EC2 instance with IP 1.2.3.4 . And all magic happens with DNS!

Supposedly, you have 3 domains: web.test.ralabs.org , api.test.dev.ralabs.org, and admin.test.ralabs.org . All the domains have A record navigated to 1.2.3.4 .

On the remote EC2 server, the NGINX configuration is stored on the/etc/nginx/conf.d/ directory for each domain. Therefore, we have 3 configuration files in this directory.

A sample configuration for SSL server looks like this:

server {
listen 80;
listen [::]:80;
server_name api.test.ralabs.org;
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
listen [::]:443 ssl;

server_name api.test.ralabs.org;

location / {
proxy_pass http://127.0.0.1:3000;
proxy_redirect off;
proxy_http_version 1.1;
proxy_set_header Host $http_host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Host $server_name;
proxy_set_header Connection "";
}
}

In this configuration, you may see that all the traffic that comes to api.test.ralabs.org:80 (http) will redirect users to api.test.ralabs.org:443 (https). After that, all the traffic that comes to api.test.ralabs.org:443 (https) will be forwarded internally to http://127.0.0.1:3000. As you remember, :3000 stands for where we have run the Docker container.

With this being said, here’s how the magic happens: the traffic gets redirected to the internal service (Docker). It’s not visible for the user, but we can have multiple running containers on a single EC2 instance.


Now you can try to push your code to a remote code repository (i.e. Github), and CircleCI will track the changes, build an image, and push it to a remote AWS EC2 instance. Watchtower, run on this EC2 instance, will find a new image and update the container.

That’s it! Now you know the perks of using Docker for Continuous Delivery in React application.

We are eager to get some feedback! So let us know if you have any questions at hello@ralabs.org and share your experience in the comments :)

Ralabs

Written by

Ralabs

Your business casual in the world of custom software https://ralabs.org/

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade