> ## Content Index
> Fetch the complete content index at: https://www.karls.io/llms.txt
> Use this file to discover other available public pages before exploring further.

# Deploying NestJS to Google Kubernetes Engine (GKE)
- URL: https://www.karls.io/google-kubernetes-engine-nestjs/
- Published: 2023-12-30T17:05:19.000Z
- Updated: 2025-12-15T18:32:05.000Z
- Description: In this tutorial you will learn how to build, deploy and serve NestJS application on Google Kubernetes Engine (GKE) and secure traffic over HTTPS.
- Author: Karl Scerbiakas
- Tags: NestJS, Cloud

## TL;DR of How To Deploy Nestjs App On GKE

- Dockerize the app
- Push to Artifact Registry on Google Cloud Platform (GCP)
- Configure a Kubernetes Ingress with a Google Managed Certificate.

This article shows how to achieve this 

## Table of contents

- [Introduction](#introduction)
- [Prerequisites](#prerequisites)
- [Dockerize](#dockerize)
- [Deployment](#deployment)
- [Service](#service)
- [Ingress](#ingress)
- [HTTPS](#https)
- [Conclusion](#conclusion)

## Introduction

Kubernetes, an open-source platform designed by Google and now maintained by the Cloud Native Computing Foundation, revolutionizes the way we deploy, scale, and manage containerized applications across clusters of machines. 

It automates various aspects of application deployment, scaling, and operations, enabling organizations to focus on their core product without worrying about the underlying infrastructure. NestJS, on the other hand, is a progressive Node.js framework for building efficient, reliable, and scalable server-side applications. By leveraging TypeScript and combining elements of Object-Oriented Programming, Functional Programming, and Functional Reactive Programming, NestJS provides an out-of-the-box application architecture that allows developers to create highly testable, scalable, loosely coupled, and easily maintainable applications. 

## Prerequisites

- `gcloud` installed. More info [here](https://cloud.google.com/sdk/docs/install?ref=karls.io).
- GKE cluster created. More info [here](https://cloud.google.com/kubernetes-engine/docs/how-to/creating-a-zonal-cluster?ref=karls.io). Make sure to authenticate `kubectl` against the cluster that has been created.  
`gcloud container clusters get-credentials <clustername> --zone <zone> --project <gcp-project>`
- Setup Google Artifact Registry repository created. More info [here](https://cloud.google.com/artifact-registry/docs/repositories/create-repos?ref=karls.io).

## Dockerize

Firstly you'd need a package your project into a docker container. As a starting point you can use the containerfile below. Place this file in the root of your project. 

💡

Note this dockerfile has hardcoded `PORT` 3000\. 

```shell
ARG NODE_VERSION=18.12.1-alpine 

FROM node:$NODE_VERSION AS development

WORKDIR /usr/src/app

COPY package.json ./
COPY package-lock.json ./
COPY tsconfig.json tsconfig.json
COPY nest-cli.json nest-cli.json

RUN npm install

COPY . .

RUN npm run build

FROM node:alpine as production

ARG NODE_ENV=production
ENV NODE_ENV=${NODE_ENV}

WORKDIR /usr/src/app

COPY package.json ./
COPY package-lock.json ./

RUN npm install --prod

COPY --from=development /usr/src/app/dist ./dist

EXPOSE 3000

CMD ["node", "dist/main"]
```

> *Note: In a real production environment, never run your container as* `root`*.* 

  
Now open your terminal and `cd` into the directory and build this container by running. 

💡

To be able to deploy your application to Google Kubernetes Engine (GKE) easiest way would be to push your built images to Google Cloud Artifact Registry. You can find on how to do it [here](https://cloud.google.com/artifact-registry/docs/docker/pushing-and-pulling?ref=karls.io). Replace LOCATION, PROJECT-ID, REPOSITORY and IMAGE with your settings. 

💡

If you are on MacOS and using Docker engine make sure to pass --platform linux/amd64 flag

```shell
docker build -t LOCATION-docker.pkg.dev/PROJECT-ID/REPOSITORY/IMAGE -f .
```

after build has successfully completed push image to Artifact Registry by running

```
docker push LOCATION-docker.pkg.dev/PROJECT-ID/REPOSITORY/IMAGE
```

## Deployment

To deploy to Kubernetes deployment file is required. It tells cluster how to create and manage your pods (containerized application) in the cluster. 

```yaml
     
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp
spec:
  strategy:
    type: RollingUpdate
    rollingUpdate:
      maxSurge: 1
      maxUnavailable: 0
  selector:
    matchLabels:
      app: whatabot
  template:
    metadata:
      labels:
        app: myapp
    spec:
      terminationGracePeriodSeconds: 10
      containers:
        - name: myapp
          image: LOCATION-docker.pkg.dev/PROJECT-ID/REPOSITORY/IMAGE #replace this with image URL
          imagePullPolicy: Always
          ports:
            - containerPort: 3000
              protocol: TCP
```

Apply with `kubectl apply -f <deployment-file>.yaml`  
This is very generic deployment file. Ways it can be improved: 

- Add health check
- Add readiness check
- Resource constraints

I skipped`resources`here for brevity, but**do not do this in production.**

Without**Memory Limits**, a single leak in your NestJS app can consume all available RAM, causing the OOM (Out Of Memory Error) to terminate your pod.

Without**CPU Limits**, a runaway loop can starve your other services. 

Start with`memory: "512Mi"`and`cpu: "250m"`for a standard NestJS deployment and tune from there.

## Join Devs Who Are Building Better Backend Systems

Get production-tested NestJS patterns, microservices insights,   
and GCP Cost hacks. 

Subscribe 

Email sent! Check your inbox to complete your signup. 

No spam. Unsubscribe anytime.

## Service

Service is a method for exposing a network application that is running as one or more Pods in your cluster. Entry point for the application in short. Service file is required to tell Kubernetes how to route traffic internally across its services. 

```yaml
apiVersion: v1
kind: Service
metadata:
  name: myapp
spec:
  type: ClusterIP
  ports:
    - targetPort: 3333
      port: 3000
  selector:
      app: myapp

```

apply by running `kubectl apply -f <service-file>.yaml`

To test if everything is working correctly on cluster side you can port forward and in browser if NestJS app is responding by running:  

```shell
kubectl port-forward svc/myapp 3333:3000
```

Now you can use browser or any Rest API client on port 3333 to test your application. All in all this step could be considered as done if you'd like to to consume your service internally. To make it publicly available on Google Cloud we'd need to create a LoadBalancer, create SSL and point the domain to newly created cluster. Feel free to follow along. 

## Ingress

To expose your application (service) over the internet you should use the ingress object. 

```yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: myapp #name of ingress
spec:
  rules:
  - http:
      paths:
      - path: /*
        pathType: ImplementationSpecific
        backend:
          service:
            name: myapp #name of your service object we created above. 
            port:
              number: 3000
```

And apply 

```shell
kubectl apply -f <ingress>.yaml
```

This will provision load balancer behind the scenes and it will take some time.   
Run this command to get IP address of a load balancer. 

```shell
kubectl get ingress myapp
```

Once you see an IP adress in the "ADDRESS" section you can visit browser. Traffic is served over HTTP and not HTTPS, so it's not much use for this. Let's expose our app via HTTPS. 

### HTTPS

Before starting delete the ingress created before. 

```shell
kubectl delete -f <ingress>.yaml
```

delete ingress

For this we will need a global IP address. We can get one by running `gcloud` command. 

```shell
gcloud compute addresses create <name-of-ip> --global
```

create global ip adress

Remember the name of IP address. 

To get IP actual address run following:  

```shell
gcloud compute addresses describe <name-of-ip> --global  
```

get IP address

Create a managed SSL certificate by applying following manifest.

```yaml
apiVersion: networking.gke.io/v1
kind: ManagedCertificate
metadata:
  name: myapp-cert #reference to our certificate in the cluster
spec:
  domains:
    - myapp.example.com #replace with your DNS
```

create a managed certificate

and adjust ingress object by adding annotations. 

```yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: myapp
  annotations:
    kubernetes.io/ingress.global-static-ip-name: myapp-ip #name of ip
    networking.gke.io/managed-certificates: myapp-cert #name of certificate 
spec:
  rules:
  - http:
      paths:
      - path: /*
        pathType: ImplementationSpecific
        backend:
          service:
            name: myapp #name of service to route traffic to
            port:
              number: 3000
```

Apply managed certificate and ingress manifests. While everything is provisioning make sure to point your domain `A` record to the global IP address you've created. After couple minutes visit your domain name and it should be secured by Google's Managed Certificate and be serving your traffic. 

## Conclusion

In this short tutorial we managed to build and deploy NestJS application to the Google Kubernetes Engine and secure it over HTTPS. Make sure to delete all resources if not used, because you will get charged.   
  
Also if you are interested in Kubernetes you might want to check out[ Cloud vs BareBones Kubernetes](https://www.karls.io/kubernetes-bare-metal-vs-cloud-bitcoin-k3s/) article too!

You can find code [here](https://github.com/kscerbiakas/gke-nestjs?ref=karls.io). If any questions - feel free to reach out!  

##