【Node】DockerでNext.js+MySQL
ReactやVue.jsなど、Node.jsアプリケーションを試す環境が欲しくなった。まずは、Next.js+MySQLな環境をDockerで作成し、DBを使うアプリケーションを作成してみる。
GitHubリポジトリはこちら。
ディレクトリ構成
プロジェクトルート
├── app-next
│ └── アプリケーション構成ファイル
├── mysql
│ ├── conf.d
│ │ └── my.cnf
│ └── init.d
│ └── データベースの初期化SQL
├── .env
├── .gitignore
├── docker-compose.yml
└── Dockerfile
プロジェクトルートに、app-nextやらapp-react、app-vueなどのNode.jsアプリケーションをぶら下げていくつもり。
環境構築手順
1. 環境変数ファイル作成
DBの情報を持たせた.envファイルを作成する。環境依存ファイルをGitの無視リストに登録するのを忘れずに。
MYSQL_HOST=localhost
MYSQL_ROOT_PASSWORD=パスワード
MYSQL_DATABASE=DB名
MYSQL_USER=ユーザー名
MYSQL_PASSWORD=パスワード
2. MySQL設定ファイルの作成
my.cnfにタイムゾーンと文字コードを定義しておき、後でDBコンテナにマウントする。
[mysqld]
default-time-zone = 'Asia/Tokyo'
character-set-server = utf8mb4
collation-server = utf8mb4_bin
default-authentication-plugin = mysql_native_password
[client]
default-character-set = utf8mb4
MySQL8.04以降は、パスワード認証のハッシュ方式が変わったようだ。後で使用するNode.jsのパッケージが新しい方に対応しておらず、認証エラーが発生するので旧来のハッシュ方式を使うように定義しておく。
3. DB初期化SQLの作成
テーブルを作成してデータを投入するSQLを作成しておく。このような簡単なテーブルで今回は行ってみよう。
4. Dockerfileの作成
ベースイメージはNode.js。
FROM node:latest
# 作業ディレクトリ
WORKDIR /var/www
# ロケールのインストールと設定
RUN apt updateRUN apt -y install locales && \
localedef -f UTF-8 -i ja_JP ja_JP.UTF-8
ENV LANG ja_JP.UTF-8ENV LANGUAGE ja_JP:ja
ENV LC_ALL ja_JP.UTF-8
ENV TZ JST-9
ENV TERM xterm
# Vimインストール
RUN apt install -y vim
# create-next-appをインストール
RUN npm install -g npm@latest && npm install create-next-app
Webサーバー(入れてないけど)の公開ディレクトリ以下にアプリケーションを作っていくイメージで作業ディレクトリを設定。
最低限必要なものをインストールしたら、Next.js(のアプリケーションを作成するためのパッケージ)をインストールする。
5. docker-compose.ymlの作成
Node.jsとMySQLと、それぞれコンテナで構成する。
version: '3'
services:
# Node.js
node:
build: .
container_name: node
tty: true
ports:
- 3000:3000
# プロジェクトディレクトリにマウントする
volumes:
- .:/var/www
# ネットワーク
networks:
- default
# データベース
db:
image: mysql:latest
container_name: mysql
restart: always
ports:
- 3306:3306
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
MYSQL_DATABASE: ${MYSQL_DATABASE}
MYSQL_USER: ${MYSQL_USER}
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
volumes:
# 設定ファイルディレクトリにマウントする
- ./mysql/conf.d:/etc/mysql/conf.d
# DB初期化ディレクトリにマウントする
- ./mysql/init.d:/docker-entrypoint-initdb.d
# ネットワーク
networks:
- default
# ネットワーク
networks:
default:
driver: bridge
Nodeコンテナ
Webサーバーの公開ディレクトリをプロジェクトルートにマウントする。作成したアプリケーションがここに生成される。
DBコンテナ
MySQLへの接続情報は環境変数(.env)より取得する。ユーザーはビルド時に作成してくれる。設定ファイルと初期化のエントリポイントをローカルのディレクトリにマウントする。
ネットワーク
NodeコンテナとDBコンテナを同じブリッジネットワークに載せる。
6. コンテナビルド
Dockerイメージを作成する。
# コンテナビルド
$ docker-compose build
# イメージの確認
$ docker image ls -a
REPOSITORY TAG IMAGE ID CREATED SIZE
node-node latest fd515a4c08ce 42 hours ago 1.05GB
7. アプリケーションの作成
Next.jsのアプリケーション雛形作成コマンドをNodeコンテナで実行する。rmオプションは実行後にコンテナをいったん削除しなさいの意。
$ docker-compose run --rm node npx create-next-app app-next
Next.jsの初期化で訊かれる問答のうち、App Routerを使うかどうかについては「Yes」にする。
実行後、ローカルのプロジェクトディレクトリにアプリケーション雛形が作成されているはず。
8. コンテナ起動
# コンテナ起動
$ docker-compose up -d
# イメージの確認
$ docker image ls -a
REPOSITORY TAG IMAGE ID CREATED SIZE
mysql latest 21978c3803ca 33 hours ago 544MB
node-node latest fd515a4c08ce 42 hours ago 1.05GB
# コンテナの確認
$ docker container ls -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
64a2a554be28 mysql:latest "docker-entrypoint.s…" About a minute ago Up About a minute 0.0.0.0:3306->3306/tcp, 33060/tcp mysql
db7d575fd078 node-node "docker-entrypoint.s…" About a minute ago Up About a minute 0.0.0.0:3000->3000/tcp node
9. DBの確認
DBコンテナに入り、いろいろ中身を確認してみよう。
$ docker-compose exec db /bin/bash
# 認証プラグインの確認(先述のハッシュ方式の確認)
$ mysql -u root -p
> SELECT user, host, plugin FROM mysql.user;
+------------------+-----------+-----------------------+
| user | host | plugin |
+------------------+-----------+-----------------------+
| root | % | mysql_native_password |
| ユーザー名 | % | mysql_native_password |
| mysql.infoschema | localhost | caching_sha2_password |
| mysql.session | localhost | caching_sha2_password |
| mysql.sys | localhost | caching_sha2_password |
| root | localhost | mysql_native_password |
+------------------+-----------+-----------------------+
6 rows in set (0.00 sec)
# タイムゾーンの確認
> show variables like '%time_zone%';
+------------------+------------+
| Variable_name | Value |
+------------------+------------+
| system_time_zone | UTC |
| time_zone | Asia/Tokyo |
+------------------+------------+
2 rows in set (0.02 sec)
# 文字コードの確認
> show variables like '%char%';
+--------------------------+--------------------------------+
| Variable_name | Value |
+--------------------------+--------------------------------+
| character_set_client | utf8mb4 |
| character_set_connection | utf8mb4 |
| character_set_database | utf8mb4 |
| character_set_filesystem | binary |
| character_set_results | utf8mb4 |
| character_set_server | utf8mb4 |
| character_set_system | utf8mb3 |
| character_sets_dir | /usr/share/mysql-8.0/charsets/ |
+--------------------------+--------------------------------+
8 rows in set (0.00 sec)
# テーブルとデータの初期化確認
> use DB名;
> show tables;
+-------------------+
| Tables_in_sandbox |
+-------------------+
| authors |
| books |
+-------------------+
2 rows in set (0.01 sec)
> SELECT b.id id, b.name name, a.name author FROM books b LEFT JOIN authors a ON b.author = a.id;
+----+-----------------------+---------------+
| id | name | name |
+----+-----------------------+---------------+
| 1 | 吾輩は猫である | 夏目 漱石 |
| 2 | 坊つちやん | 夏目 漱石 |
| 3 | 三四郎 | 夏目 漱石 |
| 4 | 舞姫 | 森 鷗外 |
| 5 | 雁 | 森 鷗外 |
| 6 | 高瀬舟 | 森 鷗外 |
| 7 | にごりえ | 樋口 一葉 |
| 8 | 十三夜 | 樋口 一葉 |
| 9 | たけくらべ | 樋口 一葉 |
+----+-----------------------+---------------+
9 rows in set (0.00 sec)
よしよし。
10. デバッグサーバーの起動
Nodeコンテナでデバッグサーバーを起動する。
$ docker-compose exec node /bin/bash
# アプリケーションディレクトリへ移動
$ cd app-next
# デバッグサーバー起動
$ npm run dev
> app-next@0.1.0 dev
> next dev
ready - started server on 0.0.0.0:3000, url: http://localhost:3000
Attention: Next.js now collects completely anonymous telemetry regarding usage.
This information is used to shape Next.js' roadmap and prioritize features.
You can learn more, including how to opt-out if you'd not like to participate in this anonymous program, by visiting the following URL:
https://nextjs.org/telemetry
event - compiled client and server successfully in 3s (170 modules)
wait - compiling...
event - compiled successfully in 78 ms (137 modules)
11. 動作確認
http://localhost:3000をブラウザで動作確認。
ここまでは問題なさそう。
アプリケーション作成手順
1. パッケージのインストール
アプリケーションに必要なパッケージをインストールする。Dockerfileでグローバルにインストールしたくないけど、docker-compse.ymlに初回のみ実行されるコマンドとして登録するのも面倒なので手動でやるか。
MySQLのクライアントと環境変数ファイル読み込みパッケージを導入する。
$ docker-compose exec node /bin/bash
# アプリケーションディレクトリへ移動
$ cd app-next
# MySQLクライアントパッケージ
$ npm install promise-mysql
# 環境変数ファイル読み込みパッケージ
$ npm install dotenv
2. APIを作成
app-next/app/api/books/route.tsを作成し、DBから取得した値を返してみる。(今回はTypeScriptを使用)
import { NextResponse } from 'next/server';
import * as mysql from 'promise-mysql';
// 環境変数
require('dotenv').config({path: '../.env'});
// 書籍一覧取得API
export async function GET() {
const connection = await mysql.createConnection({
host: 'db',
port: 3306,
database: process.env.MYSQL_DATABASE,
user: process.env.MYSQL_USER,
password: process.env.MYSQL_PASSWORD
});
const sql = 'SELECT b.id id, b.name name, a.name author FROM books b LEFT JOIN authors a ON b.author = a.id';
const result = await connection.query(sql);
connection.end();
return NextResponse.json(result);
}
3. APIの動作確認
http://localhost:3000/api/booksで作成したAPIを呼び出してみる。
[
{
"id":1,
"name":"吾輩は猫である",
"author":"夏目 漱石"
},
{
"id":2,
"name":"坊つちやん",
"author":"夏目 漱石"
},
...
}
いい感じ。
4. コンポーネントの作成
app-next/app/pages/books/page.tsxを作成し、APIから取得した値を当ててみる。(今回はTypeScriptを使用)
// 型宣言
type Book = {
id: number,
name: String,
author: String
}
// コンポーネント
export default async function Books() {
// データ取得
const response = await fetch('http://localhost:3000/api/books');
const books: Book[] = await response.json();
// 描画
return (
<>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.0.2/dist/css/bootstrap.min.css"
rel="stylesheet"
integrity="sha384-EVSTQN3/azprG1Anm3QDgpJLIm9Nao0Yz1ztcQTwFspd3yD65VohhpuuCOmLASjC"
crossOrigin="anonymous">
</link>
<table className="table">
<thead>
<tr>
<th>ID</th>
<th>書名</th>
<th>著者</th>
</tr>
</thead>
<tbody>
{books.map(book => (
<tr key={book.id}>
<th>{book.id}</th>
<td>{book.name}</td>
<td>{book.author}</td>
</tr>
))}
</tbody>
</table>
</>
);
}
テーブルの見映えを良くするためにBootstrapをあててみた。
5. 動作確認
http://localhost:3000/booksをブラウザで動作確認。
おしまい。
この記事が気に入ったらサポートをしてみませんか?