7
4

More than 3 years have passed since last update.

【アプリ開発 1】【Node.js express Docker】 Dockerを用いてNode.js Express MongoDB(mongoose)の環境を構築する【2020年12月】

Last updated at Posted at 2020-12-30

※当方駆け出しエンジニアのため、間違っていることも多々あると思いますので、ご了承ください。また、間違いに気付いた方はご一報いただけると幸いです。

Node.js Express MongoDBを用いたアプリ開発

受託開発でNode.js Express MongoDBを用いたアプリ開発を行うことになりました。
開発の中で得られた知見を、支障のない範囲で記録していきたいと思います。
アプリの内容はさておき、チームで開発するため、まずはDockerを用いて開発環境を構築を行います。

構築する環境

  • docker-composeを用いて、アプリコンテナ、mongodbコンテナを作成する。
  • アプリコンテナとmongodbコンテナの接続テスト(mongoose)を用いて、テストモデルにデータ保存。
  • mongo compassからデータの挿入を確認
  • mongodbに認証を設ける。作成するユーザーの権限は"root","read","owner"
  • データベースのパスワード等は環境変数で管理(gitignoreにてgitの管理から外す。)

※注意点
<アプリ名> <パスワード>となっているところは、各自で適当なものを記入してください。
そのまま記載するとエラーとなります。
今回は、パスワードは全て共通としています。

初期インストールするパッケージ一覧

 "bcrypt"
 "body-parser"
 "connect-flash"
 "cookie-parser"
 "debug"
 "ejs"
 "express"
 "express-ejs-layouts"
 "express-generator"
 "express-session"
 "express-validator"
 "http-errors"
 "http-status-codes"
 "method-override"
 "mongoose"
 "morgan"
 "nodemon"
 "passport"
 "passport-local-mongoose"

下準備

最初に用意するファイル群

.
├── .env
├── .gitignore
├── data
│   └── db  //空ディレクトリ
├── docker-compose.yml
├── docker_app
│   └── Dockerfile
├── secret_file
│   ├── db.env
│   └── db_init
│         └──mongo_init_user.js
└── src
    ├── controllers
    │     └── initTestsController.js
    ├── models
    │     └── init_test.js
    └── package.json

env.

MONGO_INITDB_ROOT_USERNAME=root
MONGO_INITDB_ROOT_PASSWORD=<パスワード>
MONGO_INITDB_DATABASE=<DB名>
gitignore.

node_modules/
data/
.env
secret_file/
docker-compose.yml
version: '3'
services:
  app:
    build: ./docker_app
    container_name: <アプリ名>_app_cnt
    ports:
      - "8080:3000"
    restart: always
    working_dir: /app
    tty: true
    volumes:
      - /etc/passwd:/etc/passwd:ro
      - /etc/group:/etc/group:ro
      - ./src:/app
    env_file:
      - ./secret_file/db.env
    command: bash
    networks:
      - <アプリ名>-network
    depends_on:
      - mongo
  mongo:
    image: mongo:latest
    container_name: <アプリ名>_db_cnt
    ports:
      - "27018:27017"
    restart: always
    environment:
      MONGO_INITDB_ROOT_USERNAME: ${MONGO_INITDB_ROOT_USERNAME}
      MONGO_INITDB_ROOT_PASSWORD: ${MONGO_INITDB_ROOT_PASSWORD}
      MONGO_INITDB_DATABASE: ${MONGO_INITDB_DATABASE}
    volumes:
      - ./data/db:/data/db
      - ./secret_file/db_init/:/docker-entrypoint-initdb.d
    env_file:
      - ./secret_file/db.env
    command:
      - mongod
    networks:
      - <アプリ名>-network
networks:
  <アプリ名>-network:
    external: true
Dockerfile.

FROM node:12
WORKDIR /app
RUN npm install
db.env
DB_USER=owner
DB_PASS=<パスワード>
DB_NAME=<アプリ名>_db
mongo_init_user.js
let users = [
  {
    user: "read",
    pwd: "<パスワード>",
    roles: [
      {
        role: "read",
        db: "<アプリ名>_db"
      }
    ]
  },
  {
    user: "owner",
    pwd: "<パスワード>",
    roles: [
      {
        role: "dbOwner",
        db: "<アプリ名>_db"
      }
    ]
  },
  {
    user: "readWriteUser",
    pwd: "<パスワード>",
    roles: [
      {
        role: "readWrite",
        db: "<アプリ名>_db"
      }
    ]
  }
];

for (let i = 0, length = users.length; i < length; ++i) {
  db.createUser(users[i]);
}
initTestsController.js
"use strict";

const InitTest = require('../models/init_test');

const test = () => {
  let initTest = new InitTest({
    name: "Taro",
    age: 20
  })
  initTest.save((error, data) => {
    if (error) {
      console.log(error);
    }
    console.log(data);
  })
}

module.exports = { test };
init.test.js
"use strict";

const mongoose = require("mongoose");

const initTestSchema = new mongoose.Schema({
  name: String,
  age: Number
});

module.exports = mongoose.model("InitTest", initTestSchema);
package.json
{}

環境作成

コンテナ作成

ホスト.
docker-compose build

下記の様な警告がでるが問題ない。

