【Docker】初心者向け NestJS + Next.js の環境構築

# はじめに

こんにちは、梅雨です。

今回は、初心者向けに NestJS と Next.js を Docker で使用する際の環境構築について解説しようと思います。

# NestJS と Next.js について

まずは、NestJS と Next.js について軽く触れようと思います。

## NestJS

https://nestjs.com

NestJSは、Node.js 上で動作するサーバーサイドアプリケーションフレームワークです。

TypeScript で構築されており、堅牢な型システムとモジュール構造によって、コードの保守性と拡張性を向上させます。

依存性注入（DI）やデコレーターを活用することで、直感的で効率的な開発が可能です。これに関しては以下の記事で詳しく説明しているので是非読んでみてください。

https://qiita.com/tsuyuni/items/4b4be7c28e933f5021c7

Nest.js は Express または Fastify をアプリケーション基盤として利用できますが、今回は Express を使用します。

## Next.js

https://nextjs.org

Next.jsは、React をベースとしたフロントエンドフレームワークであり、サーバーサイドレンダリング（SSR）や静的サイト生成（SSG）を簡単に実現できます。

ファイルシステムベースのルーティングによりシンプルで直感的なページ構造が提供されています。

NestJS と同様、TypeScript に対応しているため、型安全なコーディングが可能となっています。

# Docker を用いて環境構築を行う

それでは、Docker を用いたコンテナ環境でこれらの環境構築を行っていきましょう。

## フォルダの準備

まずはプロジェクトのルートディレクトリを作成し、移動します。

```bash
$ mkdir docker-nestjs-nextjs-demo
$ cd docker-nestjs-nextjs-demo
```

このディレクトリ配下に `backend` と `frontend` のフォルダを作成します。

```bash
$ mkdir backend
$ mkdir frontend
```

現在フォルダ構造は以下のようになっています。

```
docker-nestjs-nextjs-demo
├─ backend
└─ frontend
```

## Docker Compose の環境構築

次に、Docker Compose の環境構築を行います。Docker Compose は複数の Docker コンテナを管理するために使われるツールであり、今回であれば NestJS と Next.js の２つのコンテナの管理を行います。

`backend` と `frontend` の各フォルダ内に `Dockerfile` を作成します。

```shell
$ touch backend/Dockerfile
$ touch frontend/Dockerfile
```

```dockerfile:Dockerfile
FROM node:22.12.0-alpine
```

ベースイメージには `node:22.12.0-alpine` を指定しました。

`22.12.0` は 2024/12/25 における LTS（Long-Term Support）バージョンです。

また、`alpine` は linux ディストーションの中でもとりわけ軽量であり、よく使用されます。

続いて、ルートディレクトリに Docker Compose 用の設定ファイルである `docker-compose.yml` を作成しましょう。

```shell
$ touch docker-compose.yaml
```

```yaml:docker-compose.yaml
services:
  backend:
    build: ./backend
    ports:
      - 8000:8000
    volumes:
      - ./backend:/app
  frontend:
    image: ./frontend
    ports:
      - 3000:3000
    volumes:
      - ./frontend:/app
```

`build` には各 `Dockerfile` のあるパスを記述します。
 
# バックエンドの環境構築

Docker をしようする準備ができたので、今度はバックエンドの環境構築を行っていきます。

## Dockerfile の記述

NestJS プロジェクトは CLI コマンドで作成できるので、まずはコンテナを起動するための準備をします。

Dockerfileに以下を追記して bash と Nest CLI を使えるようにしましょう。

```diff_docker:backend/Dockerfile
FROM node:22.12.0-alpine
+ WORKDIR /app
+ RUN apk add bash && npm i -g @nestjs/cli
```

複数コマンドの実行は、以下のよう改行をはさむことで可読性を高めることもできます。

```docker:backend/Dockerfile
RUN apk add bash && \
    npm i -g @nestjs/cli
```

コンテナをビルドし、コンテナでbashを実行します。

```bash
$ docker compose build
$ docker compose run --rm backend bash
```

## NestJS の環境構築

まずは、NestJS の CLI がきちんとインストールされていることを確認しましょう。

```bash:backend
/app# nest -v
10.4.9
```

`nest new` コマンドでプロジェクトを作成できます。

```bash:backend
/app# nest new .
⚡  We will scaffold your app in a few seconds..

? Which package manager would you ❤️  to use? (Use arrow keys)
❯ npm 
  yarn 
  pnpm 
```

