【NestJS + PostgreSQL + Prisma】DevContainerで作る快適な開発環境

【NestJS + PostgreSQL + Prisma】DevContainerで作る快適な開発環境

ども!年末年始の検証結果を順次ブログ化している龍ちゃんです。思いついたらすぐ検証という流れで、いろんなことを検証していたので10本ぐらいはブログのネタに困らなさそうですね。反動が今から恐ろしいです。

今回の内容は、以下の二つになります。

  • ローカル開発環境をDevContainerで作成する(nest.js + postgres)
  • nest.jsからPrismaを使用してpostgresに接続する

今回のゴールとしては、nest.js内でORMとしてPrismaを使用してpostgresへ接続して動作確認となります。

環境構築

前提条件としては、DockerとDocker Composeコマンドが使えれば大丈夫です。最終的なファイルとしては、こちらのリポジトリに上がっています。まだ、絶賛開発に使用する前段階なので、何の整備もしていなくてすいません。

ディレクトリ構成としては、以下のようになります。postgresのデータの永続化は、ボリュームマウントとしてコンテナ内へ収めておきます。

.
├── .devcontainer
│   └── devcontainer.json
├── .dockerignore
├── .env                       # docker用環境変数
├── Dockerfile
├── docker-compose.yml
└── nest-app                   # nest.jsアプリ
  1. nest.jsの環境づくり
  2. node_modulesをvolumeマウント化
  3. postgresの環境づくり

nest.jsの環境づくり

まずは、nest.jsの環境を作っていこうと思います。先にNodeの環境を作成して、DevContainerでいきなりアクセスしてしまいます。

三つのファイルを作成します。

Dockerfile

ARG NODE_VER
FROM node:${NODE_VER} as base
RUN npm install -g npm@11.0.0

FROM base as dev

RUN npm i -g @nestjs/cli

USER node

WORKDIR /home/node/app

docker-compose.yml

version: "3.7"
services:
  nest:
    build:
      args:
        - NODE_VER=22.12.0
      context: .
      dockerfile: Dockerfile
      target: dev
    tty: true
    volumes:
      - type: bind
        source: .
        target: /home/node/app

.devcontainer/.devcontainer.json

{
  "name": "procject-backend",
  "dockerComposeFile": ["../docker-compose.yml"],
  "service": "nest",
  "workspaceFolder": "/home/node/app",
  "customizations": {
    "vscode": {
      "extensions": [],
      "settings": {}
    }
  },
  "remoteUser": "node",
}

DevContainer内に入ったら、next.jsのプロジェクトを作成します。Dockerfile内でnest CLIをインストールしているので、実行可能かを試してみます。

nest --version

バージョンが帰ってきたら、成功しているのでそのままアプリを作っていきましょう。今回のアプリ名はnest-appで作成していきます。

nest new nest-app

これで環境作成は完了です。

node_modulesをvolumeマウント化

node_modulesをvolumeマウントにすることで、コンテナ内に収めてしまいます。こちらの対応をしておくことで、元ファイル側のサイズを小さくすることができます。また、bindマウントしないことによりビルド速度を上昇させることができます。

こちらでやっていることは、「.dockerignoreでビルド時にnode_modulesをなかったことにして、Dockerfileでnode_modulesを作成してビルド、dokcer-compose.ymlでnode_modulesをボリュームマウントする」となります。Dockerファイルで作成している理由としては、dokcer-compose.ymlファイル経由で作成させるとroot権限で作成されて、詰まったいい思い出があります。

追加で、.dockerignoreファイルを作成してください。

.dockerignore

nest-app/node_modules

Dockerfile

ARG NODE_VER
FROM node:${NODE_VER} as base
RUN npm install -g npm@11.0.0

FROM base as dev

RUN npm i -g @nestjs/cli

USER node

WORKDIR /home/node/app

RUN mkdir nest-app
COPY --chown=node:node nest-app nest-app

WORKDIR /home/node/app/nest-app
RUN mkdir node_modules
RUN chown node:node node_modules

RUN npm install

docker-compose.yml

version: "3.7"
services:
  nest:
    build:
      args:
        - NODE_VER=22.12.0
      context: .
      dockerfile: Dockerfile
      target: dev
    tty: true
    volumes:
      - type: bind
        source: .
        target: /home/node/app
      - type: volume
        source: node_modules
        target: /home/node/app/nest-app/node_modules
volumes:
  node_modules:

ファイルの適応が完了したら、**DevContainerを必ずRebuildしてください。**以上で、node_modulesのボリュームマウント化完了です。

next.jsのアプリを作成した際に発生したnpm installで持ってきたnode_modulesが元ファイルに残っていると思います。気になる方は、コンテナから抜け出して、お好きなように処理してください。

postgres環境づくり

