Deployment: Deploying a NestJS Application

Deploying a NestJS application to a cloud platform (e.g., AWS, Google Cloud, Azure) or a containerized environment (e.g., Docker, Kubernetes).


Deploying NestJS Applications to Kubernetes

This document provides a guide to deploying a NestJS application to a Kubernetes cluster, covering essential aspects such as creating deployment and service manifests, handling ingress, and implementing service discovery. We'll assume a basic understanding of Kubernetes concepts.

Understanding the Deployment Process

Deploying a NestJS application to Kubernetes involves several key steps:

  1. Containerization: Packaging the NestJS application into a Docker container.
  2. Manifest Creation: Defining Kubernetes resources (Deployment, Service, Ingress) using YAML manifests.
  3. Deployment: Applying the manifests to the Kubernetes cluster.
  4. Monitoring and Management: Observing and managing the deployed application.

1. Containerizing Your NestJS Application

Before deploying to Kubernetes, your NestJS application needs to be packaged into a Docker container. Here's an example Dockerfile:

 # Dockerfile
FROM node:18-alpine AS builder

WORKDIR /app

COPY package*.json ./
RUN npm install --only=production

COPY . .

RUN npm run build

FROM node:18-alpine

WORKDIR /app

COPY --from=builder /app/package*.json ./
RUN npm install --only=production

COPY --from=builder /app/dist ./dist

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

Explanation:

  • The Dockerfile uses multi-stage builds for smaller image sizes.
  • It installs only production dependencies.
  • It copies the built NestJS application (dist folder) into the final image.
  • The CMD instruction specifies how to start the application.

Build the Docker image:

 docker build -t my-nestjs-app . 

Push the image to a container registry (Docker Hub, Google Container Registry, AWS ECR, etc.):

 docker tag my-nestjs-app your-dockerhub-username/my-nestjs-app:latest
docker push your-dockerhub-username/my-nestjs-app:latest 

2. Creating Kubernetes Deployment Manifest

The Deployment manifest defines how the application containers are deployed and managed within the Kubernetes cluster.

 # deployment.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nestjs-app-deployment
  labels:
    app: my-nestjs-app
spec:
  replicas: 3  # Adjust as needed
  selector:
    matchLabels:
      app: my-nestjs-app
  template:
    metadata:
      labels:
        app: my-nestjs-app
    spec:
      containers:
      - name: my-nestjs-app
        image: your-dockerhub-username/my-nestjs-app:latest
        ports:
        - containerPort: 3000 # NestJS application port
        env:
        # Environment variables for your NestJS application
        - name: NODE_ENV
          value: production
        # Example DB connection string
        - name: DATABASE_URL
          valueFrom:
            secretKeyRef:
              name: my-db-secret
              key: connection-string
        resources:
          requests:
            cpu: 100m
            memory: 128Mi
          limits:
            cpu: 500m
            memory: 256Mi 

Explanation:

  • replicas: Specifies the desired number of application instances. Adjust based on traffic.
  • selector: Matches the labels on the pods to be managed by this deployment.
  • template: Defines the pod specification, including the container image, ports, and environment variables.
  • env: Sets environment variables for the NestJS application. Use valueFrom with secretKeyRef to retrieve sensitive information from Kubernetes Secrets.
  • resources: Defines the resource requests and limits for the container. Important for preventing resource starvation. Adjust based on your application's needs.

3. Creating Kubernetes Service Manifest

The Service manifest exposes the application within the Kubernetes cluster. It allows other applications to access the NestJS application.

 # service.yaml
apiVersion: v1
kind: Service
metadata:
  name: my-nestjs-app-service
spec:
  selector:
    app: my-nestjs-app
  ports:
    - protocol: TCP
      port: 80 # Service port
      targetPort: 3000 # Container port
  type: ClusterIP # Exposes the service on a cluster-internal IP.  Only reachable from within the cluster. 

Explanation:

  • selector: Matches the labels on the pods to be targeted by this service.
  • ports: Defines the port mapping between the service and the target pods.
  • type: ClusterIP: Creates a ClusterIP service, accessible only from within the cluster. This is the most common type for internal services. Other types are `NodePort` (access from outside the cluster on each node's IP) and `LoadBalancer` (automatically provisions a load balancer in cloud environments).

4. Ingress for External Access

To expose the NestJS application to the outside world, you need an Ingress resource. Ingress acts as a reverse proxy and load balancer, routing external traffic to the correct service within the cluster.

You'll need an Ingress controller deployed in your cluster (e.g., Nginx Ingress Controller) before creating Ingress resources.

 # ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-nestjs-app-ingress
  annotations:
    kubernetes.io/ingress.class: nginx # Replace with your ingress controller class
spec:
  rules:
  - host: my-nestjs-app.example.com # Replace with your domain
    http:
      paths:
      - path: /
        pathType: Prefix
        backend:
          service:
            name: my-nestjs-app-service
            port:
              number: 80 # Service port 

Explanation:

  • kubernetes.io/ingress.class: Specifies the Ingress controller to use. Common values include nginx, traefik, etc.
  • host: The domain name that will be used to access the application. Configure DNS to point to your Ingress controller.
  • path: The URL path to route to the service. / routes all requests to the service.
  • backend: Specifies the service and port to which the traffic should be routed.

5. Service Discovery

Kubernetes provides built-in service discovery through DNS. Within the cluster, you can access the NestJS application using its service name (my-nestjs-app-service) as a hostname.

For example, if you have another service within the cluster that needs to communicate with the NestJS application, it can use the following URL:

 http://my-nestjs-app-service:80 

6. Applying the Manifests

Use kubectl apply to deploy the resources to your Kubernetes cluster:

 kubectl apply -f deployment.yaml
kubectl apply -f service.yaml
kubectl apply -f ingress.yaml 

7. Monitoring and Management

Use kubectl commands to monitor the deployment:

 kubectl get deployments
kubectl get services
kubectl get pods
kubectl get ingress
kubectl logs -f <pod-name> # View pod logs 

Consider using a monitoring solution like Prometheus and Grafana for more advanced monitoring and alerting.

Important Considerations

  • Secrets Management: Use Kubernetes Secrets to store sensitive information (database credentials, API keys, etc.) and avoid hardcoding them in your manifests.
  • Health Checks: Implement liveness and readiness probes in your NestJS application and configure them in your Deployment manifest. This allows Kubernetes to automatically restart unhealthy pods and ensure traffic is only routed to healthy instances.
  • Resource Limits: Carefully configure resource requests and limits for your containers to prevent resource contention and ensure application stability.
  • Persistent Storage: If your NestJS application requires persistent storage (e.g., for file uploads), consider using Kubernetes Persistent Volumes and Persistent Volume Claims.
  • CI/CD Pipeline: Automate the build, testing, and deployment process using a CI/CD pipeline (e.g., Jenkins, GitLab CI, GitHub Actions).