今回はnpmを選択しました。

```bash:backend
/app# nest new .
⚡  We will scaffold your app in a few seconds..

? Which package manager would you ❤️  to use? npm
CREATE .eslintrc.js (663 bytes)
CREATE .prettierrc (51 bytes)
CREATE README.md (5205 bytes)
CREATE nest-cli.json (171 bytes)
CREATE package.json (1939 bytes)
CREATE tsconfig.build.json (97 bytes)
CREATE tsconfig.json (546 bytes)
CREATE src/app.controller.ts (274 bytes)
CREATE src/app.module.ts (249 bytes)
CREATE src/app.service.ts (142 bytes)
CREATE src/main.ts (228 bytes)
CREATE test/jest-e2e.json (183 bytes)
CREATE src/app.controller.spec.ts (617 bytes)
CREATE test/app.e2e-spec.ts (630 bytes)

✔ Installation in progress... ☕

🚀  Successfully created a new project
👉  Get started with the following commands:

$ cd .
$ npm run start


Failed to execute command: git init
Git repository has not been initialized
                                         
                          Thanks for installing Nest 🙏
                 Please consider donating to our open collective
                        to help us maintain this package.
                                         
                                         
               🍷  Donate: https://opencollective.com/nest
```

NestJS のプロジェクトは作成できたが、`node:alpine` の Docker イメージには git が入っていないため git リポジトリの初期化に失敗してしまいました。

今回の構成では、ルートディレクトリである `docker-nestjs-nextjs-demo` を git 管理するため気にしなくて大丈夫です。

代わりに、`.gitignore` をルートディレクトリに移動させておきましょう。
（※ このコマンドはコンテナ外で実行してください。）

```bash
$ mv backend/.gitignore .gitignore
```

続いて、NestJS のサーバが起動するポート番号を 8000 番に変更します。
これは `docker-compose.yml` で指定したポート番号となっています。

```diff_typescript:backend/src/main.ts
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';

async function bootstrap() {
  const app = await NestFactory.create(AppModule);
-   await app.listen(process.env.PORT ?? 3000);
+   await app.listen(process.env.PORT ?? 8000);
}
bootstrap();
```

最後に、NestJS の開発環境のサーバ起動コマンドである `npm run start:dev` を Dockerfile に追記しましょう。

```diff_docker:backend/Dockerfile
FROM node:22.12.0-alpine
WORKDIR /app
RUN apk add bash && \
    npm i -g @nestjs/cli
+ CMD ["npm", "run", "start:dev"]
```

これで NestJS の環境構築は完了です。

# フロントエンドの環境構築

バックエンドと同様に、フロントエンドも環境構築を行っていきましょう。

## Dockerfile の記述

Next.js には CLI はないため、Dockerfile の記述は以下の内容で十分です。

```diff_docker:frontend/Dockerfile
FROM node:22.12.0-alpine
+ WORKDIR /app
+ RUN apk add bash
```

コンテナをビルドし、コンテナでbashを実行します。

```bash
$ docker compose build
$ docker compose run --rm frontend bash
```

## Next.js の環境構築

Next.js は以下の npx コマンドでプロジェクトが作成できます。

```bash:frontend
/app# npx create-next-app@latest .
✔ Would you like to use TypeScript? … Yes
✔ Would you like to use ESLint? … Yes
✔ Would you like to use Tailwind CSS? … Yes
✔ Would you like your code inside a `src/` directory? … Yes
✔ Would you like to use App Router? (recommended) … Yes
✔ Would you like to use Turbopack for `next dev`? … No
✔ Would you like to customize the import alias (`@/*` by default)? … No
```

https://nextjs.org/docs/app/api-reference/cli/create-next-app

NestJS と同様に、サーバの起動コマンドを Dockerfile に追加しましょう。

```diff_docker:frontend/Dockerfile
FROM node:22.12.0-alpine
WORKDIR /app
RUN apk add bash
CMD ["npm", "run", "dev"]
```

これでフロントエンドの環境構築が完了しました。

# おわりに

今回は、NestJS と Next.js を Docker で使用する際の環境構築について解説しました。

Docker や Docker Compose は慣れてしまえばそんなに難しくないですが、初めての方にとってはハードルが高いと思ます。もし困ったりした際は、ぜひこの記事を参考にしてみてください。

最後までお読みいただきありがとうございました。