Deploying NestJS API to Cloud Run using Cloud Build

ajipandean

Muhamad Aji Pandean Mertayasa

Posted on August 2, 2021

Deploying NestJS API to Cloud Run using Cloud Build

NestJS is a NodeJS framework and deploying NodeJS API sometimes can be so challenging. Let's say for example you have VPS ready to be the place for your API to live. When you want to deploy your API to that VPS there are a lot of works to do. Starts from setting up environment for developing the API, then developing the actual API, configuring process manager like PM2, configuring web server like nginx and etc, etc. After a lot of works, finally your app is ready to serve.

Well, maybe some of you already get used to it, so it doesn't seems that complicated. But what about the beginner programmer? They definitely got intimidated by those steps to do (just like me in the past) :D. So if you feel the same like me in the past, then you in the right place.

Fortunately, at Google Cloud Next 2019, Google announced a serverless service where you can deploy your NodeJS API easily without worrying about ton of steps above. This service called Cloud Run.

Cloud Run basically is a fully-managed and highly scalable platform for deploying containerized app. Where "fully-managed" here means that Google takes care of the server for you, so you don't have to worry about managing and maintaining the server, and "highly scalable" here means that your service will be either increased or decreased dynamically based on the traffic to that service.

In this article, I will show you how to deploy your NodeJS API using NestJS to Google Cloud Run. We will use Docker for containerizing our application. So I assume that you have a bit knowledge of what Docker is or at least you have heard about it.

So, let's get started.


Create NestJS API

So first of all, let's create our brand new NestJS app by simply run the command below on your Terminal or Command Prompt for Windows.

$ npm i -g @nestjs/cli
$ nest new <your-app-name>
Enter fullscreen mode Exit fullscreen mode

After it finished, as you can see, there are a bunch of files generated automatically by NestJS. We are not going to touch any of these files. Instead, we want to test the API by simply running the command below.

$ yarn start:dev # if you choose yarn
$ npm run start:dev # if you choose npm
Enter fullscreen mode Exit fullscreen mode

