乐闻世界logo
搜索文章和话题

How to implement NestJS deployment and DevOps?

2月21日 17:11

NestJS Deployment and DevOps Explained

Deployment Overview

Deployment is the process of moving an application from development to production environment. NestJS applications can be deployed through various methods, including traditional servers, containerized deployment, cloud services, etc.

1. Docker Containerization

Create Dockerfile

dockerfile
# Build stage FROM node:18-alpine AS builder WORKDIR /app COPY package*.json ./ RUN npm ci COPY . . RUN npm run build # Production stage FROM node:18-alpine AS runner WORKDIR /app ENV NODE_ENV production COPY package*.json ./ RUN npm ci --only=production COPY --from=builder /app/dist ./dist EXPOSE 3000 CMD ["node", "dist/main.js"]

Create .dockerignore

shell
node_modules dist .git .env *.log

Build Docker Image

bash
docker build -t nestjs-app .

Run Docker Container

bash
docker run -p 3000:3000 nestjs-app

2. Docker Compose

docker-compose.yml

yaml
version: '3.8' services: app: build: . ports: - "3000:3000" environment: - NODE_ENV=production - DATABASE_HOST=db - DATABASE_PORT=3306 - DATABASE_USER=root - DATABASE_PASSWORD=password - DATABASE_NAME=nestjs depends_on: - db restart: unless-stopped db: image: mysql:8.0 environment: - MYSQL_ROOT_PASSWORD=password - MYSQL_DATABASE=nestjs ports: - "3306:3306" volumes: - mysql_data:/var/lib/mysql restart: unless-stopped volumes: mysql_data:

Start Services

bash
docker-compose up -d

3. Kubernetes Deployment

Deployment Configuration

yaml
apiVersion: apps/v1 kind: Deployment metadata: name: nestjs-app spec: replicas: 3 selector: matchLabels: app: nestjs-app template: metadata: labels: app: nestjs-app spec: containers: - name: nestjs-app image: nestjs-app:latest ports: - containerPort: 3000 env: - name: NODE_ENV value: "production" - name: DATABASE_HOST valueFrom: secretKeyRef: name: db-secret key: host resources: requests: memory: "256Mi" cpu: "250m" limits: memory: "512Mi" cpu: "500m" livenessProbe: httpGet: path: /health port: 3000 initialDelaySeconds: 30 periodSeconds: 10 readinessProbe: httpGet: path: /health port: 3000 initialDelaySeconds: 5 periodSeconds: 5

Service Configuration

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

Ingress Configuration

yaml
apiVersion: networking.k8s.io/v1 kind: Ingress metadata: name: nestjs-app-ingress annotations: nginx.ingress.kubernetes.io/rewrite-target: / spec: rules: - host: api.example.com http: paths: - path: / pathType: Prefix backend: service: name: nestjs-app-service port: number: 80

4. CI/CD Pipeline

GitHub Actions Configuration

yaml
name: CI/CD Pipeline on: push: branches: [ main, develop ] pull_request: branches: [ main ] jobs: test: runs-on: ubuntu-latest steps: - uses: actions/checkout@v3 - name: Setup Node.js uses: actions/setup-node@v3 with: node-version: '18' cache: 'npm' - name: Install dependencies run: npm ci - name: Run tests run: npm run test - name: Run lint run: npm run lint - name: Build run: npm run build build-and-push: needs: test runs-on: ubuntu-latest if: github.ref == 'refs/heads/main' steps: - uses: actions/checkout@v3 - name: Set up Docker Buildx uses: docker/setup-buildx-action@v2 - name: Login to Docker Hub uses: docker/login-action@v2 with: username: ${{ secrets.DOCKER_USERNAME }} password: ${{ secrets.DOCKER_PASSWORD }} - name: Build and push uses: docker/build-push-action@v4 with: context: . push: true tags: username/nestjs-app:latest,username/nestjs-app:${{ github.sha }} cache-from: type=registry,ref=username/nestjs-app:latest cache-to: type=inline deploy: needs: build-and-push runs-on: ubuntu-latest if: github.ref == 'refs/heads/main' steps: - name: Deploy to Kubernetes uses: azure/k8s-deploy@v4 with: manifests: | k8s/deployment.yaml k8s/service.yaml images: | username/nestjs-app:${{ github.sha }} kubeconfig: ${{ secrets.KUBE_CONFIG }}

GitLab CI Configuration

yaml
stages: - test - build - deploy variables: NODE_ENV: test test: stage: test image: node:18 script: - npm ci - npm run test - npm run lint cache: paths: - node_modules/ build: stage: build image: docker:latest services: - docker:dind script: - docker build -t $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA . - docker push $CI_REGISTRY_IMAGE:$CI_COMMIT_SHA only: - main deploy: stage: deploy image: bitnami/kubectl:latest script: - kubectl set image deployment/nestjs-app nestjs-app=$CI_REGISTRY_IMAGE:$CI_COMMIT_SHA only: - main

5. Environment Variable Management

Use .env Files

bash
# .env.production NODE_ENV=production PORT=3000 DATABASE_HOST=localhost DATABASE_PORT=3306 DATABASE_USER=root DATABASE_PASSWORD=password DATABASE_NAME=nestjs JWT_SECRET=your-secret-key

Use ConfigModule

typescript
import { Module } from '@nestjs/common'; import { ConfigModule } from '@nestjs/config'; @Module({ imports: [ ConfigModule.forRoot({ isGlobal: true, envFilePath: `.env.${process.env.NODE_ENV}`, }), ], }) export class AppModule {}

Kubernetes Secrets

yaml
apiVersion: v1 kind: Secret metadata: name: db-secret type: Opaque data: host: bG9jYWxob3N0 port: MzMwNg== user: cm9vdA== password: cGFzc3dvcmQ=

6. Health Checks

Health Check Endpoint

typescript
import { Controller, Get } from '@nestjs/common'; import { HealthCheck, HealthCheckService, TypeOrmHealthIndicator } from '@nestjs/terminus'; @Controller('health') export class HealthController { constructor( private health: HealthCheckService, private db: TypeOrmHealthIndicator, ) {} @Get() @HealthCheck() check() { return this.health.check([ () => this.db.pingCheck('database'), ]); } }

Kubernetes Health Checks

yaml
livenessProbe: httpGet: path: /health port: 3000 initialDelaySeconds: 30 periodSeconds: 10 timeoutSeconds: 5 failureThreshold: 3 readinessProbe: httpGet: path: /health port: 3000 initialDelaySeconds: 5 periodSeconds: 5 timeoutSeconds: 3 failureThreshold: 3

7. Log Management

Structured Logging

typescript
import { Logger } from '@nestjs/common'; export class AppService { private readonly logger = new Logger(AppService.name); async getData() { this.logger.log('Fetching data', { userId: 123, action: 'fetch' }); // Business logic } }

Use Winston

typescript
import { WinstonModule } from 'nest-winston'; import * as winston from 'winston'; @Module({ imports: [ WinstonModule.forRoot({ transports: [ new winston.transports.Console({ format: winston.format.combine( winston.format.timestamp(), winston.format.json(), ), }), new winston.transports.File({ filename: 'logs/error.log', level: 'error', }), new winston.transports.File({ filename: 'logs/combined.log', }), ], }), ], }) export class AppModule {}

8. Monitoring and Alerting

Use Prometheus

typescript
import { Controller, Get } from '@nestjs/common'; import { MetricsService } from './metrics.service'; @Controller('metrics') export class MetricsController { constructor(private metricsService: MetricsService) {} @Get() getMetrics() { return this.metricsService.getMetrics(); } }

Grafana Dashboard

yaml
apiVersion: v1 kind: ConfigMap metadata: name: grafana-dashboard data: dashboard.json: | { "dashboard": { "title": "NestJS Application", "panels": [ { "title": "Request Rate", "targets": [ { "expr": "rate(http_requests_total[5m])" } ] } ] } }

9. Load Balancing

Nginx Configuration

nginx
upstream nestjs_backend { server nestjs-app-1:3000; server nestjs-app-2:3000; server nestjs-app-3:3000; } server { listen 80; server_name api.example.com; location / { proxy_pass http://nestjs_backend; proxy_set_header Host $host; proxy_set_header X-Real-IP $remote_addr; } }

AWS ALB Configuration

yaml
Resources: LoadBalancer: Type: AWS::ElasticLoadBalancingV2::LoadBalancer Properties: Name: nestjs-alb Subnets: - !Ref SubnetA - !Ref SubnetB SecurityGroups: - !Ref SecurityGroup Type: application TargetGroup: Type: AWS::ElasticLoadBalancingV2::TargetGroup Properties: Name: nestjs-tg Port: 3000 Protocol: HTTP VpcId: !Ref VPC Targets: - Id: !Ref EC2Instance1 - Id: !Ref EC2Instance2

10. Disaster Recovery

Database Backup

bash
#!/bin/bash # backup.sh DATE=$(date +%Y%m%d_%H%M%S) BACKUP_DIR="/backups" DATABASE="nestjs" mysqldump -u root -p$MYSQL_ROOT_PASSWORD $DATABASE | gzip > $BACKUP_DIR/db_backup_$DATE.sql.gz # Keep backups from last 7 days find $BACKUP_DIR -name "db_backup_*.sql.gz" -mtime +7 -delete

Auto Scaling

yaml
apiVersion: autoscaling/v2 kind: HorizontalPodAutoscaler metadata: name: nestjs-hpa spec: scaleTargetRef: apiVersion: apps/v1 kind: Deployment name: nestjs-app minReplicas: 2 maxReplicas: 10 metrics: - type: Resource resource: name: cpu target: type: Utilization averageUtilization: 70 - type: Resource resource: name: memory target: type: Utilization averageUtilization: 80

Deployment Best Practices

  1. Environment Isolation: Separate development, testing, and production environments
  2. Automated Deployment: Use CI/CD to automate deployment processes
  3. Version Control: Include all configuration files in version control
  4. Monitoring and Alerting: Implement comprehensive monitoring and alerting mechanisms
  5. Backup Strategy: Regularly backup critical data
  6. Security Hardening: Implement security best practices
  7. Documentation: Maintain detailed deployment documentation
  8. Rollback Plan: Prepare quick rollback plans
  9. Performance Testing: Conduct performance testing before deployment
  10. Progressive Release: Use blue-green deployment or canary release

Summary

NestJS deployment and DevOps provides:

  • Flexible containerization solutions
  • Powerful orchestration support
  • Automated CI/CD processes
  • Comprehensive monitoring system
  • Reliable disaster recovery

Mastering deployment and DevOps is key to successfully delivering NestJS applications to production environments. By properly using containerization, orchestration, CI/CD, and monitoring tools, you can build high-availability, scalable production environments, ensuring stable operation and rapid iteration of applications.

标签:NestJS