bon now

ありのままの現実を書き殴る吐き溜め。底辺SEの備忘録。
Written by bon who just a foolish IT Engineer.

docker-composeを使ってレプリカセットでmongoDBを起動する

Created Date: 2023/06/28 22:00
Updated Date: 2024/01/01 02:55

MongoDBのバージョンが4、5、6とあったりレプリケーションでのローカル起動の方法が色々あったり、正しい情報を探すのにとても苦労したので、 ここにdocker-composeを使ってmongoDBをレプリカセットで起動する方法をメモしておく。 ちなみになぜレプリカセットで起動したいのかというと、MongoDBの Change Streams を使いたいたかったからである。

最初にまとめ

最初にdocker-compose周りのディレクトリ構成を示す。

1
2
3
4
5
6
.
├── docker
│   └── db
│       └── init
│           └── init.js
└── docker-compose.yml

次に作成するdocker-compose.ymlは以下のようになる。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
version: '3'
services:
  mongo:
    image: mongo:6.0.6
    environment:
      - AUTH=no
    command: [--replSet, my-replica-set, --noauth, --bind_ip_all]
    ports:
      - 27017:27017
    healthcheck:
      #test: test $$(mongosh --port 27017 --quiet --eval "try {rs.initiate({_id:'my-replica-set',members:[{_id:0,host:\"mongo:27017\"}]})} catch(e) {rs.status().ok}") -eq 1
      test: mongosh mongo-init.js
      interval: 10s
      start_period: 30s
    volumes:
      - mongodb_data:/data/db
      #- ./docker/db/init/:/docker-entrypoint-initdb.d/:ro
      - ./docker/db/init/db_init.js:/mongo-init.js
    restart: always
  mongo-express:
    image: mongo-express
    container_name: mongo_express
    restart: always
    ports:
      - 8081:8081
    environment:
      #ME_CONFIG_MONGODB_URL: mongodb://@mongo:27017/
      ME_CONFIG_MONGODB_ADMINUSERNAME: root
      ME_CONFIG_MONGODB_ADMINPASSWORD: password
      ME_CONFIG_MONGODB_SERVER: mongo
      ME_CONFIG_MONGODB_PORT: 27017
    depends_on:
      - mongo
# mongodbのデータはdocker volumeで管理されるので、消すときは docker volume rm mongodb_data
volumes:
  mongodb_data:

上記docker-compose.ymlに記載のある起動用のスクリプトも作成する。これはmongoDBのレプリカセットを初期化するためのものである。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
init = false;
print("Init script ...")

try {
  if (!db.isMaster().ismaster) {
    print("Error: primary not ready, initialize ...")
    rs.initiate(
      {
        _id:'my-replica-set',
        members: [
          { _id:0,
            host: "mongo:27017"
          }
        ]
      }
    )
    quit(1);
  } else {
    if (!init) {
      admin = db.getSiblingDB("admin");
      admin.createUser(
        {
          user: "root",
          pwd: "password",
          roles: ["readWriteAnyDatabase"]
        }
      );
      init = true;
    }
  }
} catch(e) {
  rs.status().ok
}

以上でdocker-composeを使ってmongoDBをレプリカセットで起動することができる。
次章より簡単にどういう実装内容なのかをまとめる。

MongoDB

まず利用するMongoDBはバージョン6.0.6を利用。レプリケーションを利用したいので --replSet オプションをつけて起動する。
今回はローカルでの開発用なので最小構成としてプライマリーノードを1つだけ起動する。本来は3台構成で起動するのが望ましい。
--bind_ip_all はローカルでの開発用として外部からの接続を許可するためにつけている。

また、レプリカセットの初期化を行うために healthcheck にてスクリプトを監視するようにしている。
MongoDBのコンテナイメージはレプリカセット起動をすると、entrypoint-initdb.dにあるスクリプトを実行してくれない。 この問題(仕様)により、レプリカセットの初期化やユーザーの作成を行うためにハック的に healthcheck でスクリプトを実行するようにしている。 考えた人は天才だと思う。
スクリプト内で作成している管理ユーザーはmongo-express(GUIでMongoDBを操作できるアプリ)と自前のWebアプリのために作成している。 この設定によりわざわざ認証鍵を生成・指定する必要がなくなる。

volumes をdocker volumeにしている理由は、パーミッションの問題で動かなかったため。

また上述通りコンテナの初回起動時レプリカセットが起動するタイミングでhealthcheckは必ずコケるため、 restart: always をつけている。

参考にしたサイト:
* https://stackoverflow.com/questions/76013265/how-to-do-a-mongodb-6-single-node-replicaset-with-docker-compose

mongo-express

mongo-expressはmongoDBのGUIクライアントである。mongoDBの操作をGUIで行いたい場合に利用する。
environment を使うことでmongoDBの接続先を指定することができるので便利。 このコンテナを使いたいがために色々docker-composeの記述方法を調べていたといっても過言ではない。

おわりに

docker-composeを使ってmongoDBをレプリカセットで起動する方法をまとめた。 ここまで簡単・単純にまとまった記事は(僕が探した範囲では)なかったので、今後同じようなことをする人の参考になれば幸いである。
多分MongoDBのバージョンが上がるとまた色々変わると思うので、その時はまた記事を書くかもしれない。

local_offer
folder