What’s the Two-Part Piece About?

We’re practicing using CI/CD (continuous integration and continuous delivery/deployment) in many projects at Ralabs. With this tool, you get to save lots of time and effort on testing and delivering applications to end-users. We want to share our experience and the things we’ve learned on the best practices of CI/CD implementation in a project. With this being said, the two articles, or rather two parts of one piece, introduce you to a guideline on how to set up Continuous Delivery for React project from scratch using Docker, AWS, and a couple of other 3rd party tools. You’ll also come across some useful articles related to the CI/CD implementation in general.In this particular article, which is the 1st part, we tell about preparing the app foundation for future deployment. Basically, you start with running simple React app locally, then install Docker locally, setup EC2 server, and end up with preparing the Docker commands. Eventually, with our low-key tutorial, you’ll learn how to push your app’s image to remove the Docker registry. The 2nd article, in turn, guides you in configuring the CI server, adding versioning and environment variables, applying the Continuous Deployment tool, and testing the achieved deployment flow. As a result, you’ll have automated deployment for any changes in the app. If you have any questions after reading this article or want to gain a deeper insight into our experience, feel free to drop us an email at hello@ralabs.org. We’ll be happy to help you!

How Deployment Flow Should Look Like with CI/CD

CI and CD are the two important techniques widely used in DevOps. CI is exceptionally popular in the Software Development world. It’s applied to any steps that can be automated in case of new changes, like building, testing, packaging etc. From the software development perspective, all code changes are merged into a mainline, i.e. master, after the automatically created ones build. In terms of costs, your team will need to spend time on automated tests for any new features or improvements. As a result of using CI\CD, you manage to save time on regression testing by minimizing the number of occurring bugs, since regression testing becomes automated.
Source: https://it.atlassian.com/continuous-delivery/principles/continuous-integration-vs-delivery-vs-deployment
The only difference between Continuous Delivery and Continuous Deployment is whether the manual or automated trigger is utilized. In the case of the “Delivery” approach, all changes are deployed manually, i.e. using the triggering button from Jenkins. With “Continuous Deployment,” everything is automated.

React Simple Web App via React Create App

Our foundation app for deployment will be a simple React app, created using create-react-app. To set up your app, just follow the “Creating an App” steps. If you’re using Yarn (as we do), just run:
$ yarn create react-app my-app
The yarn create is a command that allows you to create new projects from boilerplate. For example, by running `yarn create react-app,` you’ll install the npm/create-react-app package.

Why Should We Use Docker?

Here comes the most interesting part. Docker is great as an approach to containerization for delivering apps or packages. Why? It allows you to avoid doing that extra job (and wasting time when it’s not necessary), such as caring about servers configuration, 3rd party packages installation, and other aspects. You can check whether you have Docker installed by running: $ docker -v
A sample response from “docker ps” command. After a fresh installation, an empty list.
If you don’t have Docker installed, you follow theDocker CE installation steps. For MacOS, you can find the instructions here. After Docker has been properly installed, you should be able to run $ docker ps., which is the process list, and see an empty list of running containers.
A sample response from “docker ps” command. After a fresh installation, an empty list.
A quick tip: consider reading “Docker and the Three Ways of DevOps” if you’re interested in deployment using Docker.

Make the Docker Image Persistent

A basic manual deployment flow using Docker consists of the following steps:
  1. Prepare the app source code
  2. Prepare the setup instructions (Dockerfile and docker-compose.yml)
  3. Build an image
  4. Run container based on that image if you need to run any tests
  5. Push the image to remote registry
  6. Pull the image on a remote server
  7. Run the container on a remote server
 Keep in mind that the steps 3 through 7 will be automated in the 2nd article.
From “Continuous Delivery with Docker on Mesos in less than a minute” on container-solutions.com
For your app, you can consider using either the “docker registry” or “repository for images.” Docker registry stores docker images, similar to what Github does for the codebase. However, for security reasons, you can use a private registry. Let’s check what Docker Registries are available on the market, and what their prices are:
  • DockerHub – 1 private repository is FREE, other plans start from $7/mo
  • GoogleCloud Container Registry Pricing – $0.026/Gb
  • AWS ECR (Elastic Container Registry) – first 500 Mb are free, the next are $0.10/Gb, plus data transfer
  • TreeScale – FREE unlim private repos, 500 pull actions limit, 50 Gb storage
  • Canister – 20 FREE private repos, limited storage. (We don’t recommend this one though, since it has had a network issue on May 2019.)
For our app, we’re using TreeScale for testing purposes. Before starting, you need to register your personal account. Having registered your account, you should now be able to sign in the account. If you’ve already logged in, you should see the “Login Succeeded” message. If this is fresh login, you’ll be asked to enter your login and password. $ docker login repo.treescale.comAuthenticating with existing credentials...Login SucceededAfter registration, you need to create a new repo on TreeScale dashboard. This is similar to the Github repository, which should not be a challenge if you’re familiar with the latter.

Dockerfile

Now, we need to prepare instructions for a future build. Create Dockerfile – content is here. Keep in mind that you should consider splitting nginx and code-container to different containers. In other words, stick to Docker’s philosophy: “single service per container.” In this article, we do explain how to create a kind of “monolithic” container but just to simplify the process, since the idea is to show how Continuous Deployment works. Create the ./deploy/nginx.conf file – content is here.

AWS EC2 Quick Setup

The next step is to prepare a virtual machine that will be responsible for storing the image and running the container. Proceed to sign up process on AWS. Usually, you’ll need to wait until AWS approves your account and can start using it immediately.
After the account is activated, you can start creating a new EC2 server.
In the course of launching a new instance, select Free tier and follow with the default configuration. After the setup is finished, don’t forget to store the .pem file, that will be used in for further authentification. After the EC2 instance has been created, ssh into the virtual machine:http://$ ssh -i my-app.pem ec2-user@18.188.230.1 Now you’re supposed to be inside the VM. Looking good! :) To continue, follow the Docker setup instructions for Linux. When Docker is installed on EC2 VM, log in, pull the previously pushed image, and run a new container. After running docker ps, you should see the container you’ve just run:
Here it is, you can now navigate to EC2’s IP! Particularly, you should see you React app in the browser. Since it is a manual process, you need to build a new image on each change and pull the images to the remote server. Besides, you need to kill and start a new container manually every time. It’s a boring, routine process that always requires following the same steps over and over. On this note, we’re done with part one of our case. In the next one, we automate the processes of building, pushing, and downloading the new container. So when you go through the rest of the piece, you’ll only have to apply some changes to a specific branch (i.e. masterdevelopment, etc). See you in part 2!