Muhamad Aji Pandean Mertayasa
Posted on August 2, 2021
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>
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
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" ]
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.
-
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. -
WORKDIR /app
tells Docker to create a directory called/app
and redirect us to that directory. It basically quite similar tomkdir /app && cd /app
. -
COPY package.json .
tells Docker to copy package.json file from our project on local computer to/app
directory inside our container. -
RUN yarn
tells Docker to install all dependencies needed for our API. -
COPY . .
tells Docker to copy all files from our project on local computer to/app
directory inside our container. -
RUN yarn build
tells Docker to build our API. -
EXPOSE 3000
tells Docker to open port 3000 for external access. -
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/
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> .
Let's cover above command one by one.
-
docker build
tells Docker to build our image based on Dockerfile. -
-t <image_name:tag>
parameter used to specifies the name of the image and also tag (for versioning purpose) for our image. -
.
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>
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
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
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
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
Clone your code from GitHub that we just created earlier.
$ git clone <your-repository-url>
$ cd <your-project-name>
Then finally run below command to deploy your API to Cloud Run.
$ gcloud builds submit
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
Posted on August 2, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.