🍃

はじめてのMongoDB with Docker

2022/08/15に公開

はじめに

MongoDB に入門したので、勉強したことをメモ。
環境作って、基本操作を試すところまで。
レプリカセットとかシャーっディングとか運用っぽい話はスコープ外。
migration もスコープ外。

MongoDB って?

  • MongoDB: The Developer Data Platform | MongoDB | MongoDB
  • MongoDB Inc. が開発とサポートしてる。
  • OSS だけど、少し特殊なライセンス。
  • Server Side Public License (SSPL)っていうライセンス(SaaS として提供するときに制限がかかる)
  • 機能強化された商用版もある
  • 管理ツールとかマネージドサービスとかが、本体と別で提供されてる。
  • NoSQL(スキーマレス、基本結合操作しない、スケールアウトしやすい、トランザクション処理しない)
  • JSON を使ったドキュメント指向データベース
  • JavaScript ライクなクエリ
  • DBMS のランキングで 5 位
  • NoSQL で 1 位

環境構築

docker compose

mongod が動いてるコンテナとクライアントのコンテナを用意する。
公式と先人の情報を参考に環境を構築した。あっさりできた。

mongo - Official Image | Docker Hub
MongoDB と Mongo-express を docker-compose で立ち上げる | Yukkuri Machine Learning
docker-compose で mongoDB 環境を構築して使う - Qiita

そのままコピペも微妙かなと思って、3 点変更した。
network を設定してみたのと、volume の書き方変えてみたのと、クライアント用に環境変数設定なしで、もう一つ mongo コンテナを立ち上げてみたのと。

docker-compose.yml
version: "3.1"

services:
  mongo:
    image: mongo
    networks:
      - mongo_network
    restart: always
    environment:
      MONGO_INITDB_ROOT_USERNAME: root
      MONGO_INITDB_ROOT_PASSWORD: password
    volumes:
      - mongodb_data1:/data/db

  mongo-express:
    image: mongo-express
    networks:
      - mongo_network
    restart: always
    ports:
      - 8081:8081
    environment:
      ME_CONFIG_MONGODB_ADMINUSERNAME: root
      ME_CONFIG_MONGODB_ADMINPASSWORD: password
      ME_CONFIG_MONGODB_SERVER: mongo
    depends_on:
      - mongo

  mongo-client:
    image: mongo
    networks:
      - mongo_network
    restart: always
    volumes:
      - mongodb_data2:/data/db

volumes:
  mongodb_data1:
  mongodb_data2:

networks:
  mongo_network:

mongo-express もすんなり繋がった。

docker compose upするときに、下記ワーニングが出てたけど、ローカルで動かすだけだから一旦無視することにした。

hello-mongo-mongo-express-1  | Server is open to allow connections from anyone (0.0.0.0)
hello-mongo-mongo-express-1  | basicAuth credentials are "admin:pass", it is recommended you change this in your config.js!

auth

以下、mongod が動いている方に環境変数で指定したユーザー名とパスワードでアクセスしてみたところ。期待通りユーザーが作成されている。ちなみに、mongoだけだと何も見れないので、auth がきいてそう。

ただ、いまいち自信ないので、docker-compose.ymlcommand: [mongod, --auth]を追加しといた方が良いかも。本番環境では必須。
下記サイトをみると、--authが効いてない場合、ユーザー認証しなくても入れてしまうっぽい。

MongoDB ユーザー認証設定は必ずしましょう - Qiita

root@fdce2f3b200a:/# mongo -u root -p password
> show dbs
admin   0.000GB
config  0.000GB
local   0.000GB
> use admin
switched to db admin
> show collections
system.users
system.version
> db.system.users.find()
{下記ユーザー情報}
{
    "_id": "admin.root",
    "userId": UUID(""),
    "user": "root",
    "db": "admin",
    "credentials": {
        "SCRAM-SHA-1": {
            "iterationCount": 10000,
            "salt": "",
            "storedKey": "",
            "serverKey": ""
        },
        "SCRAM-SHA-256": {
            "iterationCount": 15000,
            "salt": "",
            "storedKey": "",
            "serverKey": ""
        }
    },
    "roles": [
        {
            "role": "root",
            "db": "admin"
        }
    ]
}

client の方のコンテナは、(当たり前だけど)下記の通りアクセスできない。

root@9807833c9166:/# mongo -u root -p password
MongoDB shell version v5.0.10
connecting to: mongodb://127.0.0.1:27017/?compressors=disabled&gssapiServiceName=mongodb
Error: Authentication failed. :
connect@src/mongo/shell/mongo.js:372:17
@(connect):2:6
exception: connect failed
exiting with code 1

client のコンテナでは、下記コマンドで mongo にアクセスして情報を見れる。(当たり前だけど)system.usersはない。

root@9807833c9166:/# mongo admin
> show dbs
admin   0.000GB
config  0.000GB
local   0.000GB
> use admin
switched to db admin
> show  collections
system.version

クライアントから、サーバー側にアクセスするのも確認できた。host 名は mongo でいけた。

> show dbs
root@9807833c9166:/# mongo -u root -p password --host mongo
admin   0.000GB
config  0.000GB
local   0.000GB
> use admin
switched to db admin
> show collections
system.users
system.version
> db.system.users.find()

init.js

最初の立ち上げ時に実行するスクリプトを読み込ませるために、docker-compose.ymlvolumesに下記を追加。

