概要
先日行われた勉強会にて簡易ではありますが表題のサービスを作りました。Dockerの勉強の延長で取り組みました。この記事ではそのときの勉強会の内容を記載します。
どんなモノをつくるのか?
- チャットのようなアプリケーション
- docker-composeによるデータベースとの連携
- Node.js(Express)でフロントエンド&バックエンド
- データベースはPostgresSQL
完成したソースコード
参考にさせていただいた記事
作ったモノの説明
docker-compose
サービス:app
app:
build:
context: ./ # Dockerfile保存場所
depends_on:
- database
image: n-app # イメージ名
container_name: n-app # コンテナ名
ports: # ポート接続
- 3000:5000
environment:
PORT: 5000
DB_USER: postgres
DB_HOST: database
DB_PORT: 5432
DB_NAME: test_db
appはNode.js(Express)がメインとなるサービスになります。ここでは学習のために敢えてデフォルトのポートを5000に変更しています。これは参考にさせていただいたExpressの環境変数でPORTが使用されており、それをdocker-composeで5000に上書きしています。コンテナ内の5000をホスト側の3000に転送しています。ちなみにExpressで環境変数が使用されている箇所はapp/bin/のwwwというファイルで確認できます。
app/bin/www
# !/usr/bin/env node
/**
* Module dependencies.
*/
var app = require('../app');
var debug = require('debug')('myapp:server');
var http = require('http');
/**
* Get port from environment and store in Express.
*/
var port = normalizePort(process.env.PORT || '3000');
app.set('port', port);
// ~以下省略~
サービス:database
database:
image: postgres:12.3
volumes:
- ./init-sql:/docker-entrypoint-initdb.d:ro
environment:
POSTGRES_DB: test_db
TZ: "Asia/Tokyo"
POSTGRES_HOST_AUTH_METHOD: trust
databaseはPostgresSQLを使用しています。docker-composeで環境変数であるPOSTGRES_DBをtest_dbに設定することで自動的にtest_dbという名前のデータベースが作成されます。
volumesの設定はinit-dbというフォルダにSQLファイルを格納しておくことで、SQLファイルに書かれているクエリを自動的に実行してくれます。
初期スキーマの設定(テーブル構造の作成)やダミーデータなどを挿入するときに利用します。
実行順序はファイル名の昇順で実行されるので、ファイル名に番号などをつけるとよさそうです。
今回、作成したデータベースにはpostgresというユーザーが作成されますが、パスワードが設定されていません。そのためPOSTGRES_HOST_AUTH_METHODをtrustに設定する必要があります。
あと、TZでタイムゾーンを設定しています。タイムゾーンの変更については以下のクエリでも可能です。
ALTER DATABASE test_db SET timezone TO 'Asia/Tokyo';
SELECT pg_reload_conf();
init-dbにクエリをファイルとして格納しておけばタイムゾーンも変更可能です。ただし、どこでタイムゾーンが設定されているか後追いしづらいので、環境変数で設定できるなら環境変数を使った方が良いと思います。
Dockerfile:Node.js(Express)
今回のアプリケーションの部分(サービス:app)はappフォルダ配下
にExpressのソースが格納されています。それらのソースを元にDockerfileでコンテナを作成します。
Dockerfile
# ベースイメージを指定
FROM node:10.12
# 環境変数設定
ENV NODE_ENV="development"
# 作業ディレクトリ作成&設定
WORKDIR /src
COPY ./app /src
RUN npm install
CMD npm run start
ここで重要なのでコンテナの中にsrcというフォルダを作成し、そこにホスト(自分の端末)のappフォルダの中身をコピーします。srcはWORKDIRに設定されているのでsrcでコピーしたソースファイルを元にnpm installなどを実行できます。
今回はDockerfileでソースをコピーしましたがdocker-composeでも同じようなことが可能です。
Node.js(Express)
ここは別記事にしてもよいくらい説明する箇所が多いので抜粋して記載します。今回のExpressのソースではapp/routesフォルダのファイルでエンドポイントを設定して、表示内容をapp/viewsフォルダのテンプレートのファイルに渡してコンテンツを表示する流れになっています。
処理の流れ
app/routes → app/views
localhost:3000 にアクセス
app/routes/index.js
↓
app/views/index.ejs
index.jsではPostgresSQLのchatテーブルをセレクトした結果をindex.ejsに渡しています。
localhost:3000/insert?msg=SEND_TEST
app/routes/insert.js
↓
app/views/index.ejs
insert.jsではURLパラメーターでmsgを受け取ることができます。msgの値をchatテーブルにインサートします。もしパラメーターがない場合は「ふにょふにょ」という値がインサートされます。
表示する内容はindex.ejsと同じですがインサートされた後のテーブルの情報を表示します。app/routesのファイルとapp/viewsのファイルは必ず1対1にする必要はなく、同じテンプレートでも渡す内容で表示内容を切り替えるなどの制御も可能だったりします。
データベース(PostgresSQL)への接続:db_client.js
module.exports = {
pg_client: function () {
const { Client } = require('pg')
const client = new Client({
user: process.env.DB_USER,
host: process.env.DB_HOST,
port: process.env.DB_PORT,
database: process.env.DB_NAME
})
return client
},
pupupu: function () {
console.log('pupupupu')
}
};
db_client.jsでデータベースの接続処理を共通で使用できるようにしています。PostgresSQLに必要なユーザー情報などはdocker-composeから環境変数で受け取りそれを元に接続を行います。
総評
ある程度コンパクトにまとまっており、構成もそこまで複雑ではないかなと思いました。ただ開発するときに少し難がありExpressは個別でnpm installなどでpackage.jsonなどを更新する必要があります。これはdocker-compose buildはappフォルダをコピーしているので、アプリのnode_moduleなどは手動で更新しないとコンテナで動作してくれません。逆にnpm startなどで開発すればよい話になりますが、データベースとの接続ができないので困ったところです。
しかしながら、今回の勉強会ではいろいろとdocker-composeについて理解を深めることができたのでよかったかなと思います。