DEV Community 👩‍💻👨‍💻

Cover image for Deploy a React App on GCP with Google Cloud Run
Johannes Vitt
Johannes Vitt

Posted on

Deploy a React App on GCP with Google Cloud Run

So you have created your first React project and now you are ready to try to deploy it? Fear not, Google offers Cloud Run, a very simple but powerful tool that helps you do just that. I will show you in three simple steps, how you can deploy a containerized React app with Cloud Run.

This tutorial assumes you have already setup your Google Cloud Project and have your React app running locally.

Can I simply upload my code into a bucket?

When I tried to deploy my first React project, I was already experienced with Cloud Run for various other projects. When I wanted to deploy the app to GCP, my first idea was to run a simple npm run build... and upload the compiled output folder into a Google Cloud Storage (GCS) bucket.

After I was done, I realized that this approach would not work. GCS is trying to serve all routes from a path inside the bucket. So if you create a page /login in React, GCS will try to serve a file located inside the subfolder of the GCS bucket. This will fail, because no such file exists. React is supposed to handle the routing client side. More info on this can be found here.

The "easiest" way to achieve a working routing is to use Google App Engine. However, I find App Engine not very scalable for multiple reasons. The major issue I faced is that the location of your App Engine can not be changed once it was activated for a project (Why?), and you can only have one App Engine location for the whole project.

Cloud Run

The better solution to go with is Google Cloud Run. Cloud Run is actually based on Knative, a "Kubernetes-based platform to deploy and manage modern serverless workloads". The main benefit of Knative is that it makes scaling of any stateless applications very easy. You simply provide a docker image and Knative will scale it up to as many instances as needed.

In comparison to directly running Knative your own Kubernetes cluster, Cloud Run is easier to set up and maintain. It is also very cheap for projects, where you expect a small load of traffic, because Cloud Run is billed per usage (e.g. per request to the service). Another advantage of Cloud Run is the ability to revert your deployments within less than 10s. This feature saved me some headaches in the startup that I worked with.

1. Create a docker image that contains your compiled React app

You need to create a file Dockerfile in the root directory of your project. We will use a multi-stage docker file in this step so be sure to copy all of the following code into a single file.

FROM node:lts-alpine as builder

# by only copying package.json, before running npm install. We can leverage dockers caching strategy for steps. Otherwise docker needs to run npm install every time you change any of the code.
COPY package.json ./
RUN npm install
RUN mkdir /app-ui
RUN mv ./node_modules ./app-ui
WORKDIR /app-ui
COPY . .
# in this step the static React files are created. For more info see package.json
RUN npm run build

Enter fullscreen mode Exit fullscreen mode

After running the builder we have all our static files available. However we still need a way of serving them to the client. We use nginx for this.

FROM nginx:alpine

# copy the .conf template
COPY ./.nginx/nginx.conf /etc/nginx/nginx.conf

## Remove default nginx index page and replace it with the static files we created in the first step
RUN rm -rf /usr/share/nginx/html/*
COPY --from=builder /app-ui/build /usr/share/nginx/html
EXPOSE 80

CMD nginx -g 'daemon off;'
Enter fullscreen mode Exit fullscreen mode

In the first stage of the docker file (the "build" stage), we call the "build" script. This needs to be defined in your package.json. It triggers the compilation of your react code.

{
  ...
  "scripts": {
    "start": "react-scripts start",
    "build": "react-scripts build",
    ...
  }
  ...
}
Enter fullscreen mode Exit fullscreen mode

In the second stage of the docker file, we copy the configuration file of nginx into the server. So please create a file .nginx/nginx.conf with the following content.

worker_processes 4;

events { worker_connections 1024; }

http {
    server {
        listen 80;

        gzip on;
        gzip_disable "msie6";

        gzip_comp_level 6;
        gzip_min_length 1100;
        gzip_buffers 16 8k;
        gzip_proxied any;
        gzip_types
            text/plain
            text/css
            text/js
            text/xml
            text/javascript
            application/javascript
            application/json
            application/xml
            application/rss+xml
            image/svg+xml;

        root   /usr/share/nginx/html;
        index  /index.html;
        include /etc/nginx/mime.types;

        location / {
            try_files $uri $uri/ /index.html;
        }
    }
}
Enter fullscreen mode Exit fullscreen mode

In the configuration the line try_files $uri $uri/ /index.html; tells the server to try to locate the requested file in the /usr/share/nginx/html directory. If it is not found we serve the index.html file.

2. Upload the Docker Image to Google Container Registry

In the terminal navigate to your projects root folder and run

gcloud builds submit --tag gcr.io/<your-project-id>/react-with-cloudrun
Enter fullscreen mode Exit fullscreen mode

This will build the docker image using the Dockerfile that you have created in the previous step and upload it to the Container Registry.

3. Create the Cloud Run service

Navigating to Cloud Run in the GCP console
In the Google Cloud Console, navigate to the Cloud Run overview. There, create a new service. During the creation of the service select the image you uploaded in the previous step. Choose the port 80 because this is where our NGINX server is listening.
Creating a new Cloud Run Service

4. (Optional) Map your custom domain to the service

If you own a domain and want to make your React app available with that domain you can set it up with Cloud Run.

Image description

Image description

Where to go from here

You have successfully deployed your React app with Cloud Run!

As a next step you can try to set up an automated CI/CD pipeline with Google Cloud Build. It fits perfectly with Cloud Run and Docker images.

Instead of using the web GUI to create and manage the resources of Google Cloud Platform, you can also start using Terraform.

When you have multiple services running in Cloud Run, Google Cloud Load Balancing offers an efficient way of routing requests.

Top comments (0)

👋 New to DEV?

Head over to our Welcome Thread and tell us a bit about yourself!