🦴

Next.js × Nest.jsの環境をDockerで作成する

2024/09/15に公開

はじめに

フロントエンドをNext.js、バックエンドをNest.jsで作成し、Dockerで環境構築します。

  • node 20.9.0
  • next.js 14.2.11
  • nest.js 10.0.0

プロジェクトを作成

任意の開発ディレクトリでプロジェクト用のディレクトリを作成します。

mkdir next-nest-dev
cd next-next-dev

フロント側をNext.jsで作成

Next.jsのフロント環境をcreate-next-appを使って作ります。

npx create-next-app front

対話形式で選択できる初期設定は好みですが、今回は以下の通り選択しました。

✔ Would you like to use TypeScript? … No / Yes
✔ Would you like to use ESLint? … No / Yes
✔ Would you like to use Tailwind CSS? … No / Yes
✔ Would you like to use src/ directory? … No / Yes
✔ Would you like to use App Router? (recommended) … No / Yes
✔ Would you like to customize the default import alias (@/*)? … No / Yes

Success!と表示されたら、/frontに移動してlocalhostを立ち上げます。

cd front
yarn
yarn dev

localhost:3000にアクセスして表示されていればOKです。

バックエンド側をNest.jsで作成

同様にしてバックエンド側も作成していきます。
Nest.jsのCLIのインストールがまだの方はnpm i -g @nestjs/cliでインストールしてください。

Nest.jsの雛形を作成します。

nest new back

/backにファイルが出力されたら/frontのポートとバッティングしないようにポートを5000に変更しておきます。

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

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
-   await app.listen(3000);
+   await app.listen(5000);
}
bootstrap();

localhostが立ち上がるか確認します

yarn run start

localhost:5000で**Hello, World!**が確認されたらOKです。

Dockerで開発環境を立ち上げる

プロジェクトルートにdocker-compose.ymlを作成します。

docker-compose.yml
version: "3.8"
services:
  api:
    build:
      context: ./docker/back
      dockerfile: Dockerfile
    volumes:
      - ./back:/app
    ports:
      - "5000:5000"
    networks:
      - app-network

  front:
    build:
      context: ./docker/front
      dockerfile: Dockerfile
    volumes:
      - ./front:/app
    ports:
      - "3000:3000"
    networks:
      - app-network

networks:
  app-network:
    driver: bridge

フロントエンドとバックエンドをそれぞれ立ち上げるためにDockerfileを作成します。

/dockerディレクトリを作成し、その中に/front/backを作成。その中にDockerfileを作成します。

├── front
├── docker
│    ├── front
│    │    └── Dockerfile
│    └── back
│         └── Dockerfile
├── back
└── docker-compose.yml
docker/back/Dockerfile
FROM node:20.9.0

WORKDIR /app

COPY package*.json ./

RUN npm i -g @nestjs/cli

RUN yarn install

COPY . .

CMD ["npm", "run", "start"]
docker/front/Dockerfile
FROM node:20.9.0

WORKDIR /app

COPY package*.json ./

RUN yarn install

COPY . .

CMD ["npm", "run", "dev"]

ディレクトリ、ファイルが作成できたら、dockerを立ち上げます。

docker-compose up -d

localhost:3000と、localhost:5000が立ち上がればOKです。

Nest.jsで作成したAPIをNext.jsで取得してみる

Nest.jsでAPIを作成

/backディレクトリに移動して、 modulepostsserviceを作成します。

cd back
nest generate module posts
nest generate controller posts
nest generate service posts

/src/postsにファイルが生成されるので、それぞれ記述していきます。

posts.service.ts
import { Injectable } from '@nestjs/common';

@Injectable()
export class PostsService {
  private readonly posts = [
    {
      id: 1,
      title: 'title 1',
      content: 'content 1',
    },
    {
      id: 2,
      title: 'title 2',
      content: 'content 2',
    },
  ];

  findAll() {
    return this.posts;
  }
}
posts.controller.ts
import { Controller, Get } from '@nestjs/common';
import { PostsService } from './posts.service';

@Controller('posts')
export class PostsController {
  constructor(private readonly postsService: PostsService) {}

  @Get()
  findAll() {
    return this.postsService.findAll();
  }
}

一度docker環境を落としてから、再度立ち上げ、localhost:5000にアクセスすると、json APIが表示されます。

Next.jsでAPIを取得

Next.jsで生成されたAPIの取得を試みます。

src/app/page.tsx
export default async function Home() {
    const res = await fetch('http://localhost:5000/posts');
    const data = await res.json();
  
    return (
        // ...
    )
}

が、エラーが発生します。

Error: fetch failed

dockerのコンテナのIPを固定して修正します。

一度docker-compose downしてから、docker-compose.ymlを編集します。

docker-compose.yml
version: "3.8"
services:
  api:
    build:
      context: ./docker/back
      dockerfile: Dockerfile
    volumes:
      - ./back:/app
    ports:
      - "5000:5000"
    networks:
-      - app-network
+      fixed_compose_network:
+        ipv4_address: 192.168.188.2

  front:
    build:
      context: ./docker/front
      dockerfile: Dockerfile
    volumes:
      - ./front:/app
    ports:
      - "3000:3000"
    networks:
-      - app-network
+      fixed_compose_network:
+        ipv4_address: 192.168.188.3

networks:
-  app-network:
-    driver: bridge
+  fixed_compose_network:
+    ipam:
+      driver: default
+      config:
+        - subnet: 192.168.188.0/24

urlを指定していたファイルのlocalhostの部分を指定したIPに変更します。

src/app/page.tsx
export default async function Home() {
-    const res = await fetch('http://localhost:5000/posts');
+    const res = await fetch('http://192.168.188.2:5000/posts');
    const data = await res.json();
  
    return (
        // ...
    )
}

これでエラーなく、データを取得できます。

Discussion