gomze
gomze

Reputation: 23

Unable to establish connections between docker

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

Server

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

Client

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

Answers (2)

jkmrto
jkmrto

Reputation: 104

Quick Answer:

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

Explanation

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.

Using --network=host to simplify the communication

There 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

larsks
larsks

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:

  1. 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/').

  2. If the service is exposed on your host using -p, you can point your client at any ip address of your host.

  3. 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.

  4. 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

Related Questions