How to connect graphql and prisma in docker containers? - node.js

I am trying to build a docker-compose file that run a node.js graphql api that uses prisma and mongodb.
But I got an error request to http://localhost:4466/ failed, reason: connect ECONNREFUSED 127.0.0.1:4466 when ever I try to send requests from graphql playground and the same error when I run prisma deploy or just try to ping http:localhost:4466 from inside the graphql container.
I have tried to use the default network and creating new network but I got the same error.
I have tried to use links (which is deprecated) in version 3 but also I got the same error.
P.S I can open the playground of prisma normally in the browser with the link: http://localhost:4466
This is my docker-compose file:
version: '3'
services:
web:
build: .
networks:
net:
ports:
- "80:4000"
command: wait-for-it/wait-for-it.sh http://localhost:4466 -t 30 -- ./run.sh
prisma:
image: prismagraphql/prisma:1.34
restart: always
networks:
net:
ports:
- "4466:4466"
environment:
PRISMA_CONFIG: |
port: 4466
# uncomment the next line and provide the env var PRISMA_MANAGEMENT_API_SECRET=my-secret to activate cluster security
# managementApiSecret: my-secret
databases:
default:
connector: mongo
uri: mongodb://prisma:prisma#mongo
command: /bin/sh.sh
mongo:
image: mongo:3.6
restart: always
networks:
net:
environment:
MONGO_INITDB_ROOT_USERNAME: prisma
MONGO_INITDB_ROOT_PASSWORD: prisma
ports:
- "27017:27017"
volumes:
- mongo:/var/lib/mongo
volumes:
mongo:
networks:
net:
And this is the dockerfile of the web service:
FROM node:10
WORKDIR /app
COPY . /app/
RUN yarn install --pure-lockfile
RUN yarn global add prisma
And this is the run.sh file:
echo "prisma deploy command "
prisma deploy
echo "get-schema command"
yarn run get-schema
echo "starting command"
yarn run start
Are there anything that I misunderstand, Or what I need to fix to make it work?

You should use http://prisma:4466 as the connection URL in your web container. As your containers will be connected to the same network the name of the container will be DNS name and therefor will be resolved to IP of concrete container.

The localhost in your Node application points to the container running Node itself, not your host machine. Replace http://localhost:4466 with http://prisma:4466 or http://<host-machine-local-ip>:4466
To get host IP on a Unix machine run:
hostname -i
Or
ifconfig | awk '/broadcast/ {print $2}'

Change the content of your prisma.yml from
endpoint: http://localhost:4466
datamodel: datamodel.prisma
to
endpoint: http://192.168.99.100:4466
datamodel: datamodel.prisma
This worked for me.

Run your docker container by typing $docker-compose up -d -d flag is for running container in detach mode.
Instead of using endpoint as http://localhost:4466 use http://127.0.1.1:4466 Or check your localhost by the cmd: $localhost -i.
In prisma-binding your constructor should have endpoint as http://127.0.1.1:4466.
const prisma = new Prisma({
typeDefs: './src/generated/prisma.graphql',
endpoint: 'http://127.0.1.1:4466'
});

Related

Docker Prisma Error P1001: Can't reach database server at `postgres`:`5432`

