はじめに
先日、MongoDB 6.0
を docker-compose で立ち上げて Prisma でデータを create/update しようとすると、replica set が適切に設定されていないとエラーになったので、その時の対応をメモします。
遭遇エラー
1PrismaClientKnownRequestError:
2Invalid `prisma.media.upsert()` invocation in
3/***/packages/fullstack/prisma/fixture.ts:37:46
4
5 34 ];
6 35
7 36 for (const m of media) {
8→ 37 const upsertedMedia = await prisma.media.upsert(
9Prisma needs to perform transactions, which requires your MongoDB server to be run as a replica set. https://pris.ly/d/mongodb-replica-set
10 at Object.handleRequestError (/***/node_modules/@prisma/client/runtime/library.js:174:6929)
11 at Object.handleAndLogRequestError (/***/node_modules/@prisma/client/runtime/library.js:174:6358)
12 at Object.request (/***/node_modules/@prisma/client/runtime/library.js:174:6237)
13 at fixtures (/***/packages/fullstack/prisma/fixture.ts:37:27)
14 at main (/***/packages/fullstack/prisma/seed.ts:11:5) {
15 code: 'P2031',
16 clientVersion: '4.15.0',
17 meta: {}
18}
エラー内容から、Prisma でトランザクションを利用するためには、MongoDB で replica set を適切に設定してほしいとのこと。
結論
6.0
での対応は解決策が見出せなかったので、次の Issue #3040 を参考に 5.0
でお茶を濁しました 😅
docker-compose.yml
Dockerfile に渡す環境変数をセットしておく必要があります。
1version: "3.9"
2
3services:
4 mongo:
5 container_name: mongo
6 build:
7 context: .
8 dockerfile: ./.docker/mongo/Dockerfile
9 ports:
10 - "27017:27017"
11 environment:
12 - MONGO_REPLICA_HOST=${MONGO_REPLICA_HOST}
13 - MONGO_REPLICA_PORT=${MONGO_REPLICA_PORT}
14 - MONGO_INITDB_ROOT_USERNAME=${MONGO_INITDB_ROOT_USERNAME}
15 - MONGO_INITDB_ROOT_PASSWORD=${MONGO_INITDB_ROOT_PASSWORD}
16 volumes:
17 - mongoData:/app:cached
18 restart: always
docker/mongo/Dockerfile
こちらを参考にバージョンを変えただけです。
ただし、6.0
では、mongo コマンドから mongosh コマンドへの移行など数々のエラーに遭遇して断念しました 😢
作成者本人も 6.0
では動作しないとコメントしています。
この Dockerfile では、レプリカセットモードにして単ーノードで mongo を起動するようにしています。
1FROM mongo:5.0
2
3# we take over the default & start mongo in replica set mode in a background task
4ENTRYPOINT mongod --port $MONGO_REPLICA_PORT --replSet rs0 --bind_ip 0.0.0.0 & MONGOD_PID=$!; \
5# we prepare the replica set with a single node and prepare the root user config
6INIT_REPL_CMD="rs.initiate({ _id: 'rs0', members: [{ _id: 0, host: '$MONGO_REPLICA_HOST:$MONGO_REPLICA_PORT' }] })"; \
7INIT_USER_CMD="db.getUser('$MONGO_INITDB_ROOT_USERNAME') || db.createUser({ user: '$MONGO_INITDB_ROOT_USERNAME', pwd: '$MONGO_INITDB_ROOT_PASSWORD', roles: [ 'root' ] })"; \
8# we wait for the replica set to be ready and then submit the commands just above
9until (mongo admin --port $MONGO_REPLICA_PORT --eval "$INIT_REPL_CMD && $INIT_USER_CMD"); do sleep 1; done; \
10# we are done but we keep the container by waiting on signals from the mongo task
11echo "REPLICA SET ONLINE"; wait $MONGOD_PID;
.env
次の環境変数を設定することで、mongo に対して prisma から create/update できるようになりました 🎉
1DATABASE_URL="mongodb://root:root@localhost:27017/mydb?authSource=admin"
そもそも reolica set とは?
A replica set in MongoDB is a group of mongod processes that maintain the same data set. Replica sets provide redundancy and high availability, and are the basis for all production deployments. MongoDB のレプリカセットは、同じデータセットを保持する mongod プロセスのグループです。レプリカセットは冗長性と高可用性を提供し、すべてのプロダクションデプロイメントの基礎となるものです。 replication (公式ページの序文を DeepL で翻訳)
前述のエラーは、MongoDB 側ではなく、Prisma 側が要求していることに注意です。
対応の流れ
mongo 公式の docker hub の内容を参考に次の yml を書いたのですが、これでは前述の エラーが発生します。
1version: "3.9"
2
3services:
4 mongodb:
5 container_name: mongodb
6 image: mongo:6.0
7 ports:
8 - "27017:27017"
9 environment:
10 - MONGO_INITDB_ROOT_USERNAME=${DB_ROOT_USER}
11 - MONGO_INITDB_ROOT_PASSWORD=${DB_ROOT_PASSWORD}
12 volumes:
13 - mongoData:/app:cached
14 restart: always
15
16volumes:
17 mongoData:
18 driver_opts:
19 type: none
20 device: ${PWD}
21 o: bind
22
23networks:
24 default:
25 name: localing
前述のエラーに関して prisma で Issue #8266 もあるのですが(既に Close 済み)4.0
や 5.0
の解決策はあっても 6.0
では見出せませんでした 🤔
Issue をある程度追いかけて、Dockerfile からの起動や、bitnami 製の mongodb を試したり、カスタムした mongodb の設定ファイルをマウントしたりしたのでしたが、ダメでした 😢
そこで、 結論で述べたようにバージョンを落として対応しました。
余談
mongo の Docker コンテナは、本家のmongoと vmware によってカスタムされたbitnami/mongodbがあり、後者が簡単・便利らしいのですが、私では 6.0
を動かせませんでした 😢
また、bitnami/mongodb は、そのほとんどが linux/amd64 でビルドされていたので、Apple シリコンではワーニングになります。実際に若干動作がもっさりしてました。
なぜか、arm のイメージはなさそうです 🤔
おわりに
5.0
は、EOL が October 2024 なのでしばらくは使えそうですが、できることなら July 2025 までサポートされている 6.0
を使いたいですね 💦
https://www.mongodb.com/support-policy/lifecycles
バージョンアップこそ最も軽視されがちなのに重要度が高い作業だと私は考えるためです 💪