npm WARN saveError ENOENT: no such file or directory, open '/app/package.json'
npm notice created a lockfile as package-lock.json. You should commit this file.
npm WARN enoent ENOENT: no such file or directory, open '/app/package.json'
npm WARN app No description
npm WARN app No repository field.
npm WARN app No README data
npm WARN app No license field.
ホスト.
#コンテナを一時的に起動コンテナ内に入る(--rmで停止後削除する。コンテナ起動後、bashに入る)
docker-compose run --rm app /bin/bash
appコンテナ内.
# express-generatorでアプリケーションのひな形を生成
npx express-generator --view=ejs

下記の用に即abortingで拒絶されたら再度実行

destination is not empty, continue? [y/N]
aborting

二回目は質問で待ってくれるので y でエンター

destination is not empty, continue? [y/N] y

下記の様な各種ファイルが作成される。

   create : public/
   create : public/javascripts/
   create : public/images/
   create : public/stylesheets/
   create : public/stylesheets/style.css
   create : routes/
   create : routes/index.js
   create : routes/users.js
   create : views/
   create : views/error.ejs
   create : views/index.ejs
   create : app.js
   create : package.json
   create : bin/
   create : bin/www

package.jsonに下記の内容を上書き

package.json
{
  "name": "uniq_app",
  "version": "0.0.0",
  "private": true,
  "scripts": {
    "start": "nodemon ./bin/www"
  },
  "dependencies": {
    "bcrypt": "^5.0.0",
    "body-parser": "^1.19.0",
    "connect-flash": "^0.1.1",
    "cookie-parser": "~1.4.4",
    "debug": "~2.6.9",
    "ejs": "^3.1.5",
    "express": "~4.16.1",
    "express-ejs-layouts": "^2.5.0",
    "express-generator": "^4.16.1",
    "express-session": "^1.17.1",
    "express-validator": "^6.7.0",
    "http-errors": "~1.6.3",
    "http-status-codes": "^2.1.4",
    "method-override": "^3.0.0",
    "mongoose": "^5.11.9",
    "morgan": "~1.9.1",
    "nodemon": "^2.0.6",
    "passport": "^0.4.1",
    "passport-local-mongoose": "^6.0.1"
  }
}

app.jsに下記の内容を上書き

app.js
const createError = require('http-errors');
const express = require('express');
const path = require('path');
const cookieParser = require('cookie-parser');
const logger = require('morgan');
const mongoose = require("mongoose");


const indexRouter = require('./routes/index');
const usersRouter = require('./routes/users');

const initTestController = require('./controllers/initTestsController');

const app = express();

mongoose.connect(
  `mongodb://${process.env.DB_USER}:${process.env.DB_PASS}@mongo:27017/<アプリ名>_db`,
  { userNewParser: true }
);

mongoose.set("useCreateIndex", true);

// view engine setup
app.set('views', path.join(__dirname, 'views'));
app.set('view engine', 'ejs');

app.use(logger('dev'));
app.use(express.json());
app.use(express.urlencoded({ extended: false }));
app.use(cookieParser());
app.use(express.static(path.join(__dirname, 'public')));

app.get('/initTest', initTestController.test);/* 初期テストルーティング */
app.use('/', indexRouter);
app.use('/users', usersRouter);

// catch 404 and forward to error handler
app.use(function (req, res, next) {
  next(createError(404));
});

// error handler
app.use(function (err, req, res, next) {
  // set locals, only providing error in development
  res.locals.message = err.message;
  res.locals.error = req.app.get('env') === 'development' ? err : {};

  // render the error page
  res.status(err.status || 500);
  res.render('error');
});

module.exports = app;

パッケージのインストール

appコンテナ内.
npm install

一度コンテナを抜ける

appコンテナ内.
#コンテナを抜ける(この仮コンテナは削除される)
exit

コンテナを再起動

ホスト.
docker-compose up

下記クリックで接続確認
http://localhost:8080/

mongooseとの接続確認

下記クリックでデータが作成されるか確認
http://localhost:8080/initTest

下記の様なログが出力されれば成功(docker-compose upしたターミナルで)

uniq_app_cnt |   _id: 5fec5a6213a2fd002d89acca,
uniq_app_cnt |   name: 'initTestUser',
uniq_app_cnt |   age: 20,
uniq_app_cnt |   __v: 0
uniq_app_cnt | }
uniq_app_cnt | 【ログ】--接続成功--【ログ】

mongodbの権限周り確認

ターミナルを別タブで開き、dbコンテナに入る

docker exec -it <アプリ名>_db_cnt bash
mongo
//mongodbに接続

show dbs
//何も表示されない。(認証でロックされていることを確認)

use admin
//adminデータベースへ接続

db.auth("root", "<パスワード>")

//1 と返れば認証成功

db.system.users.find().pretty()
//作成されたユーザー確認

以下の様な、データベースに対する各権限者が作成されていたらオッケー。

{
    "_id" : "admin.root",
    "roles" : [
        {
            "role" : "root",
            "db" : "admin"
        }
    ]
}
{
    "_id" : "uniq_db.read",
    "roles" : [
        {
            "role" : "read",
            "db" : "<データベース名>_db"
        }
    ]
}
{
    "_id" : "uniq_db.owner",
    "roles" : [
        {
            "role" : "dbOwner",
            "db" : "<データベース名>_db"
        }
    ]
}
{
    "_id" : "uniq_db.readWriteUser",
    "roles" : [
        {
            "role" : "readWrite",
            "db" : "<データベース名>_db"
        }
    ]
}

mongo compassからの接続確認。

image.png

7
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
7
4