After hours of searchs, I must bow dow and ask you some advices on my problem :
My backend (express + prisma + postgresql) is Dockerized, functionning BUT I can't use npx prisma commands from my wsl2 zsh terminal.
Here is my .env
# Database settings
NODE_ENV=dev
DB_USER=user
DB_PASS=password
DATABASE_URL="postgresql://${DB_USER}:${DB_PASS}#postgres/chimere?schema=public"
Dockerfile :
FROM node:17-alpine3.14 as base
WORKDIR /user/src/app
COPY package*.json /user/src/app/
EXPOSE 5000
FROM base as dev
ENV NODE_ENV=development
RUN npm install -g nodemon && npm install
COPY . /user/src/app/
RUN npx prisma generate
CMD ["nodemon", "src/index.js"]
FROM base as production
ENV NODE_ENV=production
RUN npm ci
COPY . /user/src/app/
RUN npx prisma generate
CMD ["node", "src/index.js"]
docker-compose.yml :
version: '3.8'
services:
postgres:
image: postgres
restart: always
environment:
- POSTGRES_USER=${DB_USER}
- POSTGRES_PASSWORD=${DB_PASS}
volumes:
- postgres:/var/lib/postgresql/data
ports:
- '5432:5432'
web:
build:
context: ./
target: dev
restart: always
volumes:
- .:/usr/src/app
- uploaded-files:/usr/src/app/public/media/files
- uploaded-pictures:/usr/src/app/public/media/pictures
command: npm run start:dev
ports:
- "5000:5000"
environment:
NODE_ENV: development
DEBUG: nodejs-docker-express:*
volumes:
postgres:
uploaded-files:
uploaded-pictures:
and Prisma Schema :
generator client {
provider = "prisma-client-js"
binaryTargets = ["native", "linux-musl"]
}
datasource db {
provider = "postgresql"
url = env("DATABASE_URL")
}
Like you can see I'm prettry new to Docker and almost everything is an adjusted copypasta from Google (:
How can I get my app to work AND get my commands to work aswell ?
Thanks !
I was facing the same issue but it was on a mysql container. Basically I was having a problem with my DATABASE_URL in my .env file. It was looking something like this:
DATABASE_URL="mysql://${DB_USER}:${DB_PASS}#localhost:3306/project_name"
The problem was that localhost. Apparently, when running inside a container, instead of the localhost, it uses the container's name. I changed my docker compose to specify the container's name:
version: '3.1'
services:
db:
image: mysql
container_name: mysql
ports:
- 3306:3306
Notice the container_name property. After that, I changed my .env to:
DATABASE_URL="mysql://${DB_USER}:${DB_PASS}#mysql:3306/project_name"
I would suggest you to try something similar. Maybe something along these lines:
version: '3.8'
services:
postgres:
image: postgres
container_name: postgres
restart: always
environment:
- POSTGRES_USER=${DB_USER}
- POSTGRES_PASSWORD=${DB_PASS}
volumes:
- postgres:/var/lib/postgresql/data
ports:
- '5432:5432'
And for your .env you can leave the way it is now unless you chose a different container's name, then you would subsitute with the name you chose inside the curly braces (remember to remove the curly braces):
DATABASE_URL="postgresql://${DB_USER}:${DB_PASS}#{container_name}/chimere?schema=public"
Check this GitHub issue for more information as well:
https://github.com/prisma/prisma/issues/1385
You need to act from inside the container.
First, create an interactive shell in the container using docker exec:
docker exec -it <name of your containter> sh
Note: the -i flag keeps input open to the container, and the -t flag creates a pseudo-terminal that the shell can attach to.
Then, once inside the container, execute the commands you need:
npx prisma migrate dev --name <name of your migration>

Running commands on docker container from the host

Code first, it will be easier to explain what I'm after.
docker-compose.yml
version: '3.4'
services:
db:
user: '${UID}:${GID}'
image: postgres
container_name: postgres
ports:
- '5432:5432'
restart: always
environment:
POSTGRES_HOST: db
POSTGRES_USER: root
POSTGRES_PASSWORD: secret
POSTGRES_DATABASE: foo
PGDATA: /var/lib/postgresql/data/db
volumes:
- ./db/data:/var/lib/postgresql/data/db
- db-init.sh:/docker-entrypoint-initdb.d/:ro
cache:
image: redis:alpine
container_name: redis
sysctls:
net.core.somaxconn: '511'
ports:
- '6379:6379'
command: ['--requirepass "secret"']
api:
image: node:alpine
container_name: api
working_dir: /var/www/app
command: sh -c "npm start"
ports:
- '5000:5000'
volumes:
- node_modules:/var/www/app/node_modules
- .:/var/www/app
env_file: .env
depends_on:
- db
- cache
volumes:
node_modules:
postgres connection settings for node.js app:
export const {
POSTGRES_USER = 'root',
POSTGRES_PASSWORD = 'secret',
POSTGRES_HOST = 'db',
POSTGRES_PORT = 5432,
POSTGRES_DATABASE = 'foo',
} = process.env
issue:
When using service or container name (db or postgres) for the POSTGRES_HOST setting of node app:
I can successfully connect to, and query, the database.
I'm not able to run commands from host which affect the container. For example, seeding db won't work:
npx knex --esm seed:run
This makes sense, as the DNS resolution for db / postgres is taken care of by docker and those only have meaning on the network connecting the containers. Commands run from the host and targeting that container will fail as host doesn't know how to resolve the DNS here.
On the other hand, when using localhost for the POSTGRES_HOST setting of node app:
Queries to postgres from api will fail.
Commands run from the host, like npx knex --esm seed:run, will succeed.
Again, this makes perfect sense. Addressing container as localhost from host will work thanks to the port forwarding in docker-compose.yml. But in the context of the container, it refers to that very container: for api localhost means itself, and its trying to find a database on localhost:5432 or api:5432.
I want to have working inter-container network and also run commands from the host, addressing the said containers. I'm aware of two approaches to achieve that:
Use container / service name as POSTGRES_HOST, and run commands against the containers with:
docker exec -it <container_name> <command>
Assign static ips to the containers and use those instead of service / container names.
Do I have any other options here?
since you are exposing the database ports on the host machine you can do the following.
Use service or container name (db or postgres) for the POSTGRES_HOST, this way it will work for Docker containers.
when you run the seed command form the host, overwrite the POSTGRES_HOST. This can be done in this way
$ export POSTGRES_HOST=127.0.0.1
$ npx knex --esm seed:run
or in one step
$ POSTGRES_HOST=127.0.0.1 npx knex --esm seed:run

