Paul
Paul

Reputation: 1355

can't acces mongo from inside docker

I'm trying to access mongo from inside of a docker container The error occurs when I'm trying to create the connection.

new MongoClient(host, port)is working.

mongo is also running in a docker container and I was able to connect to it with robomongo and also running the app outside its docker container can connect do mongo

I'm getting following exception

No server chosen by WritableServerSelector from cluster description ClusterDescription{type=UNKNOWN, connectionMode=SINGLE, serverDescriptions=[ServerDescription{address=172.17.0.1:27017, type=UNKNOWN, state=CONNECTING}]}


2017-05-25T21:11:32.277  INFO 5 --- [72.17.0.1:27017] org.mongodb.driver.cluster               : Exception in monitor thread while connecting to server 172.17.0.1:27017
com.mongodb.MongoSocketOpenException: Exception opening socket
at com.mongodb.connection.SocketStream.open(SocketStream.java:63)
at com.mongodb.connection.InternalStreamConnection.open(InternalStreamConnection.java:115)
at com.mongodb.connection.DefaultServerMonitor$ServerMonitorRunnable.run(DefaultServerMonitor.java:113)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.net.SocketTimeoutException: connect timed out
at java.net.PlainSocketImpl.socketConnect(Native Method)
at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350)
at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206)
at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188)
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392)
at java.net.Socket.connect(Socket.java:589)
at com.mongodb.connection.SocketStreamHelper.initialize(SocketStreamHelper.java:57)
at com.mongodb.connection.SocketStream.open(SocketStream.java:58)
... 3 common frames omitted

docker-compose.yml

mongo:
 image: library/mongo:3.4.4
 ports: 
   - "27017:27017"
   - "28017:28017"
   - "28018:28018"
 volumes:
   - ./data/mongo:/data/db

dronedelivery:
  image: paulcurcean/dronedelivery:latest
  ports:
   - "8080:8080"

Dockerfile for dronedelivery

ADD dronedelivery-0-SNAPSHOT.jar /
ADD start.sh /  # java -jar dronedelivery-0-SNAPSHOT.jar
CMD ["sh", "/start.sh"]

docker ps / docker-compose ps

image                 ports
dronedelivery         0.0.0.0:8080 -> 8080/tcp
mongo                 0.0.0.0:27017 -> 27017/tcp, 0.0.0.0:28017-28018 -> 28017-28018/tcp

I'm connecting to mongo via new MongoClient(host, port)

Upvotes: 6

Views: 10281

Answers (2)

andreim
andreim

Reputation: 3503

I think the problem you are encountering is due to the fact that you are referencing the host incorrectly.

I created a working POC here in order create two containers, a SpringBoot application container and the Mongo container. The information and instructions are in the README.md.

There are multiple points which may cause your app to malfunction:

  • you might need to ensure that your app should run after Mongo is functioning properly
  • your containers are by default connected to the default bridge network which is a separate network than the host network (your actual main network). The bridge network is connected to your main host network. Therefore referencing one container from another container needs to be done in respect to the network used to connect the containers, thus the bridge network.
  • having in docker-compose.yml - services.mymongo with ports 12345:27017 means that the Mongo database can be referred to from another container as mymongo:27017 but from host like localhost:12345. Using from another container localhost:27017 is incorrect because mymongo is one host and myapp for example is another. Calling localhost from myapp does not mean mymongo host.
  • in order to query the health of your Mongo instance you can enable the REST api using mongod --rest. Thus command: ["mongod", "--rest"] in docker-compose.yml. This is used when starting the app container in order to know if the Mongo instance is up and running.

Sample docker-compose.yml:

version: '3'

services:
  myapp:
    build: ./myapp/docker
    environment:
      - SERVER_PORT=8080
      - MONGODB_URI=mongodb://mymongo:27017/mydb
      - MONGODB_STATUS_HOST=mymongo
      - MONGODB_STATUS_PORT=28017
    ports:
      - 8888:8080
  mymongo:
    image: mongo:3.4
    volumes:
      - ./_data:/data/db
    ports:
      - 12345:27017
      - 23456:28017
    command: ["mongod", "--rest"]

Notice that Mongo is configured on port 27017 and thus the REST interface will be available on 27017 + 1000 = 28017.

Sample app Dockerfile

The following is the Dockerfile for creating the image of the app that connects to the Mongo instance:

FROM openjdk:8-jdk-alpine
RUN  apk update && apk upgrade && apk add netcat-openbsd
RUN mkdir -p /usr/local/myapp
ADD ./myapp.jar /usr/local/myapp/
ADD run.sh run.sh
RUN chmod +x run.sh
CMD ./run.sh

Then the app is started with the following run.sh script:

#!/bin/sh

echo "********************************************************"
echo "Wait for mongodb to be available"
echo "********************************************************"

while ! nc -z $MONGODB_STATUS_HOST $MONGODB_STATUS_PORT; do
  printf 'mongodb is still not available. Retrying...\n'
  sleep 3
done

echo "********************************************************"
echo "Starting myapp"
echo "********************************************************"

java -Dserver.port=$SERVER_PORT \
     -Dspring.data.mongodb.uri=$MONGODB_URI \
     -jar /usr/local/myapp/myapp.jar

Notice that it first waits for the Mongo instance to start by querying its REST interface and just after that it uses the OpenJdk 8 JRE to start the app from its .jar file.

Upvotes: 5

Gonzalo
Gonzalo

Reputation: 530

You could use docker-compose instead.

First, install docker-compose.

I assume you are using a Dockerfile for your application.

Create a directory with a docker-compose.yml inside.

version: '2'
services:

  mongo:
    image: mongo:latest
    restart: always

  app:
    build: ./app
    restart: always
    volumes:
      - ./_client/:/var/www/html/
    links:
      - mongo
    ports:
      - "80:80"

Now, in ./app put your current Dockerfile for the application.

In a _client/ folder put your app (you can correct the internal path /var/www/html as you need). Both folders in the same level as docker-compose.yml file.

Finally, run all with docker-compose:

docker-compose -f /path/to/your/docker-compose.yml build

This command will build the image from your Dockerfile

docker-compose -f /path/to/your/docker-compose.yml up

This command will create and run all defined containers.

To access your mongodb container from inside the app container, you can use "mongo" as hostname (same name defined in "services:"). From your host machine, you can use the docker container IP, but you need to expose a port, same way as "app" service in the docker-compose.yml.

Upvotes: 1

Related Questions