Next.js × Prisma × PostgreSQLの開発環境をdockerを使って構築する
初めに
Next.jsでのアプリケーション開発を行うにあたって、環境構築をした際の備忘録を記していきます。
この記事でやらないこと
- Next.js、Prisma、Dockerについての詳しい解説
手順
- Next.jsアプリケーションを作成
- PostgreSQLのコンテナ作成
- Prismaのインストール
- dbコンテナ立ち上げ時にcreate文を実行するようにする
- makeコマンドでdocker compose 〇〇が立ち上がるようにする
動作環境
- Mac Apple M1 Pro
- Docker version 24.0.5
- Docker Compose version v2.20.2-desktop.1
いざ、環境構築
ここからは実際にコンテナを作成して環境構築していきます。
※あえて順を追って書いているため、結論だけ知りたいねん、という方はページ下部までジャンプしていただけるといいかと思います。
Next.jsのプロジェクトを作成
npx create-next-app next-prisma-postgresql
// 以下の設定はお好みで
✔ Would you like to use TypeScript with this project? … No / Yes
✔ Would you like to use ESLint with this project? … No / Yes
✔ Would you like to use `src/` directory with this project? … No / Yes
✔ Would you like to use experimental `app/` directory with this project? … No / Yes
✔ What import alias would you like configured? … @/*
以下のコマンドでNext.jsがlocalhost:3000で立ち上がることを確認します(ローカルPCにNode環境がインストールされている場合)
npm run dev
PostgreSQLのコンテナを定義
docker-compose.ymlをプロジェクトのルートに作成し、以下のように記述します
services:
db:
image: postgres:15
hostname: db
env_file:
- ./.env
networks:
- app_network
environment:
- TZ=Asia/Tokyo
- POSTGRES_DB=$DB_NAME
- POSTGRES_USER=$DB_USER
- POSTGRES_PASSWORD=$DB_PASS
- PGDATA=/var/lib/postgresql/data/pgdata
ports:
- 5432:5432
volumes:
- db_data:/var/lib/postgresql/data
- ./sql:/docker-entrypoint-initdb.d
networks:
app_network:
driver: bridge
.envをルートディレクトリに作成
ここに設定している値は各環境によって自由に設定してください。
DB_HOST=db
DB_NAME=mydb
DB_USER=admin
DB_PASS=password
試しにプロジェクト直下でdocker compose up
と打ってみると、以下のようにdbのコンテナが立ち上がります。
xxx@yyyzzz next-prisma-postgresql % docker compose up
[+] Running 14/14
✔ db 13 layers [⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿⣿] 0B/0B Pulled 9.6s
✔ e886f0f47ef5 Already exists 0.0s
✔ bf49dd051338 Pull complete 0.6s
✔ 2c6efaa7c024 Pull complete 0.9s
✔ aaa6d3dac3d5 Pull complete 0.9s
✔ 0302c98903c9 Pull complete 1.8s
✔ 82c9ca236580 Pull complete 1.8s
✔ 15a5ae6b0cba Pull complete 1.8s
✔ a868fa6ad308 Pull complete 2.1s
✔ 1a3bad4a399a Pull complete 6.3s
✔ 3c605283dfa7 Pull complete 6.3s
✔ 5dab6cff0193 Pull complete 6.3s
✔ 47d8471cbd01 Pull complete 6.3s
✔ 030e872d86fa Pull complete 6.3s
[+] Running 2/2
✔ Network next-prisma-postgresql_app_network Created 0.1s
✔ Container next-prisma-postgresql-db-1 Created
コンテナにNode環境を作成
ルートディレクトリにDockerfileを作成します。
touch Dockerfile
Dockerfileに、以下のように記述します。
FROM node:18-alpine
RUN apk add g++ make py3-pip
WORKDIR /app/
COPY ./ /app/
RUN apk add --no-cache git
RUN npm install -g npm@9.7.2
RUN npm install -g node-gyp
RUN npm upgrade --save --legacy-peer-deps
RUN npm install
先ほどdbコンテナを定義したdocker-compose.ymlに、以下のようにappを追記します。
services:
app:
tty: true
networks:
- app_network
build:
context: .
ports:
- "3000:3000"
volumes:
- ./:/app
- node_modules:/app/node_modules
depends_on:
- db
db:
image: postgres:15
hostname: db
env_file:
- ./.env
networks:
- app_network
environment:
- TZ=Asia/Tokyo
- POSTGRES_DB=$DB_NAME
- POSTGRES_USER=$DB_USER
- POSTGRES_PASSWORD=$DB_PASS
- PGDATA=/var/lib/postgresql/data/pgdata
ports:
- 5432:5432
volumes:
- db_data:/var/lib/postgresql/data
- ./sql:/docker-entrypoint-initdb.d
networks:
app_network:
driver: bridge
volumes:
node_modules:
コンテナをビルドして、起動します
docker compose up --build
appコンテナの中に入り、npm run devを実行すると、アプリケーションが起動します。
docker container exec -it next-prisma-postgresql-app-1 sh
npm run dev
起動を確認したら、一旦npm run devは停止しておきます。
Prismaをインストール
ここからはappコンテナ内で作業します。
より詳しい内容ついては公式Docをご参照ください。
prismaとts-nodeをインストール
npm install prisma ts-node --save-dev
Prismaのセットアップを行います
npx prisma init
以下のようにPrismaディレクトリが作成されます
先ほど作成した.envにも、コメントとDATABASE_URLの記述が追加されています。
DB_HOST=db
DB_NAME=mydb
DB_USER=admin
DB_PASS=password
# This was inserted by `prisma init`:
# Environment variables declared in this file are automatically made available to Prisma.
# See the documentation for more detail: https://pris.ly/d/prisma-schema#accessing-environment-variables-from-the-schema
# Prisma supports the native connection string format for PostgreSQL, MySQL, SQLite, SQL Server, MongoDB and CockroachDB.
# See the documentation for all the connection string options: https://pris.ly/d/connection-strings
DATABASE_URL="postgresql://johndoe:randompassword@localhost:5432/mydb?schema=public"
DATABASE_URLの値を、以下のように書き換えます。
DATABASE_URL="postgresql://admin:password@db:5432/mydb?schema=public"
ポイント
- docker-compose.ymlでdbのhostnameを
db
としているため、localhost
をdb
に書き換えます - admin, password, mydb などと記述しているところは.envの上部に記載しているDB_NAMEやDB_USER, DB_PASSに設定している値です
- docker-compose.ymlで、dbのportを5432に指定する場合は、db:1234 といった感じで任意のportに書き換えてください
- .envは忘れずに.gitignoreに加えておきましょう
dbコンテナ立ち上げ時にcreate文を実行するようにする
今のままでは、DBにはなんのテーブルも定義されていません。
そのため、DBコンテナのビルド時に自動的にcreate文を実行し、テーブルを定義するようにします。
create_table.sql
drop table if exists users cascade;
-- ----------------------------------------------------------------------------------------------------
create table users (
id serial not null, -- ID
name text not null, -- ユーザー名
created_at timestamp not null, -- 作成日時
primary key (id)
);
一旦コンテナをdownし、再度起動します。
docker compose down
docker compose up --build
ログに以下のようにCREATE TABLEと出力されるとOK。
next-prisma-postgresql-db-1 | server started
next-prisma-postgresql-db-1 | CREATE DATABASE
next-prisma-postgresql-db-1 |
next-prisma-postgresql-db-1 |
next-prisma-postgresql-db-1 |
next-prisma-postgresql-db-1 | /usr/local/bin/docker-entrypoint.sh: running /docker-entrypoint-initdb.d/create_table.sql
next-prisma-postgresql-db-1 |
next-prisma-postgresql-db-1 | DROP TABLE
next-prisma-postgresql-db-1 | psql:/docker-entrypoint-initdb.d/create_table.sql:1: NOTICE: table "users" does not exist, skipping
next-prisma-postgresql-db-1 | CREATE TABLE
next-prisma-postgresql-db-1 |
next-prisma-postgresql-db-1 |
Prisma Studioを開く
再びappコンテナに以下のコマンドで入り、テーブルの構成をPrismaに反映します。
docker container exec -it next-prisma-postgresql-app-1 sh
npx prisma db pull
実際に反映されているかはschema.prismaを確認するか、npx prisma studio
で確認できます
……が、今のdocker-compose.ymlの記述ではnpx prisma studioを起動してもlocalhost:5555では何も見ることができません。
docker-compose.ymlに以下を追記します
services:
app:
tty: true
networks:
- app_network
build:
context: .
ports:
- "3000:3000"
- "5555:5555" # ここを追加
volumes:
- ./:/app
- node_modules:/app/node_modules
depends_on:
- db
db:
image: postgres:15
hostname: db
env_file:
- ./.env
networks:
- app_network
environment:
- TZ=Asia/Tokyo
- POSTGRES_DB=$DB_NAME
- POSTGRES_USER=$DB_USER
- POSTGRES_PASSWORD=$DB_PASS
- PGDATA=/var/lib/postgresql/data/pgdata
ports:
- 5432:5432
volumes:
- db_data:/var/lib/postgresql/data
- ./sql:/docker-entrypoint-initdb.d
networks:
app_network:
driver: bridge
volumes:
node_modules:
再度コンテナを立ち上げ直すと、確認できるようになりました。
makeコマンドを使ってコンテナが立ち上がるようにする
ここからは少しオマケ感。
以下のように、サーバーデプロイ用のdocker-composeとローカル開発用のdokcer-composeを分けたい、ということがありました。
docker-compose.deploy.yml
docker-compose.local.yml
この場合、それぞれコマンドを打つのは面倒なので、Makefileとして名前をつけて定義します。
ルートディレクトリで以下のコマンドを実行します。
touch Makefile
作成したファイルに、コマンド名と実行内容を記述
.PHONY: up
up-local:
docker compose -f docker-compose.local.yml up --build
up-deploy:
docker compose -f docker-compose.deploy.yml up --build
.PHONY: up-d
up-d-local:
docker compose -f docker-compose.local.yml up -d --build
.PHONY: down
down-local:
docker compose -f docker-compose.local.yml down
down-deploy:
docker compose -f docker-compose.deploy.yml down
.PHONY: build
build-local:
docker compose -f docker-compose.local.yml build
build-deploy:
docker compose -f docker-compose.deploy.yml build
こうすることで、以下のようなコマンドでコンテナが立ち上がるようになります。
make up-local
種類が増えたり、一つのコマンドで複数コンテナを立ち上げたい、などといった場合に便利です。
makeコマンドはMacには標準で入っているみたいですが、windowsには入っていないようなので適宜インストーるしてください。(WSL2上ですがUbuntu20.04では入ってるみたいでした。なければインストールしていただければと思います)
結果
最終的なdocker-compose.ymlは以下です
services:
app:
tty: true
networks:
- app_network
build:
context: .
ports:
- "3000:3000"
- "5555:5555"
volumes:
- ./:/app
- node_modules:/app/node_modules
depends_on:
- db
db:
image: postgres:15
hostname: db
env_file:
- ./.env
networks:
- app_network
environment:
- TZ=Asia/Tokyo
- POSTGRES_DB=$DB_NAME
- POSTGRES_USER=$DB_USER
- POSTGRES_PASSWORD=$DB_PASS
- PGDATA=/var/lib/postgresql/data/pgdata
ports:
- 5432:5432
volumes:
- db_data:/var/lib/postgresql/data
- ./sql:/docker-entrypoint-initdb.d
networks:
app_network:
driver: bridge
volumes:
node_modules:
sql/create_table.sql
drop table if exists users cascade;
-- ----------------------------------------------------------------------------------------------------
create table users (
id serial not null, -- ID
name text not null, -- ユーザー名
created_at timestamp not null, -- 作成日時
primary key (id)
);
.env
DB_HOST=db
DB_NAME=mydb
DB_USER=admin
DB_PASS=password
# This was inserted by `prisma init`:
# Environment variables declared in this file are automatically made available to Prisma.
# See the documentation for more detail: https://pris.ly/d/prisma-schema#accessing-environment-variables-from-the-schema
# Prisma supports the native connection string format for PostgreSQL, MySQL, SQLite, SQL Server, MongoDB and CockroachDB.
# See the documentation for all the connection string options: https://pris.ly/d/connection-strings
DATABASE_URL="postgresql://admin:password@db:5432/mydb?schema=public"
テーブルの作成方法に関しては、コンテナ立ち上げ時以外にもschemaに定義してdb pushする方法でも良いかと。
一旦ここまでで、次回はVPSにデプロイする用のコンテナ構成なども最近いろいろ試行錯誤していたので記事にしていければと思います!
記事で作成したリポジトリ
Discussion