Deploy React App using GitLab CICD and Docker
Tags: cicd, docker, devops, react
Published: 2024-05-09 18:06:16

## Prerequisites:
1. Ubuntu Machine
2. GitLab account
3. Node, NPM, Docker installed on Ubuntu Machine & Local Machine

## Steps:

### 1. Project Folder

- Create a react app on your local machine using `npx create-react-app react-app`
- Create **nginx.conf** file with below content

```
http {

  include mime.types;

  set_real_ip_from        0.0.0.0/0;
  real_ip_recursive       on;
  real_ip_header          X-Forward-For;
  limit_req_zone          $binary_remote_addr zone=mylimit:10m rate=10r/s;

  server {
    listen 80;
    server_name localhost;
    root /proxy;
    limit_req zone=mylimit burst=70 nodelay;

    location / {
            root   /usr/share/nginx/html;
            index  index.html index.htm;
            try_files $uri /index.html;   
    }
  }
}

events {}
```

- Create a **Dockerfile** with below content

```
FROM nginx:latest

COPY ./build /usr/share/nginx/html

COPY nginx.conf /etc/nginx/nginx.conf  

EXPOSE 80/tcp 

CMD ["/usr/sbin/nginx", "-g", "daemon off;"]  
```

- Create a **deploy.sh** file

```
#!/bin/bash

# Pull the latest Docker image
docker pull <image-name>

# Stop and remove any existing container with the same name
docker stop <container-name> || true
docker rm <container-name> || true

# Run the Docker container
docker run -d --name <container-name> -p <host-port>:<container-port> <image-name>
```

- Add the .pem file, which will be require to SSH into our Ubuntu machine in same folder.

### 2. GitLab
- Create a GitLab account if you don't have
- Push code to GitLab
- Goto **Setting -> CICD -> Variables**
- Create a new **variable** with DNS of your ubuntu machine, Docker Image Name, Docker Hub Token(configure later on), Docker Hub username
![Variable for CICD](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/2kf91en82929jf7yqf9s.png)
- Create a cicd file in gitlab pipeline editor with below content

```
stages:
  - build
  - build image
  - deploy

Build:
  stage: build
  image: node:20-alpine

  script:
    - npm install
    - npm run build

  artifacts:
      paths:
        - build/

Push To DockerHub:
  stage: build image
  image: docker:stable

  services:
    - docker:dind
  script:
    - docker build -t $DH_IMAGE_NAME .
    - docker login -u $DH_USER_NAME -p $DH_TOKEN
    - docker push $DH_IMAGE_NAME

  dependencies:
    - Build

Deploy to EC2:
  stage: deploy
  image: alpine:3.19

  before_script:
    - apk update
    - apk add openssh-client
    - chmod 600 "Ubuntu1Key.pem" 
    
  script:
    - ssh -o StrictHostKeyChecking=no -i "Ubuntu1Key.pem" ubuntu@"$U1_EC2_DNS" 'bash -s' < deploy.sh  
```

> **Explantion:** 
> This CI/CD file in GitLab has three stages:
> - **Build:** Uses Node.js to install dependencies and build the project. The resulting artifacts are stored in the build/ directory.
> - **Push To DockerHub:** Builds a Docker image using Docker's stable version, then pushes it to DockerHub after logging in with credentials.
> - **Deploy to EC2:** Utilizes Alpine Linux to update packages and install SSH client. It sets permissions for SSH key usage, then deploys to an EC2 instance by executing a deployment script via SSH.

### 3. Docker Hub

- Create an account for Docker Hub
- Goto **My Account -> Security -> Create A new Token** (With Read and Write)
- Copy the token & paste it in the variable create earlier in GitLab name **DH_TOKEN** 

### 4. Run the CICD Pipeline

- Commit once on the main branch, so our CICD will be triggered automatically.
- Goto the **_Build -> Pipelines_**
- After successful completion of CICD, it will look like this

![CICD Result](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/h6y9u0vke3vf46q04ape.png)

Now open the Public IP of EC2 with host-port which you specified in the `deploy.sh`.

**_BYE_ 👋👋**