Maison  >  Article  >  interface Web  >  Déployer NextJs et NestJs en tant qu'application unique

Déployer NextJs et NestJs en tant qu'application unique

WBOY
WBOYoriginal
2024-09-10 11:34:47961parcourir

Salut ! Je suis ravi de partager comment vous pouvez configurer NestJS pour qu'il fonctionne de manière transparente sur un seul hôte. Mais d'abord, laissez-moi vous expliquer pourquoi cette configuration est mon premier choix pour gérer à la fois le frontend et le backend depuis si longtemps.

Next.js est une centrale électrique lorsqu'il s'agit de lancer de nouveaux projets. Il est livré avec des fonctionnalités telles que le routage intégré, le rendu côté serveur (SSR) et la mise en cache qui vous aident à démarrer. De plus, Next.js possède ses propres capacités API internes, vous permettant de gérer des tâches telles que la mise en cache et la préparation des données directement dans le cadre. Cela signifie que vous pouvez vous concentrer davantage sur la création de votre application et moins sur la configuration de l'infrastructure.

Mais parfois, vous avez besoin de quelque chose de plus puissant pour le serveur. C'est là qu'intervient Nest.js. Ce framework est si puissant qu'il peut non seulement gérer les tâches de middleware entre votre backend et votre frontend, mais peut également agir comme une solution backend robuste à elle seule. Par conséquent, NestJS est un bon ajout à Next.js dans ce cas, permettant d'utiliser un seul langage de programmation pour le frontend et le backend.

Pourquoi un seul hébergeur ?

En termes simples, c’est incroyablement pratique. Avec juste un git pull et un docker-compose up -d, vous êtes prêt à partir. Il n'y a pas besoin de s'inquiéter du CORS ou de jongler avec les ports. De plus, il rationalise le processus de livraison, rendant tout plus fluide et plus efficace. Comme inconvénient, je peux souligner que cela ne convient pas aux gros projets avec une charge élevée.

1. Tout d'abord, définissons la structure des dossiers de votre référentiel

Deploy NextJs and NestJs as a single application

2. Déclarons un fichier docker pour le serveur

Fichier : ./docker-compose.yml

services:
    nginx:
        image: nginx:alpine
        ports:
            - "80:80"
        volumes:
            - "./docker/nginx/conf.d:/etc/nginx/conf.d"
        depends_on:
            - frontend
            - backend
        networks:
            - internal-network
            - external-network

    frontend:
        image: ${FRONTEND_IMAGE}
        restart: always
        networks:
            - internal-network

    backend:
        image: ${BACKEND_IMAGE}
        environment:
            NODE_ENV: ${NODE_ENV}
            POSTGRES_HOST: ${POSTGRES_HOST}
            POSTGRES_USER: ${POSTGRES_USER}
            POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
            POSTGRES_DB: ${POSTGRES_DB}
        depends_on:
            - postgres
        restart: always
        networks:
            - internal-network

    postgres:
        image: postgres:12.1-alpine
        container_name: postgres
        volumes:
            - "./docker/postgres:/var/lib/postgresql/data"
        environment:
            POSTGRES_USER: ${POSTGRES_USER}
            POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
            POSTGRES_DB: ${POSTGRES_DB}
        ports:
            - "5432:5432"

networks:
    internal-network:
        driver: bridge

    external-network:
        driver: bridge

En termes simples, c’est incroyablement pratique. Avec juste un git pull et un docker-compose up -d, vous êtes prêt à partir. Il n'y a pas besoin de s'inquiéter du CORS ou de jongler avec les ports. De plus, il rationalise le processus de livraison, rendant tout plus fluide et plus efficace. Comme inconvénient, je peux souligner que cela ne convient pas aux gros projets avec une charge élevée.

3. Un autre fichier docker pour le mode développement

Pour le mode développement, nous n'avons pas besoin de service de conteneur pour le backend et le frontend car nous les exécuterons localement.

Fichier : ./docker-compose.dev.yml

version: '3'

