NestJS(Fastify) × TypeORM × PostgreSQL × Dockerで環境構築

タイトルの構成で、マイグレーションが実行できる一歩手前までの環境構築を行う。

環境構築手順

1. Dockerの設定

Terminal window
mkdir <PROJECT_NAME>
touch Dockerfile docker-compose.yml .dockerignore

1-1. Dockerfile

FROM node:18.14.1-alpine
WORKDIR /app
RUN npm i -g @nestjs/cli

1-2. docker-compose.yml

version: '3.8'
services:
app:
container_name: app
build: .
tty: true
stdin_open: true
volumes:
- .:/app
- /app/node_modules
depends_on:
- db
environment:
TZ: Asia/Tokyo
ports:
- '3000:3000'
db:
container_name: db
image: postgres:14.2-alpine
restart: always
volumes:
- ./docker/postgres/init.d:/docker-entrypoint-initdb.d
- ./docker/postgres/pgdata:/var/lib/postgresql/data
environment:
POSTGRES_DB: mydb
POSTGRES_USER: user
POSTGRES_PASSWORD: pw
TZ: 'Asia/Tokyo'
ports:
- '5432:5432'
db-gui:
container_name: db-gui
image: dpage/pgadmin4
volumes:
- ./docker/pgadmin:/var/lib/pgadmin
depends_on:
- db
environment:
PGADMIN_DEFAULT_EMAIL: email@email.com
PGADMIN_DEFAULT_PASSWORD: pw
ports:
- '80:80'

今回はWeb GUI上でDBの操作を行いたいのでpgadmin4も導入しておく。

1-3 .dockerignore

node_modules

1-4. ビルド

Terminal window
docker compose up -d --build
docker compose ps

上記コマンドを叩きコンテナが起動していればOK。

もしMac・Docker Desktopを利用していてビルドが失敗する際は下記の方法で解決するかも。

【Docker】ビルドが.docker/buildx/current:permission deniedとエラーになる

2. コンテナに入る

Terminal window
docker exec -it app sh

以後はコンテナ内で作業していく。

3. Nestプロジェクトの作成

Terminal window
nest new .
? Which package manager would you ❤️ to use? (Use arrow keys)
❯ npm
yarn
pnpm

と聞かれるのでnpmを選択。

Terminal window
npm run start:dev

localhost:3000にアクセスしてHello World!が表示されればアプリ側はOK。

FROM node:18.14.1-alpine
WORKDIR /app
RUN npm i -g @nestjs/cli
COPY ./package.json .
COPY ./package-lock.json .
RUN npm install

コンテナを立ち上げる際に各種npmパッケージのインストールを行いたいので、Dockerfileに追記しておく。

4. Fastifyに切り替え

Terminal window
npm i @nestjs/platform-fastify
import { NestFactory } from '@nestjs/core';
import { AppModule } from './app.module';
import {
FastifyAdapter,
type NestFastifyApplication,
} from '@nestjs/platform-fastify';
async function bootstrap() {
const app = await NestFactory.create(AppModule);
const app = await NestFactory.create<NestFastifyApplication>(
AppModule,
new FastifyAdapter(),
);
await app.listen(3000);
await app.listen(3000, '0.0.0.0');
}
bootstrap();

main.tsを書き換える。

5. pgAdminからDBに接続する

下記に沿ってpgAdminにログインし、PostgresのDBに接続できることを確認する。

【Docker】pgAdmin4でPostgreSQLに接続&永続化する

6. DBの接続情報

6-1. 環境変数に設定

Terminal window
touch .env
DATABASE_HOST=db
DATABASE_NAME=mydb
DATABASE_USER=user
DATABASE_PASSWORD=pw
DATABASE_PORT=5432

6-2. ConfigModuleの導入

Terminal window
npm i @nestjs/config
import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { AppController } from './app.controller';
import { AppService } from './app.service';
@Module({
imports: [],
imports: [ConfigModule.forRoot({ isGlobal: true })],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}

.envの値を参照するためにconfigServiceをDIする。

7. TypeORMの導入

Terminal window
npm i @nestjs/typeorm typeorm pg
import { Module } from '@nestjs/common';
import { TypeOrmModule } from '@nestjs/typeorm';
import { ConfigService } from '@nestjs/config';
@Module({
imports: [
TypeOrmModule.forRootAsync({
inject: [ConfigService],
useFactory: (configService: ConfigService) => ({
type: 'postgres',
host: configService.get<string>('DATABASE_HOST'),
database: configService.get<string>('DATABASE_NAME'),
username: configService.get<string>('DATABASE_USER'),
password: configService.get<string>('DATABASE_PASSWORD'),
port: Number(configService.get<string>('DATABASE_PORT')),
entities: [],
synchronize: false,
}),
}),
],
})
export class DatabaseModule {}

TypeORMの設定専用のモジュールsrc/database/database.module.tsを作成し、上記のようにConfigServiceをDIしてDBへの接続オプションを設定する。

import { Module } from '@nestjs/common';
import { ConfigModule } from '@nestjs/config';
import { DatabaseModule } from './database/database.module';
import { AppController } from './app.controller';
import { AppService } from './app.service';
@Module({
imports: [ConfigModule.forRoot({ isGlobal: true })],
imports: [ConfigModule.forRoot({ isGlobal: true }), DatabaseModule],
controllers: [AppController],
providers: [AppService],
})
export class AppModule {}

あとはapp.module.tsでimportすれば設定完了。

[9:18:11 PM] File change detected. Starting incremental compilation...
[9:18:11 PM] Found 0 errors. Watching for file changes.
[Nest] 433 - 09/29/2023, 9:18:12 PM LOG [NestFactory] Starting Nest application...
[Nest] 433 - 09/29/2023, 9:18:12 PM LOG [InstanceLoader] DatabaseModule dependencies initialized +9ms
[Nest] 433 - 09/29/2023, 9:18:12 PM LOG [InstanceLoader] TypeOrmModule dependencies initialized +0ms

npm run start:devしてエラーが吐かれていないことを確認。

次のステップ

NestJS × TypeORM 0.3 でCLIからmigrationする

12

参考
  1. Database | NestJS - A progressive Node.js framework

  2. NestJSをTypeORM 0.3 で使う - Zenn