We have decided to develop an application using Node.js Express MongoDB as a contract development. I would like to record the knowledge gained during development within a range that does not hinder it. Aside from the contents of the application, since we will develop it as a team, we will first build a development environment using Docker.
--Create an app container and mongodb container using docker-compose. --Save data in the test model using the connection test (mongoose) between the app container and the mongodb container. --Confirm data insertion from mongo compass --Provide authentication for mongodb. The authority of the user to create is "root", "read", "owner" --Database password etc. are managed by environment variables (remove from git management with gitignore)
※important point
If it is 
 "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  //Empty directory
├── 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=<password>
MONGO_INITDB_DATABASE=<DB name>
.gitignore.
node_modules/
data/
.env
secret_file/
docker-compose.yml
version: '3'
services:
  app:
    build: ./docker_app
    container_name: <app 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:
      - <app name>-network
    depends_on:
      - mongo
  mongo:
    image: mongo:latest
    container_name: <app 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:
      - <app name>-network
networks:
  <app name>-network:
    external: true
Dockerfile.
FROM node:12
WORKDIR /app
RUN npm install
db.env
DB_USER=owner
DB_PASS=<password>
DB_NAME=<app name>_db
mongo_init_user.js
let users = [
  {
    user: "read",
    pwd: "<password>",
    roles: [
      {
        role: "read",
        db: "<app name>_db"
      }
    ]
  },
  {
    user: "owner",
    pwd: "<password>",
    roles: [
      {
        role: "dbOwner",
        db: "<app name>_db"
      }
    ]
  },
  {
    user: "readWriteUser",
    pwd: "<password>",
    roles: [
      {
        role: "readWrite",
        db: "<app name>_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
{}
host.
docker-compose build
The following warning appears, but there is no problem.
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.
host.
#Temporarily put the container inside the start container (--Delete after stopping with rm. After starting the container, enter bash)
docker-compose run --rm app /bin/bash
In the app container.
# express-Generate application template with generator
npx express-generator --view=ejs
If it is rejected by aborting immediately for the following, execute again
destination is not empty, continue? [y/N]
aborting
The second time I will wait with a question, so enter with y
destination is not empty, continue? [y/N] y
Various files such as the following are created.
   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
Overwrite the following contents in 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"
  }
}
Overwrite the following contents in 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/<app name>_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);/*Initial test routing*/
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;
Package installation
In the app container.
npm install
Exit the container once
In the app container.
#Exit the container (this temporary container will be deleted)
exit
Restart the container
host.
docker-compose up
Click below to check connection http://localhost:8080/
Check if the data is created by clicking below http://localhost:8080/initTest
If the following log is output, it is successful (in the terminal where 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 |【log】--Successful connection--【log】
Open the terminal in a separate tab and enter the db container
docker exec -it <app name>_db_cnt bash
mongo
//Connect to mongodb
show dbs
//Nothing is displayed.(Make sure it is locked by authentication)
use admin
//Connect to admin database
db.auth("root", "<password>")
//If 1 is returned, authentication is successful
db.system.users.find().pretty()
//User confirmation created
It's okay if each authorized person for the database is created as shown below.
{
	"_id" : "admin.root",
	"roles" : [
		{
			"role" : "root",
			"db" : "admin"
		}
	]
}
{
	"_id" : "uniq_db.read",
	"roles" : [
		{
			"role" : "read",
			"db" : "<Database name>_db"
		}
	]
}
{
	"_id" : "uniq_db.owner",
	"roles" : [
		{
			"role" : "dbOwner",
			"db" : "<Database name>_db"
		}
	]
}
{
	"_id" : "uniq_db.readWriteUser",
	"roles" : [
		{
			"role" : "readWrite",
			"db" : "<Database name>_db"
		}
	]
}

Recommended Posts