postgresの環境は、16.6とバージョンを指定して作成していきます。公式のリファレンスを置いておきます。

環境変数を渡すので、まずは.envファイルを作成しておきます。本当のファイルの場合は、もっとちゃんとしたセキュリティにしてくださいね。

.env

POSTGRES_USER=user
POSTGRES_PASSWORD=password

docker-compose.yml

version: "3.7"
services:
  nest:
    build:
      args:
        - NODE_VER=22.12.0
      context: .
      dockerfile: Dockerfile
      target: dev
    tty: true
    volumes:
      - type: bind
        source: .
        target: /home/node/app
      - type: volume
        source: node_modules
        target: /home/node/app/nest-app/node_modules
    depends_on:
      - postgresql

  postgresql:
    env_file: ".env"
    container_name: postgresql
    image: postgres:16.6
    ports:
      - 5432:5432
    volumes:
      - type: volume
        source: postgres_data
        target: /var/lib/postgresql/data
    environment:
      POSTGRES_USER: ${POSTGRES_USER}
      POSTGRES_PASSWORD: ${POSTGRES_PASSWORD}
      POSTGRES_INITDB_ARGS: "--encoding=UTF-8"
      TZ: "Asia/Tokyo"
    hostname: postgres
    restart: always

volumes:
  node_modules:
  postgres_data:

nest.jsのアプリは、postgresの環境が立ち上がった後に立ち上がるように設定しておきます。あくまで開発環境なので、厳密である必要はないのですが、DB前提のシステムを組むと想定されるので念のためですね。

ここまでコピペできたら、**DevContainerを必ずRebuildしてください。**実行中のDevContainerからpostgresの環境にアクセスして以下のコマンドを実行してください。

psql -h postgres -U user 

無事アクセスすることができれば、問題なく動作していると考えられます。

Prisma接続

Prismaのセットアップは公式のドキュメントが十分なので、今回作成したpostgresへアクセスするまでについて共有していきます。これから、Prsimaの勉強もしていくので、まとまったらブログ書きます。

npm install prisma --save-dev

npx prisma init                      # prismaセットアップ .envファイルが作成される

npm i --save @nestjs/config          # nest.jsのコンフィグ読み込み用ライブラリ

nest-app/src/app.module.ts

import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { AppController } from './app.controller';
import { AppService } from './app.service';

@Module({
  imports: [ConfigModule.forRoot({isGlobal:true})],
  controllers: [AppController],
  providers: [AppService],
})
export class AppModule {}

Globalで環境変数を読めるようにglobalで読み込んでおきます。これで、Prismaが作成した.envファイルも読み込むことができます。

スキーマファイルに定義を記入します。

nest-app/prisma/schema.prisma

// This is your Prisma schema file,
// learn more about it in the docs: <https://pris.ly/d/prisma-schema>

// Looking for ways to speed up your queries, or scale easily with your serverless or edge functions?
// Try Prisma Accelerate: <https://pris.ly/cli/accelerate-init>

generator client {
  provider = "prisma-client-js"
}

datasource db {
  provider = "postgresql"
  url      = env("DATABASE_URL")
}
model User {
  id    Int     @default(autoincrement()) @id
  email String  @unique
  name  String?
  posts Post[]
}

model Post {
  id        Int      @default(autoincrement()) @id
  title     String
  content   String?
  published Boolean? @default(false)
  author    User?    @relation(fields: [authorId], references: [id])
  authorId  Int?
}

ここまでしてやっとで.envファイルの接続情報変更します。今回の環境では、以下に更新することで接続することができます。

DATABASE_URL="postgresql://user:password@postgres:5432/mydb?schema=public"

// DATABASE_URL="postgresql://{ユーザー}:{パスワード}@{ホスト名}:5432/mydb?schema=public"

以下のコマンドで先ほどコピペした内容がDBに反映されます。

npx prisma migrate dev --name init

コマンドが無事完了したら、以下のコマンドでprisma studioを立ち上げて反映できているか確認します。

npx prisma studio

かっこいい画面が立ち上がり、PostとUserが作成されていれば無事にアクセスできています。

prisma studio image

おわり

今回の閑居構築で特に詰まった点としては、postgresの環境にアクセスできるまで長かったのでpostgresの環境作成が正しいのか試すことができなかった点ですね。postgresのイメージのドキュメントをちゃんと読みに行きましたね。今回は、DevContainerのVolumeを何度も消し飛ばして検証しました。開発体験としては、Git上でローカルのデータを管理しない想定なのでバインドはしたくありませんでした。PrismaのSeedなどを作りこんでおけば問題ないかと思います。

では2025年もよろしくお願いします。

ご覧いただきありがとうございます! この投稿はお役に立ちましたか?

役に立った 役に立たなかった

0人がこの投稿は役に立ったと言っています。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です