見出し画像

MongoDBをDockerで構築する!

こんにちは。株式会社レスキューナウで基幹システムを担当しているエンジニアの衣笠です。
今回のテーマは、MongoDBのDocker化です。

データベースをコンテナ化すれば何かと便利です。例えば、新しくコレクションを作成するときや、データベースの構成変更を検討しているときに、運用中のデータベースを直接書き換えてしまうと、データベースを壊してしまう恐れがあります。開発環境であっても、運用中のデータベースを壊すようなことをしたくありません。まずはローカル環境でコンテナ構築して色々と試せれば、仮に失敗してもコンテナごと消去して再構築すればいいので、手軽に安全に検討することができます。

また、GitHubActions などのクラウド型の CI (継続的インテグレーション) ツールで、データベースアクセスが必要なプログラムのユニットテストを自動化することも可能になります。実際に、これまで利用していた Jenkins からGitHubActions に移行し、mongoDB コンテナを起動させてからユニットテストを実行するワークフローを設定して利用しています。

それでは早速ですが、Docker化作業について説明いたします。

Docker化作業


ディレクトリ構成

docker
├── docker-compose-db-init.yml
├── docker-compose-db.yml
└── mongodb
    ├── Dockerfile
    ├── data
    ├── initdata
    │   ├── SAMPLE.json.gz
    │   └── import_collections.sh
    └── initdb.d
        └── create_user.js

環境
Docker Desktop for Mac (Intel) 4.8.2


MongoDB起動とユーザ作成


一番初めのコンテナ起動で、MongoDBの構築とユーザ作成をする方法です。

docker-compose-db-init.yml

version: "3"

services:
  mongodb:
    build:
      context: ./mongodb
      dockerfile: Dockerfile
    container_name: mongodb
    restart: always
    ports:
      - "27017:27017"
    volumes:
      - ./mongodb/initdb.d:/docker-entrypoint-initdb.d
      - ./mongodb/data:/data/db

/docker-entrypoint-initdb.d
MongoDBコンテナ内の /docker-entrypoint-initdb.d に配置されたファイル (.sh, .js) はコンテナ起動時に自動で実行されます$${^{1)}}$$。ここに、ユーザ作成のクエリを記述したファイル (create_user.js) を配置しておきます。

/data/db
MongoDBのデータファイルはコンテナ内の /data/db に書き込まれます$${^{1)}}$$。このディレクトリをホストにマウントしてデータを永続化しておけば、コンテナを停止してもデータベース内のデータは消えません。

Dockerfile
MongoDBの公式Dockerイメージを使用します。

FROM mongo:latest

ENV TZ Asia/Tokyo

COPY initdata/ /initdata

初期構築時にデータベースにコレクションをインポートしたいので、コレクションのJSONファイルと、インポートコマンドを記載したスクリプト (import_collections.sh) を initdata ディレクトリに配置し、コンテナ内にコピーします。これについては、後ほど説明します。

create_user.js

db = db.getSiblingDB("admin");
db.createUser({
  user: "root",
  pwd: "****",
  roles: [{role: "root", db: "admin"}]
});

db = db.getSiblingDB("sampledb");
db.createUser({
  user: "sampleuser",
  pwd: "****",
  roles: [
    { role : "dbOwner", db : "sampledb" },
    { role : "dbAdmin", db : "sampledb" },
    { role : "readWrite", db : "sampledb" },
  ]
});

データベース admin にroot ユーザを、データベース sampledb にユーザ sampleuser を作成する例です。db.createUser() でユーザ名とパスワード、権限を設定しています$${^{2)}}$$$${^{3)}}$$。

このファイルをコンテナ内のディレクトリ /docker-entrypoint-initdb.d に配置すれば、初回起動時に自動でユーザ作成されます。

参考
1) Docker Hub (mongo)
2) MongoDB Manual (db.createUser)
3) MongoDB Manual (Built-In Roles)


コレクションのインポート