- ./init.js:/docker-entrypoint-initdb.d/init.js:ro

下記init.jsを準備することで、hogeに読み書きできるユーザーを追加することができる。

下記 Stack Overflow を信じると、init.jsでユーザー作るとき、権限周りがトリッキーなので、色々注意する必要あるみたい。色々試しても、なぜかうまくいかなくて、すごくハマった。

The tricky part was to understand that *.js files were run unauthenticated. The solution authenticates the script as the admin-user in the admin database. MONGO_INITDB_DATABASE admin is essential, otherwise the script would be executed against the test db. Check the source code of docker-entrypoint.sh.

docker - How to create a DB for MongoDB container on start up? - Stack Overflow

init.js
db = db.getSiblingDB("admin");
db.auth("root", "password");
db.createUser({
  user: "testuser",
  pwd: "password",
  roles: [
    {
      role: "readWrite",
      db: "hoge",
    },
  ],
});

db = db.getSiblingDB("hoge");
db.createCollection("test");
const doc1 = { name: "Hoge", age: 36 };
const doc2 = { name: "Fuga", age: 32 };
db.test.insertMany([doc1, doc2]);

試しに接続してみたら、期待通り読み書きできた。
--authenticationDatabaseは指定したユーザーが登録されてるデータベースを指定する必要があるらしい。
今回、init.jsでルートユーザーでユーザー作成してるので、adminに登録されるみたい。
MongoDB のユーザ管理 - Qiita

root@b0a9ed9d4807:/# mongo hoge -u testuser -p password --authenticationDatabase admin
> show dbs
hoge  0.000GB
> show collections
test
> db.test.insert({"name":"hoge"})
WriteResult({ "nInserted" : 1 })
> db.test.find()
{ "_id" : ObjectId("62fde48175962c00b516aab6"), "name" : "Hoge", "age" : 36 }
{ "_id" : ObjectId("62fde48175962c00b516aab7"), "name" : "Fuga", "age" : 32 }
{ "_id" : ObjectId("62fde64052c39d0c23eae51f"), "name" : "hoge" }

ちなみに、下記コマンドでボリューム削除しながら、何度か試した。down だけだと、ボリュームが消えなくて、データも残るから。

docker compose down --volumes

ここ参照。
docker compose down | Docker Documentation

基本操作

collection の追加削除閲覧と、Document に対する CRUD 操作を確認した。

> show collections
test
> db.createCollection("mycollection")
{ "ok" : 1 }
> show collections
mycollection
test
> db.mycollection.insert({"name":"hogehoge"});
WriteResult({ "nInserted" : 1 })
> db.mycollection.insert({"name":"fugafuga"});
WriteResult({ "nInserted" : 1 })
> db.mycollection.find();
{ "_id" : ObjectId("62fa453336a0adc30d5e2d3f"), "name" : "hogehoge" }
{ "_id" : ObjectId("62fa454736a0adc30d5e2d40"), "name" : "fugafuga" }
> db.mycollection.find({"name":"hogehoge"});
{ "_id" : ObjectId("62fa453336a0adc30d5e2d3f"), "name" : "hogehoge" }
> db.mycollection.find({"name":"hogehoge"}, {_id:0});
{ "name" : "hogehoge" }
> db.mycollection.update({"_id":ObjectId("62fa453336a0adc30d5e2d3f")}, {$set:{"name":"piyopiyo"}})
WriteResult({ "nMatched" : 1, "nUpserted" : 0, "nModified" : 1 })
> db.mycollection.find();
{ "_id" : ObjectId("62fa453336a0adc30d5e2d3f"), "name" : "piyopiyo" }
{ "_id" : ObjectId("62fa454736a0adc30d5e2d40"), "name" : "fugafuga" }
> db.mycollection.remove({"name":"fugafuga"})
WriteResult({ "nRemoved" : 1 })
> db.mycollection.find();
{ "_id" : ObjectId("62fa453336a0adc30d5e2d3f"), "name" : "piyopiyo" }
> db.mycollection.drop();
true
> show collections
test

ここを参考にした。
MongoDB データ操作(DB, Collection, Document) - わくわく Bank

おわりに

MongoDB の基本的なところ手を動かしながら試してみた。
docker composeで楽に環境用意できるのが素晴らしい。
ユーザー周りの挙動が、読み物だけだとよくわからなかったので、試しながらできて良かった。
次は、バックエンドから操作する部分をもうちょい試していきたい。

その他

mongosh

mongoコマンドを使うときに、下記出力があった。今回、シンプルなコマンドしか試していないからほとんど変わらんかもやけど、今始めるなら、mongoshてのを使った方が良いのかも。

================
Warning: the "mongo" shell has been superseded by "mongosh",
which delivers improved usability and compatibility.The "mongo" shell has been deprecated and will be removed in
an upcoming release.
For installation instructions, see
https://docs.mongodb.com/mongodb-shell/install/
================

mongo-express

mongo にアクセスする web アプリ。Node.js, Express and Bootstrap3で作ってるらしい。
ここら参照。
mongo-express/mongo-express: Web-based MongoDB admin interface, written with Node.js and express
mongo-express - Official Image | Docker Hub
mongodb を GUI で。mongo-express - Qiita

参考

他に参考にしたところは下記の通り。

GitHubで編集を提案

Discussion