「労働者が自分の仕事をうまくやりたいなら、まず自分の道具を研ぎ澄まさなければなりません。」 - 孔子、「論語。陸霊公」
表紙 > プログラミング > NextJs と NestJs を単一のアプリケーションとしてデプロイする

NextJs と NestJs を単一のアプリケーションとしてデプロイする

2024 年 11 月 8 日に公開
ブラウズ:780

ちょっと、そこ!単一ホスト上でシームレスに動作するように NestJS を構成する方法を共有できることを嬉しく思います。しかしその前に、なぜこのセットアップがフロントエンドとバックエンドの両方を管理する上で長い間私にとって最優先の選択であったのかを説明しましょう。

Next.js は、新しいプロジェクトを開始する際の強力なツールです。これには、組み込みルーティング、サーバーサイド レンダリング (SSR)、キャッシュなどの、本格的な運用に役立つ機能が満載されています。さらに、Next.js には独自の内部 API 機能があり、キャッシュやデータ準備などのタスクをフレームワーク内で直接管理できます。これは、インフラストラクチャの設定ではなく、アプリの構築に集中できることを意味します。

しかし、場合によっては、サーバーにさらに強力な機能が必要になることがあります。そこで Nest.js が介入します。このフレームワークは非常に強力であるため、バックエンドとフロントエンドの間のミドルウェアの役割を処理できるだけでなく、単独で堅牢なバックエンド ソリューションとして機能することもできます。したがって、この場合、NestJS は Next.js に追加するのに適しており、フロントエンドとバックエンドに単一のプログラミング言語を使用できるようになります。

なぜ単一のホストなのか?

一言で言えば、すごく便利です。 git pull と docker-compose up -d だけで準備完了です。 CORS やポートの操作について心配する必要はありません。さらに、配信プロセスが合理化され、すべてがよりスムーズかつ効率的に実行されます。欠点として、これは高負荷の大きなプロジェクトには適さないことが挙げられます。

1. まず、リポジトリのフォルダー構造を定義しましょう

Deploy NextJs and NestJs as a single application

2. サーバーの docker ファイルを宣言しましょう

ファイル: ./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

一言で言えば、すごく便利です。 git pull と docker-compose up -d だけで準備完了です。 CORS やポートの操作について心配する必要はありません。さらに、配信プロセスが合理化され、すべてがよりスムーズかつ効率的に実行されます。欠点として、これは高負荷の大きなプロジェクトには適さないことが挙げられます。

3. 開発モード用の別の docker ファイル

開発モードの場合、バックエンドとフロントエンドをローカルで実行するため、コンテナ サービスは必要ありません。

ファイル: ./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.バックエンド用のDockerファイル

ファイル: ./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. Ngnix の設定

このステップでは、Next.js フロントエンドと Nest.js バックエンドのリバース プロキシとして機能するように Nginx を構成します。 Nginx 構成を使用すると、同じホストからリクエストを処理しながら、フロントエンドとバックエンドの間でリクエストをシームレスにルーティングできます。

ファイル: /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;
    }
}

この構成はポート 80 でリッスンし、一般的なトラフィックをポート 3000 の Next.js フロントエンドにルーティングしますが、/api へのリクエストはすべてポート 3010 の Nest.js バックエンドに転送されます。

7. NestJs グローバル プレジックス

同じホストを使用しているため、NestJ を /apipath で利用できるようにする必要があります。これを行うには、GlobalPrefix — API.

を設定する必要があります。

ファイル: ./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. フロントエンド

フロントエンドに構成は必要ありませんが、すべてのサーバーリクエストが /api パスを基準にして呼び出される必要があることのみを考慮します。

9. ローカルで実行する

CD フロントエンド
npm run dev
cd ../バックエンド
npm run start:dev
CD ../
docker-compose -f docker-compose.dev.yml up -d

これで、ブラウザで localhost を開いて Web サイトを確認できます。この例では、サーバー上に 1 つのリクエストがあり、クライアント上にもう 1 つのリクエストがあります。これらのリクエストは両方とも Next.Js から呼び出され、Nest.Js によって処理されます。

Deploy NextJs and NestJs as a single application

10. GitHub 経由でサーバーにデプロイして実行する

この記事では、Docker Registry と GitHub Actions を使用してプロジェクトをサーバーにデプロイする方法について説明します。このプロセスは、Docker レジストリにバックエンドとフロントエンドの両方の Docker イメージを作成することから始まります。その後、GitHub リポジトリをセットアップし、シームレスなデプロイメントに必要なシークレットを構成する必要があります:

