概要
先日行われた勉強会にて簡易ではありますが表題のサービスを作りました。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
について理解を深めることができたのでよかったかなと思います。