初期構築時にデータベースにコレクションをインポートするため、事前に開発環境のMongoDBから、コレクション毎にJSONファイルにエクスポートしておきます。以下のスクリプトと一緒にホストの initdata ディレクトリに配置しておきます。ファイルサイズが大きい場合は、gzip 圧縮しておき、コンテナ内で解凍するといいと思います。

import_collections.sh

#!/bin/sh

# 解凍
gzip -d /initdata/*.gz

# コレクションインポート
mongoimport -u sampleuser -p **** -d sampledb -c SAMPLE --file /initdata/SAMPLE.json --jsonArray

mongoimport -u <ユーザ名> -p <パスワード> -d <データベース名>
-c <コレクション名> --file <JSONファイルのパス> --jsonArray

--jsonArray: JSON配列に複数のドキュメントが記載されている場合に必要

参考
4) MongoDB Database Tools (mongoimport)


レプリケーションモード


Standalone で起動しているデータベースを、レプリケーションモードで再起動して Primary にする方法です。プログラム内でトランザクション処理でデータベースにアクセスしている場合には必要になります。
レプリカセットの手順は公式チュートリアル$${^{5)}}$$どおりですが、docker-compose での起動と初期化方法を説明します。

docker-compose-db.yml

version: "3"

services:
  mongodb:
    build:
      context: ./mongodb
      dockerfile: Dockerfile
    container_name: mongodb
    restart: always
    command: mongod --replSet myReplSet
    ports:
      - "27017:27017"
    volumes:
      - ./mongodb/data:/data/db

これで docker-compose up しても、その時点ではデータベースはまだ Primary になっていませんので、ご注意ください。初期構築時のみ、レプリカセットの初期化が必要です。

初期化するには、以下のコマンドを実行します。
docker-compose-db.yml  内でレプリカセット名を "myReplSet" に指定しているので、その名前を設定します。今回はデータベース1台のみ (Primary のみ) で十分なので、メンバーは1つだけ指定しています。

docker container exec mongodb mongo -u root -p **** --eval 'rs.initiate({_id: "myReplSet", members: [{_id: 0, host: "mongodb:27017"}]})'

rs.initiate({
    _id: "<レプリカセット名>",
    members: [{_id: 0, host: "<コンテナ名>:<ポート>"}]
})

コマンド実行後、{ "ok" : 1 } と表示されれば、初期化完了です。

参考
5) MongoDB Manual (Deploy a Replica Set)


MongoDBコンテナ構築手順


必要なファイルの準備ができたら、以下の5つのステップで MongoDB を構築していきます。

初期構築

Step 1: MongoDBコンテナを起動し、ユーザを作成する

docker-compose -f docker-compose-db-init.yml up -d --build

Step 2: データベースにコレクションをインポートする

docker container exec mongodb /initdata/import_collections.sh

Step 3: コンテナ再起動

docker-compose -f docker-compose-db-init.yml down
docker-compose -f docker-compose-db.yml up -d

Step 4: レプリカセット初期化

docker container exec mongodb mongo -u root -p **** --eval 'rs.initiate({_id: "myReplSet", members: [{_id: 0, host: "mongodb:27017"}]})'

これでMongoDBの構築完了です!
次回からは以下のコマンドだけで起動できます。

初期構築後の起動

docker-compose -f docker-compose-db.yml up -d


おわりに


今回は、MongoDBのDocker化作業と構築手順を紹介しました。MongoDB や Docker について学びながらの作業だったので、実際にはDocker化に数日掛かりましたが、一度作ってしまえば、数個のコマンドで構築できてしまうので、よかったらお試しください。
最後までご覧いただき、ありがとうございました。

最後に

現在、災害情報の提供、災害情報を活用した安否確認サービスなどのWebサービスの開発エンジニアを募集しています!
入社後に安心してご活躍できることを目指し、応募された方の特性・ご希望にマッチしたチームをご紹介します。
ちょっと話を聞いてみたい、ぜひ応募したい、など、当社にご興味を持っていただけましたら、お気軽にエントリーください!!