Reputation: 1355
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
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:
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.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.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
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