# Using GitHub Actions to deploy your react application to Azure

This guide will walk you through a simple CI/CD approach for deploying react web applications to Azure Cloud

![gif](https://media.giphy.com/media/q7UpJegIZjsk0/giphy.gif)

## Prerequisites
- Azure Account 
- GitHub Account 
- A React Application 

We will be using  [GitHub Actions](https://docs.github.com/en/actions) as our CI/CD platform to deploy, [Docker](https://www.docker.com/) to containerize our application, and [Kubernetes](https://kubernetes.io/)

## Why Docker? 
Docker is a tool designed to make it easier for developers to develop, ship, and run applications by using containers. We are going to create a `Dockerfile` with an [Nginx](https://www.nginx.com/) image which will help us in serving the built project through a built server.  

## Why Kubernetes? 
Kubernetes allows you to run your Docker containers and workloads and helps you to tackle some of the operating complexities. 


## Create Nginx Config
Create a file named `nginx.conf` in the root folder of your project

This file will contain all the necessary information for Nginx to serve the `index.html` present in the `build` folder and takeyarn care of `404`s if a user visits a route that doesn't exist.

Note: If you have an SSL Certificate and you want to serve your website through HTTPS you need to add a block of code to redirect code from port `80` to `443` and serve the HTML file through that. You can read more about it [here](https://docs.nginx.com/nginx/admin-guide/security-controls/terminating-ssl-http/).

```
server {
    listen 80;
    listen [::]:80;
    location / {
        root /usr/share/nginx/html;
        index index.html index.htm;
        try_files $uri $uri/ /index.html =404;
    }
}

``` 


##  Create a Dockerfile
Create an empty file named `Dockerfile` at the root of your project

This Dockerfile will use the Nginx configuration we created in the previous step and use the 
copy the HTML from the build directory to the Nginx directory, which will help in serving the site.

```
FROM node:14.17.0-alpine AS builder

# Directory
WORKDIR /app

COPY . .

FROM nginx:stable-alpine
COPY --from=builder /app/build /usr/share/nginx/html
COPY --from=builder /app/nginx.conf /etc/nginx/conf.d/default.conf
EXPOSE 80
CMD ["nginx", "-g", "daemon off;"]
``` 

## Kubernetes Configuration
You can create a `deployment.yaml` file with the necessary information to deploy your Docker Image


```
apiVersion: v1

kind: Pod

metadata:

  name: react-project

  labels:

    app: web

spec:

  containers:

    - name: react-project

      image: nginx

      ports:

        - containerPort: 80

``` 


## Create the actions file
Create an empty directory named `.github` and create a file named `actions.yaml` inside it.

This file will help us with the step-by-step process of deploying our code to the server whenever a commit is pushed or a branch gets merged to the `main` branch. 

Following is a simple diagram of content present in the `actions.yml` file. 

![image.png](https://cdn.hashnode.com/res/hashnode/image/upload/v1663171196008/hGBkLrGBB.png align="left")

You can read about creating an Azure Container Registry [here](https://docs.microsoft.com/en-us/azure/container-registry/container-registry-get-started-portal?tabs=azure-cli) and creating an Azure Kubernetes Cluster [here](https://docs.microsoft.com/en-us/azure/aks/learn/quick-kubernetes-deploy-portal?tabs=azure-cli)

The basic setup of GitHub Actions to execute `npm install` and `npm run build` when any branch gets merged to the `main` branch

```
name: react-project

on:
  push:
    branches: [main]
      

jobs:

  publish:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Use Node.js 16.x
        uses: actions/setup-node@v2
        with:
          node-version: 16.x
      - run: npm install
      - name: Creates a build directory
        run: npm run build
        env:
               # Any environment variables used in the project
``` 


Installing Azure CLI and configuring Azure credentials is the next step to make sure we can push the created Docker Image 


```
      - name: Install Azure cli
        run: |
          sudo apt-get install ca-certificates curl apt-transport-https lsb-release gnupg
          curl -sL https://packages.microsoft.com/keys/microsoft.asc | gpg --dearmor | sudo tee /etc/apt/trusted.gpg.d/microsoft.gpg > /dev/null
          AZ_REPO=$(lsb_release -cs)
          echo "deb [arch=amd64] https://packages.microsoft.com/repos/azure-cli/ $AZ_REPO main" | sudo tee /etc/apt/sources.list.d/azure-cli.list
          sudo apt-get update
          sudo apt-get install azure-cli
      - name: Configure Azure credentials
        uses: azure/actions/login@v1
        with:
          creds: ${{ secrets.AZURE_CREDENTIALS }}
``` 

You may notice that we are using a few secret variables here and there in the file, you can read about creating them [here](https://docs.github.com/en/actions/security-guides/encrypted-secrets)

Logging to Azure Container Registry and pushing the Docker Image to the registry


```
      - name: Log into the registry
        uses: docker/login-action@v1
        with:
          registry: ${{ secrets.AZURE_ACR_ENDPOINT }}
          username: ${{ secrets.AZURE_ACR_USERNAME }}
          password: ${{ secrets.AZURE_ACR_PASSWORD }}
      - name: Build, tag, and push the image to Azure Container Registry
        run: |
          docker build -t react-project .
          docker tag react-project:latest ${{secrets.AZURE_ACR_ENDPOINT}}/react-project:latest
          docker tag react-project:latest ${{secrets.AZURE_ACR_ENDPOINT}}/react-project:${IMAGE_TAG}
          docker push ${{secrets.AZURE_ACR_ENDPOINT}}/react-project:latest
          docker push ${{secrets.AZURE_ACR_ENDPOINT}}/react-project:${IMAGE_TAG}
        env:
          IMAGE_TAG: ${{ github.sha }}

``` 

To get to know about retrieving your Azure Credentials, please refer [here](https://docs.microsoft.com/en-us/cli/azure/acr/credential?view=azure-cli-latest#az-acr-credential-show)

`${{ github.sha }}` helps in creating a unique hash string to differentiate between images pushed before. 

Deploy the Docker Image to Kubernetes Cluster and verify if it's deployed


```
 - name: Deploy to cluster
        uses: steebchen/kubectl@v2.0.0
        with: # defaults to latest kubectl binary version
          version: v1.22.0
          config: ${{ secrets.KUBE_CONFIGURATION }}
          command: rollout restart react-project 
      - name: Verify the deployment
        uses: steebchen/kubectl@v2.0.0
        with:
          config: ${{ secrets.KUBE_CONFIGURATION }}
          version: v1.22.0 # specify kubectl binary version explicitly
          command: rollout status react-project 
``` 

Now that you have verified the deployment, after merging your code to the main branch all the code will be deployed to your server directly.
![gif](https://media.giphy.com/media/RkuLrA46UiFYp9h6u9/giphy.gif)


        
[sudharsangs.in](https://www.sudharsangs.in)
