Reputation: 61
I am trying to connect a spring boot docker container to a mongodb docker container. While developing Spring Boot app, I used a MongoDB docker container with port 27017 mapped to the host machine's 27017 port with docker run -p 27017:27017 mongo:3.4
. When development finished, I containerized the spring app, but containerized spring app could not connect to the mongodb container. I know the problem is spring app is looking for mongodb at localhost. My question is how should I modify the app so that instead of looking for mongodb at localhost, it uses mongodb containers's address?
My database connections are handled with class below:
public class DB {
private final Datastore datastore;
private Morphia morphia;
/**
* Constructor for creating database instance
*/
public DB() {
morphia = new Morphia();
morphia.mapPackage("users");
datastore =
morphia.createDatastore(new MongoClient(), "test");
datastore.ensureIndexes();
}
/**
* Inserts given user to the database
*
* @param u a newly created user.
*/
public void addUser(User u) {
datastore.save(u);
}
/**
* Fetches and prints all documents in database
*
* @return json array of all documents in database
*/
public String getUsers() {
final Query<User> query = datastore.createQuery(User.class);
final List<User> employees = query.asList();
return objToJson(employees);
}
/**
* Returns the user with the specified ID.
*
* @param userID is the ID of the document in database
* @return document in json format
*/
public String getUser(ObjectId userID) {
final Query<User> query = datastore.createQuery(User.class)
.field("id").equal(userID);
final List<User> employees = query.asList();
return objToJson(employees);
}
/**
* Deletes the document with the given ID from database.
*
* @param userID is the ID of the document to be removed
*/
public void removeUser(ObjectId userID) {
final Query<User> query = datastore.createQuery(User.class)
.field("id").equal(userID);
datastore.delete(query);
}
/**
* Deletes all documents from database.
*/
public void removeUsers() {
final Query<User> query = datastore.createQuery(User.class);
datastore.delete(query);
}
/**
* Updates the fields of the document with given ID.
*
* @param userID is the ID of the document to be updated
* @param newUser contains the new fields
* @return results of the update in json format
*/
public String updateUser(ObjectId userID, User newUser) {
final Query<User> query = datastore.createQuery(User.class)
.field("id").equal(userID);
final UpdateOperations<User> updateOperations = datastore.createUpdateOperations(User.class);
if (newUser.getFirst_name() != null) {
String newName = newUser.getFirst_name();
updateOperations.set("first_name", newName);
}
if (newUser.getLast_name() != null) {
String newLastName = newUser.getLast_name();
updateOperations.set("last_name", newLastName);
}
if (newUser.getSalary() != 0) {
int newSalary = newUser.getSalary();
updateOperations.set("salary", newSalary);
}
final UpdateResults results = datastore.update(query, updateOperations);
return results.toString();
}
/**
* Translate object lists to the json array.
*
* @param query is the list of the user objects
* @return json array of the given users
*/
private String objToJson(List<User> query) {
List<String> attsToRemove = Arrays.asList(new String[]{"className"});
List<DBObject> dbObjList = new ArrayList<>(query.size());
DBObject dbObj;
for (Object obj : query) {
dbObj = morphia.toDBObject(obj);
for (int i = 0; i < attsToRemove.size(); i++) {
dbObj.removeField(attsToRemove.get(i));
}
dbObjList.add(dbObj);
}
String json = JSON.serialize(dbObjList);
return json;
}
Here is my spring boot controller
@RestController
public class DemoController {
DB mongodb = new DB();
@RequestMapping(value = "/", method = RequestMethod.GET)
public String index() {
return "Greetings from Spring Boot";
}
@RequestMapping(value = "/users/{user_id}", method = RequestMethod.GET)
public String getUser(@PathVariable("user_id") ObjectId userID) {
return mongodb.getUser(userID);
}
@RequestMapping(value = "/users", method = RequestMethod.GET)
public String getUsers() {
return mongodb.getUsers();
}
@RequestMapping(value = "/users", method = RequestMethod.POST)
public void createUser(@RequestBody User u) {
try {
mongodb.addUser(u);
} catch (Exception e) {
System.out.println(e.toString());
}
}
@RequestMapping(value = "/users", method = RequestMethod.DELETE)
public void deleteUsers() {
try {
mongodb.removeUsers();
} catch (Exception e) {
System.out.println(e.toString());
}
}
@RequestMapping(value = "/users/{user-id}", method = RequestMethod.DELETE)
public void deleteUser(@PathVariable("user-id") ObjectId userID) {
try {
mongodb.removeUser(userID);
} catch (Exception e) {
System.out.println(e.toString());
}
}
@RequestMapping(value = "/users/{user-id}", method = RequestMethod.PUT)
public String updateUser(@PathVariable("user-id") ObjectId userID, @RequestBody User u) {
return mongodb.updateUser(userID, u);
}
And here is my Dockerfile:
FROM frolvlad/alpine-oraclejdk8:slim
VOLUME /tmp
ADD demo-0.0.1-SNAPSHOT.jar app.jar
EXPOSE 27017
EXPOSE 8080
RUN sh -c 'touch /app.jar'
ENV JAVA_OPTS=""
ENTRYPOINT [ "sh", "-c", "java $JAVA_OPTS -Djava.security.egd=file:/dev/./urandom -jar /app.jar" ]
I read the solutions mentioned here and here. Also read through couple of tutorials but I couldn't fit any of these solutions to my code. In my code, where should I change?
Upvotes: 0
Views: 3474
Reputation: 658
The main issue is that your containers are not in the same network. I guess you can find a working example by this How to run Spring Boot and MongoDB in Docker containe. Here is a short extract:
docker network create spring_demo_net
create a networkdocker run --name spring-demo-mongo --network=spring_demo_net -v /home/ubuntu/mongo-data:/data/db -d mongo
start a mongo containerspring.data.mongodb.uri=mongodb://spring-demo-mongo/YOUR_DB
here spring-demo-mongo is the name of container that you created on step 1. Since you are not using SpringData repositories it will not work so you need to create a MongoClient by explicitly passing host and port:
MongoClient mongoClient2 = new MongoClient("spring-demo-mongo", 27017);
docker build --tag=spring-demo-1.0
build your docker image with tag docker run -d --name spring-demo --network=spring_demo_net -p 8080:8080 spring-demo-1.0
start your docker image Upvotes: 5