I have nestjs application with prisma mongodb setup. Nestjs connects well to dockerized mongo while running itself (nestjs) outside docker.
But when I try to run nestjs inside docker, it can’t connect to mongo.
docker-compose.yml
version: '3.8'
# For connection urls to the following instances, see
# https://github.com/prisma/prisma/blob/main/TESTING.md#environment-variables
services:
# Replica Set (required for Prisma Client)
mongo:
container_name: mongo
build:
dockerfile: ./docker/mongo.Dockerfile
environment:
MONGO_INITDB_ROOT_USERNAME: root
MONGO_INITDB_ROOT_PASSWORD: prisma
MONGO_REPLICA_HOST: 127.0.0.1
MONGO_REPLICA_PORT: 27018
env_file:
- .env
ports:
- '27018:27018'
web:
build:
dockerfile: ./docker/app.Dockerfile
environment:
DATABASE_URL: mongodb://root:prisma@mongo:27018/bookmeon?authSource=admin
env_file:
- .env
ports:
- '1337:1337'
depends_on:
- mongo
mongo.Dockerfile:
###################
# MONGO container - for replication
###################
FROM mongo:4 As mongo
# we take over the default & start mongo in replica set mode in a background task
ENTRYPOINT mongod --port $MONGO_REPLICA_PORT --replSet rs0 --bind_ip 0.0.0.0 & MONGOD_PID=$!;
# we prepare the replica set with a single node and prepare the root user config
INIT_REPL_CMD="rs.initiate({ _id: 'rs0', members: [{ _id: 0, host: '$MONGO_REPLICA_HOST:$MONGO_REPLICA_PORT' }] })";
INIT_USER_CMD="db.getUser('$MONGO_INITDB_ROOT_USERNAME') || db.createUser({ user: '$MONGO_INITDB_ROOT_USERNAME', pwd: '$MONGO_INITDB_ROOT_PASSWORD', roles: [ 'root' ] })";
# we wait for the replica set to be ready and then submit the commands just above
until (mongo admin --port $MONGO_REPLICA_PORT --eval "$INIT_REPL_CMD && $INIT_USER_CMD"); do sleep 1; done;
# we are done but we keep the container by waiting on signals from the mongo task
echo "REPLICA SET ONLINE"; wait $MONGOD_PID;
app.Dockerfile:
###################
# base
###################
#FROM node:20.5.1-alpine3.18 As base
FROM node:20.5.1-alpine3.18 As base
RUN apk add openssl1.1-compat
RUN apk add musl
RUN npm i -g pnpm
###################
# deps install
###################
FROM base As deps
WORKDIR /my
COPY --chown=node:node ./package.json .
RUN pnpm i
###################
# build
###################
FROM base As build
WORKDIR /my
COPY --chown=node:node --from=deps ./my/. .
COPY --chown=node:node ./tsconfig* .
COPY --chown=node:node ./webpack.js .
COPY --chown=node:node ./prisma ./prisma
COPY --chown=node:node ./src ./src
COPY --chown=node:node ./aps ./aps
ARG DATABASE_URL="mongodb://root:prisma@mongo:27018/bookmeon?authSource=admin"
RUN pnpm exec prisma generate
RUN pnpm run build
USER node
CMD [ "node", "dist/main.js" ]
.env:
DATABASE_URL="mongodb://root:prisma@mongo:27018/bookmeon?authSource=admin"
MONGO_INITDB_ROOT_USERNAME=root
MONGO_INITDB_ROOT_PASSWORD=prisma
MONGO_REPLICA_HOST=127.0.0.1
MONGO_REPLICA_PORT=27018
NODE_ENV=staging
FORCE_WWW=0
FORCE_TLS=0
Error i get in dockerized nestjs:
book_me_on-web-1 | PrismaClientInitializationError: Raw query failed. Code: `unknown`. Message: `Server selection timeout: No available servers. Topology: { Type: ReplicaSetNoPrimary, Servers: [ { Address: 127.0.0.1:27018, Type: Unknown, Error: Connection refused (os error 111) }, ] }`
book_me_on-web-1 | at r (/my/node_modules/.pnpm/@[email protected][email protected]/node_modules/@prisma/client/runtime/library.js:103:2766)
book_me_on-web-1 | at async Proxy.onModuleInit (/my/dist/prisma.service.js:14:9)
book_me_on-web-1 | at async Promise.all (index 0)
book_me_on-web-1 | at async callModuleInitHook (/my/node_modules/.pnpm/@[email protected]_@[email protected]_@[email protected][email protected][email protected]/node_modules/@nestjs/core/hooks/on-module-init.hook.js:43:5)
book_me_on-web-1 | at async NestApplication.callInitHook (/my/node_modules/.pnpm/@[email protected]_@[email protected]_@[email protected][email protected][email protected]/node_modules/@nestjs/core/nest-application-context.js:223:13)
book_me_on-web-1 | at async NestApplication.init (/my/node_modules/.pnpm/@[email protected]_@[email protected]_@[email protected][email protected][email protected]/node_modules/@nestjs/core/nest-application.js:97:9)
book_me_on-web-1 | at async NestApplication.listen (/my/node_modules/.pnpm/@[email protected]_@[email protected]_@[email protected][email protected][email protected]/node_modules/@nestjs/core/nest-application.js:166:33)
book_me_on-web-1 | at async bootstrap (/my/dist/main.js:21:5) {
book_me_on-web-1 | clientVersion: '5.0.0',
book_me_on-web-1 | errorCode: 'P2010'
book_me_on-web-1 | }
book_me_on-web-1 |
book_me_on-web-1 | Node.js v20.5.1
UPDATE:
I tried to create small docker container which logs some runtime envs (and changed MONGO_REPLICA_HOST to 172.19.0.2 manually);
FROM node:20.5.1-alpine3.18 as base
# ping $MONGO_REPLICA_HOST:$MONGO_REPLICA_PORT;
ENTRYPOINT echo $NODE_ENV;
sleep 5s & PID=$!;
echo $MONGO_REPLICA_PORT;
echo $MONGO_REPLICA_HOST;
ping "mongo":$MONGO_REPLICA_PORT;
echo "Done";
echo "Process ID" + PID;
As a result in resulting log i see that nestjs tries to connect to
172.19.0.2:27018, while in this new test container I see that mongo is pinged by 172.19.0.3:27018 (using mongo host name)
web | PrismaClientInitializationError: Raw query failed. Code: `unknown`. Message: `Server selection timeout: No available servers. Topology: { Type: Unknown, Servers: [ { Address: 172.19.0.2:27018, Type: Unknown, Error: Connection refused (os error 111) }, ] }`
So looks like mongo runs on a bit another ip address than I start it and nestjs tries to connect to wrong place in docker.
2
Answers
I was sure that it's something with prisma client generation IP address substitution, but turned out it was my docker daemon. I have completely reinstalled docker daemon (removed all images/containers as well) and reinstalled all images, recreated containers again.
And with no changes in dockerfiles, dockercompose or prisma scheme nestjs starts well now. Thanks to everyone!
When running within Docker, your localhost (127.0.0.1) is not visible to Docker network – you need to set your env variable
MONGO_REPLICA_HOST
tomongo
(the name of the service you have defined in your docker-compose), that way Docker will understand which service you are pointing to and will automatically set the host value