Docker MongoDB immadiately closes connection after receiving metadata

I'm trying to compose docker app with two containers:
mongo
app
Mongo container works just fine, meanwhile app cannot connect to mongo. Neither node.js app nor mongostat can. The weird part is, I tried to run this project on both computers with Win10 and it works normally on the other one.
These are logs from mongo container when I run node app.js or mongostat --uri "mongodb://mongo:27017/project" from app container:
2019-05-22T09:33:52.225+0000 I NETWORK [conn17] received client metadata from 192.168.96.2:42916 conn17: { driver: { name: "nodejs", version: "3.1.10" }, os: { type: "Linux", name: "linux", architecture: "x64", version: "4.9.125-linuxkit" }, platform: "Node.js v10.15.3, LE, mongodb-core: 3.1.9" }
2019-05-22T09:33:52.231+0000 I NETWORK [conn17] end connection 192.168.96.2:42916 (0 connections now open)
This means both containers can see each other so .yml file should be fine. If the problem was with code then it shouldn't work on both computers.
Dockerfile:
FROM node:10.15.3-alpine
RUN apk update && apk --no-cache --virtual build-dependencies add python make g++ && apk del build-dependencies
RUN mkdir -p /home/node/app && chown -R node:node /home/node/app
WORKDIR /home/node/app
COPY package*.json ./
USER node
COPY --chown=node:node . .
ENV NPM_CONFIG_PREFIX=/home/node/.npm-global
RUN npm install
EXPOSE 3000
CMD ["node", "app.js"]
docker-compose.yml:
version: "3.5"
services:
app:
container_name: app
restart: always
build: .
ports:
- "3000:3000"
networks:
- mongo
mongo:
restart: always
container_name: mongo
image: mongo
expose:
- 27017
volumes:
- mongodata:/data/db
ports:
- '27017:27017'
networks:
- mongo
volumes:
mongodata:
networks:
mongo:
external: true
snippet from app.js:
MongoClient.connect('mongodb://mongo:27017/project', {useNewUrlParser: true}, (err, client) => {
if (err) throw err; //throws MongoNetworkError: failed to connect to server [mongo:27017] on first connect [MongoNetworkError: getaddrinfo ENOTFOUND mongo mongo:27017]
console.log("connected");
client.close();//at the moment this line is not being reached because of throw err;
});```
Does it help if you insert a "sleep 10" in your application, before connecting to the mongo db? If so, adding something like wiatforit (https://github.com/maxcnunes/waitforit) might help.
Since you are getting a getaddrinfo ENOTFOUND error, the mongo hostname isn't resolving. Usually, that happens for one of two reasons: 1) your containers aren't on the same network or 2) the other container isn't up and running yet. Seeing that they are on the same network, it sounds like it's something with the container being up.
To troubleshoot, I would start another container, put it on the network, and validate the mongo hostname resolves.
docker container run --rm -ti --network mongo ubuntu
$ apt update && apt install -y dnsutils
$ dig mongo
At this point, you should see the A record resolve to the database. If not, validate the mongo database container is up and running.
You can also try doing this within your app container as well. If that's working, then using something like waitforit should work. This is a common issue, as apps may start up before the database is either running or ready to accept connections.
As one other item of feedback, you don't need to expose the mongo port. This is making it accessible to the world, which most likely isn't what you want. You can still do container-to-container communication without exposing the port.
After hours of trying multiple things I have found solution: turn off Windows Firewall. That's it.
Thanks, I appreciate your help.

Nodejs application docker unable to connect to mongodb docker container

I have a nodejs application which dockerized and need a replicated MongoDB database. I have built my replicated MongoDB in docker-compose and working just fine. if I run the command docker inspect MongoDB-primary |grep IPAddress its print:
"IPAddress": "",
"IPAddress": "172.18.0.2",
now in my application, i give this ip as mongoconnection string(of course with protocol names) but the application cannot connect to MongoDB and throw this error message(application also is a docker container):
message: 'failed to connect to server [172.18.0.2:27017] on first connect [MongoNetworkError: connection 1 to 172.18.0.2:27017 timed out]',
here is my mongodb docker compose file:
version: '2'
services:
mongodb-primary:
image: 'bitnami/mongodb:latest'
environment:
- MONGODB_REPLICA_SET_MODE=primary
volumes:
- 'mongodb_master_data:/bitnami'
mongodb-secondary:
image: 'bitnami/mongodb:latest'
depends_on:
- mongodb-primary
environment:
- MONGODB_REPLICA_SET_MODE=secondary
- MONGODB_PRIMARY_HOST=mongodb-primary
- MONGODB_PRIMARY_PORT_NUMBER=27017
mongodb-arbiter:
image: 'bitnami/mongodb:latest'
depends_on:
- mongodb-primary
environment:
- MONGODB_REPLICA_SET_MODE=arbiter
- MONGODB_PRIMARY_HOST=mongodb-primary
- MONGODB_PRIMARY_PORT_NUMBER=27017
volumes:
mongodb_master_data:
driver: local
and my node js application dockerfile is:
FROM node:6.0
# Create app directory
WORKDIR /usr/src/app
# Install app dependencies
# A wildcard is used to ensure both package.json AND package-lock.json are copied
# where available (npm#5+)
COPY package*.json ./
RUN npm install
# If you are building your code for production
# RUN npm install --only=productio
# Bundle app source
COPY . .
EXPOSE 3001
CMD [ "npm", "start" ]
how can I fix this?
Your docker-compose does not automatically expose tcp ports to the outer world, like your host PC (I assume your nodeJs runs on host and not included in docker-compose). This is the behavior of docker bridge networks, you can read more at https://docs.docker.com/network/bridge/
You have to do one of the following:
Include your NodeJs container into docker-compose
or
Expose ports from docker-compose.yml
I had the same issue and adding the ports fixed it for me.
Make sure your connection url includes the image name:
mongodb://mongo:27017/ and not localhost.
mongo:
image: mongo
expose:
- 27017
ports:
- "27017:27017"
volumes:
- ./data/db:/data/db

Cannot connect to MongoDB via node.js in Docker

My node.js express app cannot connect to the MongoDB in a Docker. I'm not that familiar with Docker.
node.js connection:
import mongodb from 'mongodb';
...
mongodb.MongoClient.connect('mongodb://localhost:27017', ... );
Dockerfile:
FROM node:argon
RUN mkdir /app
WORKDIR /app
COPY package.json /app
RUN npm install
COPY . /app
EXPOSE 3000
CMD ["npm", "start"]
docker-compose.yml
version: “2”
services:
web:
build: .
volumes:
— ./:/app
ports:
— “3000:3000”
links:
— mongo
mongo:
image: mongo
ports:
— “27017:27017”
Build command: docker build -t NAME .
Run command: docker run -ti -p 3000:3000 NAME
Connection error:
[MongoError: failed to connect to server [localhost:27017] on first connect [MongoError: connect ECONNREFUSED 127.0.0.1:27017]]
name: 'MongoError',
message: 'failed to connect to server [localhost:27017] on first connect [MongoError: connect ECONNREFUSED 127.0.0.1:27017]'
Try:
mongodb.MongoClient.connect('mongodb://mongo:27017', ... );
Change your docker-compose.yml:
version: "2"
services:
web:
build: .
volumes:
- ./:/app
ports:
- "3000:3000"
links:
- mongo
mongo:
image: mongo
ports:
- "27017:27017"
And use some docker compose commands:
docker-compose down
docker-compose build
docker-compose up -d mongo
docker-compose up web
Try this.
When using linked docker containers you should use the name of the container in this case for example your connection to mongodb should be mongodb.MongoClient.connect('mongodb://mongo:27017', ... ); instead of mongodb.MongoClient.connect('mongodb://localhost:27017', ... );. The reason for changing it to mongo is because you used the links attribute to mongo in your docker-compose.yml. That would result to a hostname of mongo in your /etc/hosts of the web docker container. Reference linking-containers.
The docker-compose.yml seems to be lacking an indention. On the mongo attribute should be the same level as web.
version: '2'
services:
web:
build: .
volumes: ['./:/app']
ports: [ '3000:3000' ]
links: [ mongo ]
mongo:
image: mongo
ports: [ '27017:27017' ]
I tried your configuration using my docker what Ive done is update docker-compose.yml then I docker-compose build then docker-compose up. Logs of my local run
I am not sure if you still have this question, but the datasources.json should be:
"host": "mongo"
rather than "localhost".
In my logs I see:
mongo | NETWORK [listener] connection accepted from 172.22.0.3:47880 #1 (1 connection now open)
As you can see, docker compose will NAT mongo to another V-LAN. The IP address 172.22.0.0 is an internal IP address used by the daemon to route a docker-compose image. So localhost is now not in the game.
At least, it works for me.
datasources.json
"mongoDS": {
"host": "mongo",
"port": 27017,
...
in my case works like this :
just link to the container from the command line. db is my up database container
sudo docker run -it --link db:db1 --publish 4000-4006:4000-4006 --name backend backend:latest

Resources