Dockerize and Deploy a NodeJS Application to Cloud Run with GitHub Actions
Tags: docker, googlecloud, node
Published: 2023-10-05 08:27:24

Hello guys, in today's post, we will dockerize and deploy a NodeJS application to Cloud Run. This NodeJS app could be a backend app. It doesn't matter as long as it is a NodeJS Application. I won't go into any details about the application setup. I'm going to assume that you have already developed your application and you are looking at deploying the app.

Google Cloud Run is a powerful and flexible serverless computing platform that enables developers to run stateless containers without having to manage servers or infrastructure. Cloud Run is a fully managed service that takes care of provisioning and scaling your containers, so you can focus on building your application. To deploy an application to Cloud Run, you simply need to push a Docker image of the app to a container registry such as Google Container Registry or Docker Hub. Cloud Run will then automatically start running your application.

In today's post, we will dockerize a NodeJS app and deploy it to a Cloud Run service, we will consider the following;

- Setup Dockerfile 
- Setup Github Action to deploy to Cloud Run 
- Set up Google Cloud and Dockerhub accounts.
- Deploy the application and set up Cloud Run service.

## Setup Dockerfile

Let's set up a simple docker file that will define the steps for creating the container image. This file should be in the root level of 

```txt
FROM node:18

WORKDIR /usr/src/app

ENV PORT 8080

COPY package*.json ./

RUN npm install

COPY . .

RUN npm run build

CMD npm start
```
Let me quickly go over the Dockerfile 

FROM: This command specifies the base image for your Docker image. And in this instance, we are using the golang:1.18-alpine image.

WORKDIR: You set the working directory for your Docker image.

COPY: This command copies the necessary files from your local machine to the Docker image. This is the directory where your app resides.

RUN: This command specifies the commands required to build or configure the app.

CMD: This command specifies the commands that you want to run when the Docker image is started. Here we run the command to start the app.

Let's set up a GitHub action to build and deploy the container to dockerhub.

Inside the root folder of your app. Create a .github folder and inside that `.github` folder create another `workflows` folder finally inside the `workflows` folder create a `build.yaml` file and paste the following content 

```yaml
name: Lint and Dockerize the app

on:
  push:
    branches: [master]
  pull_request:
    branches: [master]

env:
  # Use docker.io for Docker Hub if empty
  REGISTRY: docker.io
  # github.repository as <account>/<repo>
  IMAGE_NAME: ${{ github.repository }}

jobs:
  build:
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write

    steps:
      - name: Checkout repository
        uses: actions/checkout@v2

      - name: Set up Google Cloud
        uses: google-github-actions/setup-gcloud@v0.6.0
        with:
          project_id: ${{ secrets.GCP_PROJECT_ID }}
          service_account_key: ${{ secrets.GCP_SA_KEY }}

      # Login against a Docker registry except on PR
      # https://github.com/docker/login-action
      - name: Log into registry ${{ env.REGISTRY }}
        # if: github.event_name != 'pull_request'
        uses: docker/login-action@v1
        with:
          username: ${{ secrets.DOCKER_USERNAME }}
          password: ${{ secrets.DOCKER_PASSWORD }}

      # Extract metadata (tags, labels) for Docker
      # https://github.com/docker/metadata-action
      #- name: Extract Docker metadata
      #  id: meta
      #  uses: docker/metadata-action@98669ae865ea3cffbcbaa878cf57c20bbf1c6c38
      #  with:
      #    images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}

      # Build and push Docker image with Buildx (don't push on PR)
      # https://github.com/docker/build-push-action
      - name: Build and push Docker image
        uses: docker/build-push-action@v2
        with:
          context: ./
          tags: ${{ secrets.DOCKER_USERNAME }}/magga:latest
          push: true
          file: ./Dockerfile

      - name: Image digest
        run: echo 
```

I will not go over the GitHub action file due to the time limit, but here are some things we can draw from that.

- You need to have a docker hub account.
- You need to have a project on Google Cloud.

Go ahead and create a Google Cloud account. When you're done or if you already have a Google Cloud account set up a project and copy your project ID. Next, you need to create a service account and copy the key for your service account. Go to your Github account and set up a new remote repository. On the settings page for the remote repository add the following secrets for your Github actions. `GCP_PROJECT_ID` should have a value equal to your project ID on Google Cloud.  Next use the IAM service to generate a service account, generate a q key for that service account then copy and add a new repository secrete and add a new secrete `GCP_SA_KEY`.

Next, create a dockerhub account if you've not created one before then copy your username and password and add them as repository secrets. Your username should be saved to a variable `DOCKER_USERNAME` while your password should be saved to `DOCKER_PASSWORD`.

## Deploy the application

To deploy your application simply push it up to the remote GitHub repository you created. You should see the GitHub actions started right away and you can view it in the actions tab on the repository. Once the action is completed successfully, go to your GCP and create a new Cloud Run service, make sure to select the image URL for your container from Dockerhub. Use this as the image URL for the Cloud Run Service, and ensure you configure all of the necessary settings for the image. Which shouldn't be much. Just accept the defaults then launch the service. 

You should see the URL for viewing your app on your service dashboard, you can make a query to this URL to test that everything deployed successfully. That's how you deploy a NodeJS application with GitHub and Google Cloud Run. Leave your thoughts about this approach in the comment section and I hope you found this useful, I will see you in the next one.