2

I am trying to use Consul as discovery service, and another two spring boot app to register with Consul; and put them into docker;

following are my codes: app:

server:
  port: 3333

spring:
  application:
    name: adder
  cloud:
    consul:
      host: consul
      port: 8500
      discovery:
        preferIpAddress: true
        healthCheckPath: /health
        healthCheckInterval: 15s
        instanceId: ${spring.application.name}:${spring.application.instance_id:${server.port}}

2 docker-compose.yml

 consul1:
  image: "progrium/consul:latest"
  container_name: "consul1"
  hostname: "consul1"
  command: "-server -bootstrap -ui-dir /ui"
 adder:
  image: wsy/adder
  ports:
   - "3333:3333"
 links:
   - consul1
 environment:
   WAIT_FOR_HOSTS: consul1:8500

There is another similar question Cannot link Consul and Spring Boot app in Docker; the answer suggests, the app should wait for consul to fully work by using depends_on, which I tried, but didn't work;

the error message is as following:

adder_1    | com.ecwid.consul.transport.TransportException: java.net.ConnectException: Connection refused
adder_1    |    at com.ecwid.consul.transport.AbstractHttpTransport.executeRequest(AbstractHttpTransport.java:80) ~[consul-api-1.1.8.jar!/:na]
adder_1    |    at com.ecwid.consul.transport.AbstractHttpTransport.makeGetRequest(AbstractHttpTransport.java:39) ~[consul-api-1.1.8.jar!/:na]

besides spring boot application.yml and docker-compose.yml, following is App's Dockerfile

FROM java:8

VOLUME /tmp
ADD adder-0.0.1-SNAPSHOT.jar app.jar
RUN bash -c 'touch /app.jar'
ADD start.sh start.sh
RUN bash -c 'chmod +x /start.sh'
EXPOSE 3333
ENTRYPOINT ["/start.sh", " java -Djava.security.egd=file:/dev/./urandom    -jar /app.jar"]

and the start.sh

#!/bin/bash

set -e

wait_single_host() {
  local host=$1
  shift
  local port=$1
  shift

  echo "waiting for TCP connection to $host:$port..."

  while ! nc ${host} ${port} > /dev/null 2>&1 < /dev/null
  do
    echo "TCP connection  [$host] not ready, will try again..."
    sleep 1
 done

  echo "TCP connection ready. Executing command [$host] now..."
}

 wait_all_hosts() {
  if [ ! -z "$WAIT_FOR_HOSTS" ]; then
   local separator=':'
   for _HOST in $WAIT_FOR_HOSTS ; do
      IFS="${separator}" read -ra _HOST_PARTS <<< "$_HOST"
      wait_single_host "${_HOST_PARTS[0]}" "${_HOST_PARTS[1]}"
    done
   else
     echo "IMPORTANT : Waiting for nothing because no $WAIT_FOR_HOSTS env var defined !!!"
   fi
  }

  wait_all_hosts

  exec $1
Community
  • 1
  • 1
user1484819
  • 899
  • 1
  • 7
  • 18

3 Answers3

0

Your problem is that depends_on does only control the startup order of your services. You have to wait until the consul servers are up and running before starting your spring app. You can do this with this script:

#!/bin/bash

set -e

default_host="database"
default_port="3306"

host="${2:-$default_host}"
port="${3:-$default_port}"

echo "waiting for TCP connection to $host:$port..."

while ! (echo >/dev/tcp/$host/$port) &>/dev/null
do
  sleep 1
done

echo "TCP connection ready. Executing command [$1] now..."

exec $1

Usage in you docker file:

COPY wait.sh /wait.sh
RUN chmod +x /wait.sh
CMD ["/wait.sh", "java -jar yourApp-jar" , "consulURL" , "ConsulPort" ]
Ohmen
  • 6,194
  • 3
  • 25
  • 35
  • I used your script, but still not working. I just print out "TCP connection ready...", then pass through, and give the same connection refused failure. – user1484819 Aug 01 '16 at 11:57
  • I replaced echo >/dev/tcp/$host/$port) &>/dev/null with nc ${host} ${port} > /dev/null 2>&1 < /dev/null, then it just keep waiting and waiting. – user1484819 Aug 01 '16 at 11:59
  • try to first start the consuls, wait until they are fully up and ready and then start the adder manualy. – Ohmen Aug 01 '16 at 14:13
  • I did, put them into different compose scripts, and use external_links, still fail; – user1484819 Aug 02 '16 at 01:22
  • what do you mean consulURL? I tried consul1 directly, not working. so how can I get it? – user1484819 Aug 02 '16 at 07:01
  • your app (addr) has to define an URL for your Servicediscoverer (Consul) and you have to make sure that this url is correct. Please post the complete stacktrace – Ohmen Aug 02 '16 at 07:15
  • try to exec a bash inside your app container and then first ping consul and then try to open a tcp connection to consul:8500 (via nc) if this succedes the network is set up propperly and you have a bug in your wait script. If not i cant help you any further. – Ohmen Aug 02 '16 at 07:53
0

I just want to clarify that, at last I still don't have a solution, and can't understand the situation here; I tried the suggestion from Ohmen, in APP container, I am able to ping consul1; But the APP still fails to connect consul;

If I only start the consul by following command:

docker-compose -f docker-compose-discovery.yml up discovery

Then I can run the APP directly(through Main), and it is able to connect with spring.cloud.consul.host: discovery;

But if I try to run APP in docker container, like following:

docker run --name adder --link discovery-consul:discovery wsy/adder

It fails again with connection refused;

I am very new to docker & docker-compose; I thought it would be a good example to start, but it seems not that easy for me;

user1484819
  • 899
  • 1
  • 7
  • 18
0

I can infer that your Consul configuration is located in your application.yml instead of bootstrap.yml, that's the problem.

According to this answer, bootstrap.yml is loaded before application.yml and Consul client has to check its configuration before the application itself and therefore look at the bootstrap.yml.

Example of a working bootstrap.yml :

spring:
  cloud:
    consul:
      host: consul
      port: 8500
      discovery:
        prefer-ip-address: true
  1. Run Consul server and do not forget the name option to match with your configuration:

    docker run -d -p 8500:8500 --name=consul progrium/consul -server -bootstrap

  2. Consul server is now running, run your application image (builded previously with your artifact) and link it to the Consul container:

    docker run -d -name=my-consul-client-app --link consul:consul acme/spring-app

Alex L.
  • 813
  • 2
  • 17
  • 34
  • You are totally right. After I rename application.yml to bootstrap.yml, it just works as expected; thanks a lot – user1484819 Aug 23 '16 at 11:19