Then you can visit [http://localhost:3000](http://localhost:3000) on your favorite browser and your should see Hello, world showing up on the screen.


Containerize NestJS API

As I mentioned before, Cloud Run is a service for deploying containerized app. It means that we should bundle our API into container by using Docker — it can be anything actually, but Docker is the most popular one — and then deploy that container to Cloud Run.

So in case you don't know what the container is, basically container just bundle our API along with its dependencies and environments, so the API that runs on Cloud Run has the same dependencies and environments with the API that runs on our local machine.

Okay enough theory, let's containerize our API.

So the first thing that we have to do for containerizing our API is creating a file called Dockerfile in the root of our project directory. Then just copy and paste code below into Dockerfile.

FROM node:erbium-alpine3.14

WORKDIR /app

COPY package.json .

RUN yarn

COPY . .

RUN yarn build

EXPOSE 3000
CMD [ "yarn", "start:prod" ]
Enter fullscreen mode Exit fullscreen mode

Let's take a look of what we just did here.

We just created a Dockerfile which is required by Docker to build image from an instructions that we wrote in that file.

Inside the Dockerfile we have a lot of stuff going on, let's cover them one by one.

  1. FROM node:erbium-alpine3.14 tells Docker that we are going to use node:erbium-alpine3.14 as our base image. So here, we don't have to install & configure NodeJS manually by ourselves.
  2. WORKDIR /app tells Docker to create a directory called /app and redirect us to that directory. It basically quite similar to mkdir /app && cd /app.
  3. COPY package.json . tells Docker to copy package.json file from our project on local computer to /app directory inside our container.
  4. RUN yarn tells Docker to install all dependencies needed for our API.
  5. COPY . . tells Docker to copy all files from our project on local computer to /app directory inside our container.
  6. RUN yarn build tells Docker to build our API.
  7. EXPOSE 3000 tells Docker to open port 3000 for external access.
  8. CMD [ "yarn", "start:prod" ] tells Docker to execute this command whenever we run our image.

Okay, we've created our Dockerfile but we still don't have image yet. Before we do that, since we are building NestJS app which is literally NodeJS, we have to ignore node_modules from being copied during building. Because, the size of node_modules is quite big and can slow down the performance of building an image.

In order to ignore some files or folders, we have to create another file called .dockerignore in the root of our project folder. After that, just copy and paste code below into .dockerignore.

node_modules/
.git/
Enter fullscreen mode Exit fullscreen mode

Now we're ready to build our image, in order to build Docker image, we just have to run command below.

$ docker build -t <image_name:tag> . 
Enter fullscreen mode Exit fullscreen mode

Let's cover above command one by one.

  1. docker build tells Docker to build our image based on Dockerfile.
  2. -t <image_name:tag> parameter used to specifies the name of the image and also tag (for versioning purpose) for our image.
  3. . this 'dot' sign refers to current directory where the Docker will look for Dockerfile to build an image.

Now you can test your image by running docker run command.

$ docker run -it -p 3000:3000 <image-name:tag>
Enter fullscreen mode Exit fullscreen mode

Then you can visit [http://localhost:3000](http://localhost:3000) and you should see the same result as before. But now your app runs on Docker container.

To stop the running container, just hit Ctrl + c.


Host our code to GitHub

Before we deploy our code to Cloud Run, let's host our code first to Github so that we can clone this code to Google Cloud Shell to perform deployment. You can do it by yourself, but in case you don't know how, just copy and paste bellow commands and run on your terminal.

$ git init
$ git add .
$ git commit -m "my api project, finished"
$ git remote add origin <your-repository-url>
$ git branch -M main
$ git push origin main
Enter fullscreen mode Exit fullscreen mode

Deploy to Cloud Run

Alright, now we have all the requirements we need.

We've created our API and also containerized it with the help of Docker. Now, we're ready to deploy our API to Cloud Run.

Well, it quite simple I think cause we just have to do few steps to complete it :D

Okay let's deploy.

In order to deploy our API to Cloud Run, we'll use Google Cloud service called Cloud Build. This service will automate our deployment to Cloud Run.

First of all, create new project on GCP Console. Then copy the ID of your project.

Then to use Cloud Build, we have to create another file in our root project directory called cloudbuild.yaml. Then copy and paste following code to your cloudbuild.yaml.

steps:
# Build the container image
- name: 'gcr.io/cloud-builders/docker'
  args: ['build', '-t', 'gcr.io/PROJECT_ID/IMAGE', '.']
# Push the container image to Container Registry
- name: 'gcr.io/cloud-builders/docker'
  args: ['push', 'gcr.io/PROJECT_ID/IMAGE']
# Deploy container image to Cloud Run
- name: 'gcr.io/google.com/cloudsdktool/cloud-sdk'
  entrypoint: gcloud
  args: ['run', 'deploy', 'SERVICE-NAME', '--image', 'gcr.io/PROJECT_ID/IMAGE', '--region', 'REGION', '--platform', 'managed', '--port', '3000']
images:
- gcr.io/PROJECT_ID/IMAGE
Enter fullscreen mode Exit fullscreen mode

That just template, customize to fit your case. Don't forget to add --port 3000 after --platform managed, since our app listen on port 3000.

The template code is available on Google Cloud Build documentation here. Just head on to there, scroll until you find "Building and deploying a container" title and read it what the meaning of the above code.

Now push your cloudbuild.yaml to GitHub.

$ git add .
$ git commit -m "added cloudbuild.yaml file"
$ git push origin main
Enter fullscreen mode Exit fullscreen mode

Back to your GCP Console, open Cloud Shell. Then make directory called whatever you want. I'll name it "projects" for now.

$ mkdir projects
$ cd projects
Enter fullscreen mode Exit fullscreen mode

Clone your code from GitHub that we just created earlier.

$ git clone <your-repository-url>
$ cd <your-project-name>
Enter fullscreen mode Exit fullscreen mode

Then finally run below command to deploy your API to Cloud Run.

$ gcloud builds submit
Enter fullscreen mode Exit fullscreen mode

If you got permission "run.service.get" error during gcloud builds submit you can go here and then enabled "Cloud Run Admin". After that, run again gcloud builds submit.

After it finished, go to Cloud Run dashboard, and click on the service that you just created.

Click "Permissions" tab and then click "+ Add".

For "New members" field, type allUsers and for "Role" field, select Cloud Run Invoker.

Click Save, then Allow Public Access and re-run gcloud builds submit.

We're done.


Alright, I think that's all for Deploy NestJS API to Cloud Run episode.

Well, this is my first article of my life. I know it's not perfect yet, I feel that :D but don't worry, I'll keep improving my writing skill.

Hopefully, you can get something new from this tutorial. Thanks for reading.

See you on the next article :D

💖 💪 🙅 🚩
ajipandean
Muhamad Aji Pandean Mertayasa

Posted on August 2, 2021

Join Our Newsletter. No Spam, Only the good stuff.

Sign up to receive the latest update from our blog.

Related