services:
    nginx:
        image: nginx:alpine
        ports:
            - "80:80"
        volumes:
            - "./docker/nginx/conf.d:/etc/nginx/conf.d"

    postgres:
        image: postgres:12.1-alpine
        container_name: postgres
        volumes:
            - "./docker/postgres:/var/lib/postgresql/data"
        environment:
            POSTGRES_USER: postgres
            POSTGRES_PASSWORD: postgres
            POSTGRES_DB: postgres
        ports:
            - "5432:5432"

4. Fichier Docker pour le backend

Fichier : ./backend/Dockerfile

FROM node:18-alpine AS deps
RUN apk add --no-cache libc6-compat
WORKDIR /app

COPY package.json package-lock.json ./
RUN  npm install

FROM node:18-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .

ENV NEXT_TELEMETRY_DISABLED 1

RUN npm run build

FROM node:18-alpine AS runner
WORKDIR /app

ENV NODE_ENV production
ENV NEXT_TELEMETRY_DISABLED 1

RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs

COPY --from=builder --chown=nextjs:nodejs /app/dist ./dist
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./package.json

RUN mkdir -p /app/backups && chown -R nextjs:nodejs /app/backups && chmod -R 777 /app/backups

USER nextjs

EXPOSE 3010

ENV PORT 3010

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

## 5. Docker file for frontend
File: ./frontend/Dockerfile

FROM node:18-alpine AS deps
RUN apk add --no-cache libc6-compat
WORKDIR /app

COPY package.json package-lock.json ./
RUN  npm install

FROM node:18-alpine AS builder
WORKDIR /app
COPY --from=deps /app/node_modules ./node_modules
COPY . .

ENV NEXT_TELEMETRY_DISABLED 1

RUN npm run build

FROM node:18-alpine AS runner
WORKDIR /app

ENV NODE_ENV production
ENV NEXT_TELEMETRY_DISABLED 1

RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs

COPY --from=builder --chown=nextjs:nodejs /app/.next ./.next
COPY --from=builder --chown=nextjs:nodejs /app/public ./public
COPY --from=builder /app/node_modules ./node_modules
COPY --from=builder /app/package.json ./package.json

USER nextjs

EXPOSE 3000

ENV PORT 3000

CMD ["npm", "start"]

6. Configuration de Ngnix

Dans cette étape, nous configurons Nginx pour qu'il agisse comme un proxy inverse pour notre frontend Next.js et notre backend Nest.js. La configuration Nginx vous permet d'acheminer les requêtes de manière transparente entre le frontend et le backend, tout en les servant à partir du même hôte.

Fichier : /docker/nginx/conf.d/default.conf

server {
    listen 80;

    location / {
        proxy_pass http://host.docker.internal:3000;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }

    location /api {
        proxy_pass http://host.docker.internal:3010;
        proxy_set_header Host $host;
        proxy_set_header X-Real-IP $remote_addr;
        proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
        proxy_set_header X-Forwarded-Proto $scheme;
    }
}

Cette configuration écoute sur le port 80 et achemine le trafic général vers le frontend Next.js sur le port 3000, tandis que toutes les requêtes vers /api sont transmises au backend Nest.js sur le port 3010.

7. Prédicte global NestJs

Puisque nous utilisons le même hôte, nous avons besoin que NestJs soit disponible sur /apipath. Pour ce faire, nous devons définirGlobalPrefix — API.

Fichier : ./backend/src/main.js

import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create(AppModule, { cors: true  });
  app.setGlobalPrefix('api');
  await app.listen(3010);
}
bootstrap();

8. Front-end

Aucune configuration n'est requise sur le frontend mais seulement en tenant compte du fait que toutes les requêtes du serveur doivent être appelées par rapport au chemin /api.

9. Exécutez localement

interface cd
npm exécuter le développement
cd ../backend
npm run start:dev
cd ../
docker-compose -f docker-compose.dev.yml up -d

Maintenant, nous pouvons consulter notre site Web en ouvrant localhost dans le navigateur. Dans l'exemple, nous avons 1 requête sur le serveur et une autre sur le client. Ces deux requêtes sont appelées depuis Next.Js et traitées par Nest.Js.

Deploy NextJs and NestJs as a single application

10. Déployer et exécuter sur le serveur via GitHub

Cet article explique comment déployer un projet sur un serveur à l'aide de Docker Registry et de GitHub Actions. Le processus commence par la création d'images Docker pour le backend et le frontend dans le registre Docker. Après cela, vous devrez configurer un référentiel GitHub et configurer les secrets nécessaires pour un déploiement transparent :

