ちょっと、そこ!単一ホスト上でシームレスに動作するように NestJS を構成する方法を共有できることを嬉しく思います。しかしその前に、なぜこのセットアップがフロントエンドとバックエンドの両方を管理する上で長い間私にとって最優先の選択であったのかを説明しましょう。
Next.js は、新しいプロジェクトを開始する際の強力なツールです。これには、組み込みルーティング、サーバーサイド レンダリング (SSR)、キャッシュなどの、本格的な運用に役立つ機能が満載されています。さらに、Next.js には独自の内部 API 機能があり、キャッシュやデータ準備などのタスクをフレームワーク内で直接管理できます。これは、インフラストラクチャの設定ではなく、アプリの構築に集中できることを意味します。
しかし、場合によっては、サーバーにさらに強力な機能が必要になることがあります。そこで Nest.js が介入します。このフレームワークは非常に強力であるため、バックエンドとフロントエンドの間のミドルウェアの役割を処理できるだけでなく、単独で堅牢なバックエンド ソリューションとして機能することもできます。したがって、この場合、NestJS は Next.js に追加するのに適しており、フロントエンドとバックエンドに単一のプログラミング言語を使用できるようになります。
一言で言えば、すごく便利です。 git pull と docker-compose up -d だけで準備完了です。 CORS やポートの操作について心配する必要はありません。さらに、配信プロセスが合理化され、すべてがよりスムーズかつ効率的に実行されます。欠点として、これは高負荷の大きなプロジェクトには適さないことが挙げられます。
ファイル: ./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 やポートの操作について心配する必要はありません。さらに、配信プロセスが合理化され、すべてがよりスムーズかつ効率的に実行されます。欠点として、これは高負荷の大きなプロジェクトには適さないことが挙げられます。
開発モードの場合、バックエンドとフロントエンドをローカルで実行するため、コンテナ サービスは必要ありません。
ファイル: ./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"
ファイル: ./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"]
このステップでは、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 バックエンドに転送されます。
同じホストを使用しているため、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();
フロントエンドに構成は必要ありませんが、すべてのサーバーリクエストが /api パスを基準にして呼び出される必要があることのみを考慮します。
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 によって処理されます。
この記事では、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 を使用してアプリケーションの両方の部分を効率的に管理する方法を示しました。これにより展開プロセスが簡素化され、複数の構成をやりくりするのではなく、アプリの構築に集中できるようになります。最小限の手間でフルスタック プロジェクトを迅速に立ち上げて実行したいと考えている人に最適です。
免責事項: 提供されるすべてのリソースの一部はインターネットからのものです。お客様の著作権またはその他の権利および利益の侵害がある場合は、詳細な理由を説明し、著作権または権利および利益の証拠を提出して、電子メール [email protected] に送信してください。 できるだけ早く対応させていただきます。
Copyright© 2022 湘ICP备2022001581号-3