DOCKERHUB_USERNAME
DOCKERHUB_TOKEN
DOCKER_FRONTEND_IMAGE
DOCKER_BACKEND_IMAGE
REMOTE_SERVER_HOST
REMOTE_SERVER_USERNAME
REMOTE_SERVER_SSH_KEY
REMOTE_SERVER_SSH_PORT

バックエンドとフロントエンドに 1 つのリポジトリを使用することの裏側は、何かをプッシュするたびに両方のイメージが再構築されることです。最適化するには、次の条件を使用できます:

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’)

コミットメッセージを指定することで、注目したイメージのみをリビルドすることが可能です。

ファイル: ./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=
仕事: ビルドアンドプッシュフロントエンド: 実行: ubuntu-最新 if: contains(github.event_name, 'push') && !startsWith(github.event.head_commit.message, 'backend') 手順: - 名前: チェックアウト 使用: アクション/checkout@v3 - 名前: Docker Hub へのログイン 使用: docker/login-action@v1 と: ユーザー名: ${{ Secrets.DOCKERHUB_USERNAME }} パスワード: ${{ Secrets.DOCKERHUB_TOKEN }} - 名前: フロントエンドをビルドして Docker Hub にプッシュする 使用: docker/build-push-action@v2 と: コンテキスト: フロントエンド ファイル: フロントエンド/Dockerfile プッシュ: true タグ: ${{ Secrets.DOCKER_FRONTEND_IMAGE }}:最新 - 名前: リモート サーバーに SSH で接続し、フロントエンドをデプロイします 使用: appleboy/ssh-action@master と: ホスト: ${{ Secrets.REMOTE_SERVER_HOST }} ユーザー名: ${{ Secrets.REMOTE_SERVER_USERNAME }} パスワード: ${{ Secrets.REMOTE_SERVER_SSH_KEY }} ポート: ${{ Secrets.REMOTE_SERVER_SSH_PORT }} スクリプト: | CDサイト/ docker rmi -f ${{ Secrets.DOCKER_FRONTEND_IMAGE }}:最新 docker-compose ダウン docker-compose up -d ビルドアンドプッシュバックエンド: 実行: ubuntu-最新 if: contains(github.event_name, 'push') && !startsWith(github.event.head_commit.message, 'frontend') 手順: - 名前: チェックアウト 使用: アクション/checkout@v3 - 名前: Docker Hub へのログイン 使用: docker/login-action@v1 と: ユーザー名: ${{ Secrets.DOCKERHUB_USERNAME }} パスワード: ${{ Secrets.DOCKERHUB_TOKEN }} - 名前: バックエンドをビルドして Docker Hub にプッシュする 使用: docker/build-push-action@v2 と: コンテキスト: バックエンド ファイル: バックエンド/Dockerfile プッシュ: true タグ: ${{ Secrets.DOCKER_BACKEND_IMAGE }}:最新 - 名前: リモート サーバーに SSH で接続し、バックエンドをデプロイします 使用: appleboy/ssh-action@master と: ホスト: ${{ Secrets.REMOTE_SERVER_HOST }} ユーザー名: ${{ Secrets.REMOTE_SERVER_USERNAME }} パスワード: ${{ Secrets.REMOTE_SERVER_SSH_KEY }} ポート: ${{ Secrets.REMOTE_SERVER_SSH_PORT }} スクリプト: | CDサイト/ docker rmi -f ${{ Secrets.DOCKER_BACKEND_IMAGE }}:最新 docker-compose ダウン docker-compose up -d=

リポジトリ: https://github.com/xvandevx/blog-examples/tree/main/nextjs-nestjs-deploy

要約

この記事は、Next.js と Nest.js を 1 つのサーバーに一緒にデプロイするための実践ガイドであり、セットアップを合理化したい開発者にとって頼りになるソリューションになります。フロントエンド用の Next.js とバックエンド用の Nest.js の長所を組み合わせることで、Docker と GitHub Actions を使用してアプリケーションの両方の部分を効率的に管理する方法を示しました。これにより展開プロセスが簡素化され、複数の構成をやりくりするのではなく、アプリの構築に集中できるようになります。最小限の手間でフルスタック プロジェクトを迅速に立ち上げて実行したいと考えている人に最適です。

リリースステートメント この記事は次の場所に転載されています: https://dev.to/xvandev/deploy-nextjs-and-nestjs-as-a-single-application-15mj?1 侵害がある場合は、[email protected] に連絡して削除してください。それ
最新のチュートリアル もっと>

免責事項: 提供されるすべてのリソースの一部はインターネットからのものです。お客様の著作権またはその他の権利および利益の侵害がある場合は、詳細な理由を説明し、著作権または権利および利益の証拠を提出して、電子メール [email protected] に送信してください。 できるだけ早く対応させていただきます。

Copyright© 2022 湘ICP备2022001581号-3