DOCKERHUB_USERNAME
DOCKERHUB_TOKEN
DOCKER_FRONTEND_IMAGE
DOCKER_BACKEND_IMAGE
REMOTE_SERVER_HOST
REMOTE_SERVER_USERNAME
REMOTE_SERVER_SSH_KEY
REMOTE_SERVER_SSH_PORT

L'inconvénient de l'utilisation d'un seul référentiel pour le backend et le frontend est que chaque fois que vous poussez quelque chose, les deux images sont reconstruites. Pour l'optimiser nous pouvons utiliser ces conditions :

if: contains(github.event_name, ‘push’) && !startsWith(github.event.head_commit.message, ‘frontend’)
if: contains(github.event_name, ‘push’) && !startsWith(github.event.head_commit.message, ‘backend’)

Il permet de reconstruire uniquement l'image que vous tenez compte en spécifiant le message de commit.

File: ./github/workflows/deploy.yml

name: deploy nextjs and nestjs to GITHUB

on:
  push:
    branches: [ "main" ]

jobs:
  build-and-push-frontend:
    runs-on: ubuntu-latest

    if: contains(github.event_name, 'push') && !startsWith(github.event.head_commit.message, 'backend')

    steps:
      - name: Checkout
        uses: actions/checkout@v3

      - name: Login to Docker Hub
        uses: docker/login-action@v1
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}

      - name: Build and push frontend to Docker Hub
        uses: docker/build-push-action@v2
        with:
          context: frontend
          file: frontend/Dockerfile
          push: true
          tags: ${{ secrets.DOCKER_FRONTEND_IMAGE }}:latest

      - name: SSH into the remote server and deploy frontend
        uses: appleboy/ssh-action@master
        with:
          host: ${{ secrets.REMOTE_SERVER_HOST }}
          username: ${{ secrets.REMOTE_SERVER_USERNAME }}
          password: ${{ secrets.REMOTE_SERVER_SSH_KEY }}
          port: ${{ secrets.REMOTE_SERVER_SSH_PORT }}
          script: |
            cd website/
            docker rmi -f ${{ secrets.DOCKER_FRONTEND_IMAGE }}:latest
            docker-compose down
            docker-compose up -d

  build-and-push-backend:
    runs-on: ubuntu-latest

    if: contains(github.event_name, 'push') && !startsWith(github.event.head_commit.message, 'frontend')

    steps:
      - name: Checkout
        uses: actions/checkout@v3

      - name: Login to Docker Hub
        uses: docker/login-action@v1
        with:
          username: ${{ secrets.DOCKERHUB_USERNAME }}
          password: ${{ secrets.DOCKERHUB_TOKEN }}

      - name: Build and push backend to Docker Hub
        uses: docker/build-push-action@v2
        with:
          context: backend
          file: backend/Dockerfile
          push: true
          tags: ${{ secrets.DOCKER_BACKEND_IMAGE }}:latest

      - name: SSH into the remote server and deploy backend
        uses: appleboy/ssh-action@master
        with:
          host: ${{ secrets.REMOTE_SERVER_HOST }}
          username: ${{ secrets.REMOTE_SERVER_USERNAME }}
          password: ${{ secrets.REMOTE_SERVER_SSH_KEY }}
          port: ${{ secrets.REMOTE_SERVER_SSH_PORT }}
          script: |
            cd website/
            docker rmi -f ${{ secrets.DOCKER_BACKEND_IMAGE }}:latest
            docker-compose down
            docker-compose up -d=

Repository: https://github.com/xvandevx/blog-examples/tree/main/nextjs-nestjs-deploy

Recap

This article is a hands-on guide to deploying Next.js and Nest.js together on a single server, making it a go-to solution for developers who want a streamlined setup. By combining the strengths of Next.js for frontend and Nest.js for backend, I showed how to efficiently manage both parts of your application using Docker and GitHub Actions. It simplifies the deployment process, allowing you to focus on building your app rather than juggling multiple configurations. Perfect for those looking to get a full-stack project up and running quickly with minimal hassle.

Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!

Déclaration:
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn