Reputation: 23
Unable to establish connections between docker
I am new to the docker world so apologies beforehand if my questions are not clear. So what I am trying to do is have two containers one of which is rest service and the second one is the rest client. I am trying to establish the network connection between the two
Code:
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ProducerApplication {
public static void main(String[] args) {
SpringApplication.run(ProducerApplication.class, args);
}
}
package hello;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
public class SimpleRest {
@RequestMapping("/")
public String getHome(){
return "Hello From Producer";
}
}
server.port=8085
server.servlet.context-path=/producer-service
Code:
package hello;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
@SpringBootApplication
public class ConsumerApplication {
public static void main(String[] args) {
SpringApplication.run(ConsumerApplication.class, args);
}
}
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@RestController
public class SimpleRestConsumer {
@RequestMapping("/")
public String getHello(){
RestTemplate restTemplate = new RestTemplate();
String val = restTemplate.getForObject("http://localhost:8085/producer-service", String.class);
return val;
}
}
server.port=8086
server.servlet.context-path=/consumer-service
address.service.base-path=http://localhost:8085/producer-service
Command line:
docker run -p 8085:8085 -t producer/gs-spring-boot-docker
docker run -p 8086:8086 -t consumer/gs-spring-boot-docker
I added both of the docker in the network
b96ded69570 consumer/gs-spring-boot-docker
5ddc181daed5 producer/gs-spring-boot-docker
docker network create tulip-net
docker network connect tulip-net 5ddc181daed5
docker network connect tulip-net b96ded69570
When I am trying to access the rest service from rest client I am getting this error
Servlet.service() for servlet [dispatcherServlet] in context with path [/consumer-service] threw exception [Request processing failed; nested exception is org.springframework.web.client.ResourceAccessException: I/O error on GET request for "http://localhost:8085/producer-service": Connection refused (Connection refused); nested exception is java.net.ConnectException: Connection refused (Connection refused)] with root cause
java.net.ConnectException: Connection refused (Connection refused)
at java.net.PlainSocketImpl.socketConnect(Native Method) ~[na:1.8.0_302]
at java.net.AbstractPlainSocketImpl.doConnect(AbstractPlainSocketImpl.java:350) ~[na:1.8.0_302]
at java.net.AbstractPlainSocketImpl.connectToAddress(AbstractPlainSocketImpl.java:206) ~[na:1.8.0_302]
at java.net.AbstractPlainSocketImpl.connect(AbstractPlainSocketImpl.java:188) ~[na:1.8.0_302]
at java.net.SocksSocketImpl.connect(SocksSocketImpl.java:392) ~[na:1.8.0_302]
at java.net.Socket.connect(Socket.java:607) ~[na:1.8.0_302]
at java.net.Socket.connect(Socket.java:556) ~[na:1.8.0_302]
at sun.net.NetworkClient.doConnect(NetworkClient.java:180) ~[na:1.8.0_302]
at sun.net.www.http.HttpClient.openServer(HttpClient.java:463) ~[na:1.8.0_302]
at sun.net.www.http.HttpClient.openServer(HttpClient.java:558) ~[na:1.8.0_302]
at sun.net.www.http.HttpClient.<init>(HttpClient.java:242) ~[na:1.8.0_302]
at sun.net.www.http.HttpClient.New(HttpClient.java:339) ~[na:1.8.0_302]
at sun.net.www.http.HttpClient.New(HttpClient.java:357) ~[na:1.8.0_302]
Any idea what I could have done wrong?
Upvotes: 1
Views: 1791
Reputation: 104
Use an alias when attaching your producer to the network. The alias is the hostmane through other dockers in the same network can talk to your producer.
docker network connect tulip-net 5ddc181daed5 --alias producer
use that alias when calling it from the consumer, so instead of calling it using localhost:8085
, you should use producer:8085
When executing docker run -p 8085:8085 -t producer/gs-spring-boot-docker
you are saying that your service can be accessed from your host machine using the port 8085 (since it is exposed by 8085:8056).
However, when trying to access the producer from the consumer, the consumer thinks about localhost:8085
as his own local container, since it doesn't have visibility on the network of the host.
--network=host
to simplify the communicationThere is a way to make dockers see the localhost interface of the real host machine. This is using the --network=host
flag. Using it dockers can talk between them using the localhost reference. It doesn't require creating any docker network, so it is a good option for quick checks in local. You could try it with:
docker run -p 8085:8085 -t producer/gs-spring-boot-docker --network=host
docker run -p 8086:8086 -t consumer/gs-spring-boot-docker --network=host
Upvotes: 2
Reputation: 311278
Your problem is probably that you're attempting to connect to localhost
in your URL:
String val = restTemplate.getForObject("http://localhost:8085/producer-service",
String.class);
Just like on your host, localhost
inside a container means "this container". If the service to which you're trying to connect is running anywhere else (in another container, on the Docker host, elsewhere on the internet), you won't be able to connect to it using localhost
.
You have several options that will work:
Containers can refer to each other by name. This requires that they be running on the same user-defined Docker network (that is, a network you create using docker network create
). In this case, if your container has a name (as in docker run --name server ...
, docker run --name client ...
), your service can just use the name of the server container in the URL (e.g., `http://server:8085/').
If the service is exposed on your host using -p
, you can point your client at any ip address of your host.
It's possible to run two (or more) containers in the same network namespace by setting --network container:<container_name_or_id>
. This is the one situation in which using localhost
would actually work, because in this case all your services are sharing a single network environment.
You can use --network=host
to run your services in the host network environment, but you usually don't want this: you lose much of the network isolation you generally get with Docker, your services may conflict with existing host services, you may unintentionally expose services to public access, etc. Using --network=host
is best avoided unless you know for sure you need it. This is the other situation in which using localhost
in the URL would work.
Option 1 is generally the best option, and is exactly the scenario you get by default using docker-compose.
Upvotes: 1