NodeJS Continuous Deployment in Google Cloud with Kubernetes & Container Builder
Tags: devops, kubernetes, node, docker
Published: 2019-03-17 23:11:59

---
title: NodeJS Continuous Deployment in Google Cloud with Kubernetes & Container Builder
published: true
description: create an easy to use CD for your node application with container builder and kubernetes engine in google cloud
tags: devops, kubernetes, node, docker
cover_image: https://thepracticaldev.s3.amazonaws.com/i/vpoa739ikww30a8gvso4.png
---

So you  want your app to be deployed to your Kubernetes Cluster without caring about any manual step?
I got you covered, it's super simple to create a Continuous Deployment Pipeline with Google Cloud.
For the sake of understanding I choose an NodeJS Express Application, but it also works with react or PHP or any other application layer.

Let's get started:

## Because IAM admin

First we need to give the container builder the rights to access our Kubernetes API. Remember this does not give access to a certain cluster. It just allows the cloudbuilder service account to access our Kubernetes Cluster. So jump to the [IAM settings page](https://console.cloud.google.com/iam-admin/iam?) and look for the cloudbuild service account. If it does not exist you might have to enable the [cloudbuild API](https://console.cloud.google.com/cloud-build/)

It should look like this
![cloud build service account](https://thepracticaldev.s3.amazonaws.com/i/fuo41i04jht1xlcrof1n.png)

We need to add the rights to access the Kubernetes API of our clusters so klick on the pen and look for the following.

![Kubernetes API access rights](https://thepracticaldev.s3.amazonaws.com/i/23xzi970t9u3gw2fammn.png)
 

## Prepare the application

I won't go into details on how to setup an express application and introduce testing to it. 
I created a repository with the sample application, that we can use
{% github https://github.com/mfahlandt/gcp-continuous-deployment-node-demo %}

To give you an overview, we have a basic express app with 2 backend routes to retrieve users or and user by id.
Also we have a test folder that have tests for the two routes in it. These tests are written with the help of chai and mocha. 
If you download the repository you can do the following to see if the tests are working.


```javascript

npm install
npm test

```

Before the app can run we need the service and the deployment in the Kubernetes Cluster. So let's quickly create a service and a deployment. All of the files you also can find in the repository.

```

apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: server-production
  labels:
    app: YOUR-PROJECT-ID
spec:
  replicas: 2
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 1
  template:
    metadata:
      labels:
        app: server
    spec:
      containers:
        - name: server
          image: gcr.io/PROJECT_ID/REPOSITORY:master
          imagePullPolicy: Always
          ports:
            - containerPort: 3000
          env:
            - name: NODE_ENV
              value: "production"

```

The only important part here is that you change the project id and the repository to the path that the repository will have.

After this we only need a service to expose our app to the internet. So quickly apply the service.

```

kind: Service
apiVersion: v1
metadata:
  name:  server
spec:
  selector:
    app:  server
  ports:
    - name:  server
      protocol: TCP
      port: 80
      targetPort: 3000
  type: LoadBalancer

```



## Ready to deploy

Now we need to go to the most important part of the whole Setup. The cloudbuild.yaml. There we will define everything for our continuous deployment steps.

The first amazing part will be, that it is possible to put all of the important data in environment variables defined in the build, so you can use the cloud build for different setups.

First we install all of the node dependencies and run the test. 

```

  - name: 'gcr.io/cloud-builders/npm'
    args: ['install']
  - name: 'gcr.io/cloud-builders/npm'
    args: ['run', 'test']

```

After this we build a docker image with all the repositories files inside and a proper defined environment, so you can easily do a staging deployment as well, or even branch deployment. And we push it to the google image repository.


```

  - name: 'gcr.io/cloud-builders/docker'
    args:
      - build
      - '--build-arg'
      - 'buildtime_variable=$_NODE_ENV'
      - '-t'
      - gcr.io/$PROJECT_ID/$REPO_NAME:$BUILD_ID
      - '.'
  - name: 'gcr.io/cloud-builders/docker'
    args: ['push', 'gcr.io/$PROJECT_ID/$REPO_NAME:$BUILD_ID']

```

Also important to see, we tag the image with the unique build id to make use of the apply ability of kubernetes, so the image is actually changed.


```

  - name: 'gcr.io/cloud-builders/kubectl'
    args:
      - set
      - image
      - deployment
      - $_DEPLOYMENT
      - $_DEPLOYMENT=gcr.io/$PROJECT_ID/$REPO_NAME:$BUILD_ID
    env:
      - 'CLOUDSDK_COMPUTE_ZONE=$_CLUSTER_ZONE'
      - 'CLOUDSDK_CONTAINER_CLUSTER=$_CLUSTER_NAME'

```

And finally we set the image in the kubernetes cluster. BAM! Commit hook, automated testing, if successful automated deployment, no downtime. 


Now we open [the container builder trigger](https://console.cloud.google.com/cloud-build/triggers/add) and choose where our code is located.

![create trigger](https://thepracticaldev.s3.amazonaws.com/i/k21b5ghqguxa5lyk59zq.png)


In the last trigger step we now can add the custom variables. This is the first point where we actually define the cluster. So everything is aggregated at one place and ready to go.

![create trigger part 2](https://thepracticaldev.s3.amazonaws.com/i/n3avd0br94aosba1x20z.png)


Now we just need to commit to the master and the trigger is started.

![Build successful](https://thepracticaldev.s3.amazonaws.com/i/17nn3i98r2eym3mmjyy6.png)


YIHA now we have continuous deployment, without setting up any extra services like jenkins, ant or chef. Pretty amazing


I'm thinking of creating a tutorials series from zero to hero in cloud are you interested? drop me a comment!