Skip to main content

Command Palette

Search for a command to run...

Project 20: Deploying React Application to Google cloud run using Github Action

Updated
6 min read
Project 20: Deploying React Application to Google cloud run using Github Action

Introduction:

  • Overview:This project focuses on streamlining the deployment of a React application by leveraging the power of Google Cloud Run and GitHub Actions. The goal is to create a robust and automated Continuous Integration/Continuous Deployment (CI/CD) pipeline that efficiently builds, tests, and deploys our application whenever changes are pushed to the GitHub repository.

  • Why this Technology:

    • React : A popular JavaScript library for building dynamic and interactive user interfaces, offering component-based architecture and a thriving ecosystem.

    • Google Cloud Run: A serverless platform that automatically scales our application based on demand. This eliminates server management overhead and optimizes costs.

    • GitHub Actions: A CI/CD platform integrated directly into GitHub, enabling automated workflows triggered by code changes. This simplifies the process of building, testing, and deploying our application.

Architecture:

We'll be using this GitHub repository as our foundation: https://github.com/patelajay745/Second-brain.git#development

Project:

  • Clone git repo to local:

  • First we will setup everything for backend followed by frontend. Now we will add docker file to backend folder. I have create a multistage docker file.

  • Add Dockerfile to backend folder:

      FROM node:18-slim AS builder
      WORKDIR /app
      COPY package.json yarn.lock ./
      RUN yarn install --frozen-lockfile
      COPY . .
      RUN yarn build
    
      # second stage
      FROM node:18-slim
      WORKDIR /app
      COPY package.json yarn.lock ./
      RUN yarn install --production --frozen-lockfile
      COPY --from=builder /app/dist ./dist
      EXPOSE 8080
      CMD ["yarn", "start"]
    
  • Now we need to setup Google cloud.

1. Create new Project from google cloud console. Click on “New Project”

  1. Provide name for the project and click on “Create”.

  2. Goto IAM and click on “Service Accounts”

  3. Click on “Create Service Account”

  4. Provide name to service account “brain-app-sa”

  5. Add three roles to this service account “Artifact Registry adminnistrator”, “Cloud Run admin”, “Service Account User”

  1. Click on “continue” then “Create”.

  2. Click on name of the service account.

  3. Click on “Keys”

  4. Click on “Add key”. Then Click on “Create new Key”.

  5. Choose Json and then click on “Create”. It will download new key to access google cloud using created service account.

  6. Go to “Artifact Registry”. Enabled API for that if required. Click on “Create Repository”

  7. Provide name and region then click on “Create”

Now we need to setup required secret and variable to github repo.

Go to Settings on your Github Repo.

Click on “Secrets and variables” then click on “Actions”

We need to create 3 secrets (You can either repository secrets or Environment secrets)

1. ACCESS_TOKEN_SECRET (Randon string for json Webtoken)
2. GOOGLE_CREDENTIALS (Json data of service account key)
3. MONGODB_URI (managed mongo db access url)

Now click on “Variables” and then click on “Manage environment secrets”

Then Add 2 new variables.

1. GCP_PROJECT_ID (Google cloud project Id)
2. GCR_REPO_NAME (Google artifact registry name)

Now Go to Cloned local repo. Add Folder “.github”. Inside that folder create folder “workflows” then create file named “backend.yml”

.github>workflows>backend.yml

        name: Backend Cloud Run Deployment

        on:
          push:
            branches:
              - development
            paths:
              - "backend/**"
          pull_request:
            paths:
              - "backend/**"

        jobs:
          build-and-push:
            runs-on: ubuntu-latest
            environment: dev
            steps:
              - name: checkout
                uses: actions/checkout@v4

              - name: Google Cloud Auth
                uses: google-github-actions/auth@v2
                with:
                  credentials_json: "${{ secrets.GOOGLE_CREDENTIALS }}"
                  project_id: ${{ vars.GCP_PROJECT_ID }}

              - name: Setup Cloud SDK
                uses: "google-github-actions/setup-gcloud@v2"

              - name: Configure Docker
                run: gcloud auth configure-docker us-central1-docker.pkg.dev

              - name: Build
                env:
                  IMAGE_NAME: backend
                  PROJECT_ID: ${{ vars.GCP_PROJECT_ID }}
                run: |-
                  docker build -t us-central1-docker.pkg.dev/$PROJECT_ID/${{ vars.GCR_REPO_NAME }}/$IMAGE_NAME:latest -f backend/Dockerfile backend/.
                  docker push us-central1-docker.pkg.dev/$PROJECT_ID/${{ vars.GCR_REPO_NAME }}/$IMAGE_NAME:latest

              - name: Deploy to Cloud Run
                run: |
                  gcloud run deploy second-brain-backend \
                      --image us-central1-docker.pkg.dev/${{ vars.GCP_PROJECT_ID }}/${{ vars.GCR_REPO_NAME }}/backend:latest \
                      --platform managed \
                      --port=8080 \
                      --region us-central1 \
                      --allow-unauthenticated \
                      --set-env-vars "MONGODB_URI=${{ secrets.MONGODB_URI }},ACCESS_TOKEN_SECRET=${{secrets.ACCESS_TOKEN_SECRET}},ACCESS_TOKEN_EXPIRY=1d"

make required changes to above pipeline.

Now let’s push code to remote repo and check pipeline has any error.

We got error saying our cloud run api is not enabled. we need to enable and then try again.

Finally Pipeline got executed successfully and we got url for backend.

Try url to test your backend in postman. Keep this backend url handy , we will need to add this to frontend to solve cors problem.

Now, Moving to frontend part.

We need to add one more secrets to github repo.

VITE_BACKEND_URL (backend url ,which we got in above step)

Add Docker file to Frontend Folder

        FROM node:20-alpine AS builder
        RUN apk add --no-cache yarn
        WORKDIR /app
        COPY package.json yarn.lock ./
        RUN yarn install --frozen-lockfile --cache-folder ./.yarn-cache
        COPY . . 
        ARG VITE_BACKEND_BASE_URL
        RUN yarn build

        FROM nginx:alpine
        COPY nginx.conf /etc/nginx/conf.d/default.conf
        COPY --from=builder /app/dist /usr/share/nginx/html

        EXPOSE 80
        CMD ["nginx", "-g", "daemon off;"]

Add frontend.yml to .github/workflows folder

        name: Frontend Cloud Run Deployment

        on:
          push:
            branches:
              - development
            paths:
              - "frontend/**"
          pull_request:
            paths:
              - "frontend/**"

        jobs:
          build-and-deploy:
            runs-on: ubuntu-latest
            environment: dev
            steps:
              - name: checkout
                uses: actions/checkout@v4

              - name: Google Cloud Auth
                uses: "google-github-actions/auth@v2"
                with:
                  credentials_json: "${{ secrets.GOOGLE_CREDENTIALS }}"
                  project_id: ${{ vars.GCP_PROJECT_ID }}

              - name: Set up Cloud SDK
                uses: "google-github-actions/setup-gcloud@v2"

              - name: configure Docker
                run: gcloud auth configure-docker us-central1-docker.pkg.dev

              - name: Build
                env:
                  IMAGE_NAME: frontend
                  PROJECT_ID: ${{ vars.GCP_PROJECT_ID }}
                run: |-
                  docker build --build-arg VITE_BACKEND_BASE_URL=${{ secrets.VITE_BACKEND_URL }} -t us-central1-docker.pkg.dev/$PROJECT_ID/${{ vars.GCR_REPO_NAME }}/$IMAGE_NAME:latest -f frontend/Dockerfile frontend/.
                  docker push us-central1-docker.pkg.dev/$PROJECT_ID/${{ vars.GCR_REPO_NAME }}/$IMAGE_NAME:latest

              - name: Deploy to cloud run
                run: |
                  gcloud run deploy second-brain-fe \
                    --image us-central1-docker.pkg.dev/${{ vars.GCP_PROJECT_ID }}/${{ vars.GCR_REPO_NAME }}/frontend:latest \
                    --platform managed \
                    --port=80 \
                    --region us-central1 \
                    --allow-unauthenticated \
                    --set-env-vars "VITE_BACKEND_BASE_URL=${{secrets.VITE_BACKEND_URL}}"

Now let’s push code to run frontend pipeline. It got ran successfully and we got our frontend url but wait application will still not run.

as final step we need to add frontend url to backend end so our origin can identify for cors.

set new env to backend cloud run CORS_ORIGIN=”your frontend url” and your backend.yml will look like this.

        name: Backend Cloud Run Deployment

        on:
          push:
            branches:
              - development
            paths:
              - "backend/**"
          pull_request:
            paths:
              - "backend/**"

        jobs:
          build-and-push:
            runs-on: ubuntu-latest
            environment: dev
            steps:
              - name: checkout
                uses: actions/checkout@v4

              - name: Google Cloud Auth
                uses: google-github-actions/auth@v2
                with:
                  credentials_json: "${{ secrets.GOOGLE_CREDENTIALS }}"
                  project_id: ${{ vars.GCP_PROJECT_ID }}

              - name: Setup Cloud SDK
                uses: "google-github-actions/setup-gcloud@v2"

              - name: Configure Docker
                run: gcloud auth configure-docker us-central1-docker.pkg.dev

              - name: Build
                env:
                  IMAGE_NAME: backend
                  PROJECT_ID: ${{ vars.GCP_PROJECT_ID }}
                run: |-
                  docker build -t us-central1-docker.pkg.dev/$PROJECT_ID/${{ vars.GCR_REPO_NAME }}/$IMAGE_NAME:latest -f backend/Dockerfile backend/.
                  docker push us-central1-docker.pkg.dev/$PROJECT_ID/${{ vars.GCR_REPO_NAME }}/$IMAGE_NAME:latest

              - name: Deploy to Cloud Run
                run: |
                  gcloud run deploy second-brain-backend \
                      --image us-central1-docker.pkg.dev/${{ vars.GCP_PROJECT_ID }}/${{ vars.GCR_REPO_NAME }}/backend:latest \
                      --platform managed \
                      --port=8080 \
                      --region us-central1 \
                      --allow-unauthenticated \
                      --set-env-vars "MONGODB_URI=${{ secrets.MONGODB_URI }},ACCESS_TOKEN_SECRET=${{secrets.ACCESS_TOKEN_SECRET}},ACCESS_TOKEN_EXPIRY=1d,CORS_ORIGIN=https://second-brain-fe-475439396032.us-central1.run.app"

Now run backend pipeline and test your app.

You can also monitor using google cloud monitoring and can set alert for uptime.

If you have reached till here then Can you change your cloud run url to custom domain? If you need help then let me know, I will help out.

Conclusion : This project showcased the power and efficiency of deploying a React application using Google Cloud Run and GitHub Actions. By automating our CI/CD pipeline, we've achieved a streamlined workflow for building, testing, and deploying our application with minimal manual intervention. This setup ensures our application is always up-to-date and readily available to users.

While we've covered the essential steps, there's always room for improvement! Consider exploring advanced techniques like blue-green deployments for even smoother and risk-reduced releases. Happy coding!

More from this blog

Ajay Patel

116 posts