在客户端重新启动之前,无法使用docker compose访问Spring配置服务器

在客户端重新启动之前,无法使用docker compose访问Spring配置服务器,spring,spring-boot,docker,docker-compose,netflix-eureka,Spring,Spring Boot,Docker,Docker Compose,Netflix Eureka,我使用Eureka、配置服务器和我的客户端进行了“发现优先”设置 问题是这3个服务按顺序启动,但客户机服务器似乎注册得太早,并且永远找不到配置服务器。我尝试了一个第三方库,它允许等待config server:8888可用,但这似乎并不总是有效。这类似于比赛状态 解决方法是,如果我在一切就绪后重新启动客户机服务器,它会注册并发现配置服务器很好 第一次运行docker compose: Fetching config from server at : http://localhost:8888 C

我使用Eureka、配置服务器和我的客户端进行了“发现优先”设置

问题是这3个服务按顺序启动,但客户机服务器似乎注册得太早,并且永远找不到配置服务器。我尝试了一个第三方库,它允许等待config server:8888可用,但这似乎并不总是有效。这类似于比赛状态

解决方法是,如果我在一切就绪后重新启动客户机服务器,它会注册并发现配置服务器很好

第一次运行docker compose:

Fetching config from server at : http://localhost:8888
Connect Timeout Exception on Url - http://localhost:8888. Will be trying the next url if available
当I
docker重新启动客户机时:

Fetching config from server at : http://a80b001d04a7:8888/
Located environment: name=client-server, profiles=[default], label=null, version=053c8e1b14dc0281d5af0349c9b2cf012c1a346f, state=null
我不确定docker-compose.yml是否没有足够快地设置JAVA_OPTS属性,或者是否存在网络竞争条件,或者是什么。我在这件事上反复讨论太久了

我的配置如下:

这是我的docker-compose.yml:

version: '3'
services:
  eureka:
    image: eureka-server:latest
    environment:
    - "JAVA_OPTS=-DEUREKA_SERVER=http://eureka:8761/eureka"
    ports:
      - 8761:8761
  config:
    image: config-server:latest
    environment:
      - "JAVA_OPTS=-DEUREKA_SERVER=http://eureka:8761/eureka"
    depends_on:
      - eureka
    ports:
      - 8888:8888
  client:
    image: client-server:latest
    environment:
      JAVA_OPTS: -DEUREKA_SERVER=http://eureka:8761/eureka
    depends_on:
      - config
    ports:
      - 9000:9000
以下是eureka server application.yml:

server:
  port: 8761

spring:
  application:
    name: eureka-server

eureka:
  client:
    registerWithEureka: false
    fetchRegistry: false
    service-url:
      defaultZone: ${EUREKA_SERVER:http://localhost:8761/eureka}
以下是配置服务器bootstrap.yml:

server:
  port: 8888

eureka:
  client:
    serviceUrl:
      defaultZone: ${EUREKA_SERVER:http://localhost:8761/eureka}

spring:
  application:
    name: config-server
spring:
  application:
    name: client-server
  cloud:
    config:
      discovery:
        enabled: true
        serviceId: config-server
      fast-fail: true
    retry:
      max-attempts: 10000
      max-interval: 1000

eureka:
  instance:
    hostname: client-server
  client:
    registerWithEureka: true
    fetchRegistry: true
    serviceUrl:
      defaultZone: ${EUREKA_SERVER:http://localhost:8761/eureka}
以下是客户机服务器bootstrap.yml:

server:
  port: 8888

eureka:
  client:
    serviceUrl:
      defaultZone: ${EUREKA_SERVER:http://localhost:8761/eureka}

spring:
  application:
    name: config-server
spring:
  application:
    name: client-server
  cloud:
    config:
      discovery:
        enabled: true
        serviceId: config-server
      fast-fail: true
    retry:
      max-attempts: 10000
      max-interval: 1000

eureka:
  instance:
    hostname: client-server
  client:
    registerWithEureka: true
    fetchRegistry: true
    serviceUrl:
      defaultZone: ${EUREKA_SERVER:http://localhost:8761/eureka}
编辑:

通过使用docker compose wait库(),我可以让客户机服务器等待eureka和config可用,然后等待90秒(eureka文档表明注册可能需要90秒),并且它似乎可以持续工作


这是一个可以接受的解决方案吗?感觉有点像黑客。

最好的解决方案可能是,让您的应用程序能够适应配置服务器故障。但是您也可以通过使用Github上的脚本来解决这个问题

将脚本复制到容器中,并在
docker compose.yml中使用:

client:
    image: client-server:latest
    environment:
      JAVA_OPTS: -DEUREKA_SERVER=http://eureka:8761/eureka
    depends_on:
      - config
    ports:
      - 9000:9000
    command: wait-for $CONFIGSERVER_SERVICE_NAME:$CONFIGSERVER_PORT -- java $JVM_OPTIONS -jar client.war $SPRING_OPTIONS
CONFIGSERVER\u SERVICE\u NAME
CONFIGSERVER\u PORT
的环境变量可以在中定义

如果需要等待多个服务,可以在命令行参数中合并并列出所有需要的服务,例如:

command: wait-for $SERVICE1_NAME $SERVICE1_PORT $SERVICE2_NAME $SERVICE2_PORT -- java $JVM_OPTIONS -jar client.war $SPRING_OPTIONS

使用docker compose时,服务依赖性总是很棘手的

您的解决方案是可以接受的,因为“没有其他办法”。 为了避免使用第三方LIB,我在相同的场景中会这样做:

在Dockerfile中,我添加了
netcat openbsd
,调用了一个bash文件
entrypoint
和应用程序jar,然后运行entrypoint.sh

FROM openjdk:8-jdk-alpine
RUN apk --no-cache add netcat-openbsd
COPY entrypoint.sh /opt/bin/
COPY app.jar /opt/lib/
RUN chmod 755 /opt/esusab-bi/bin/app/entrypoint.sh
入口点文件具有以下指令:

#!/bin/sh

while ! nc -z config 8888 ; do
    echo "Waiting for upcoming Config Server"
    sleep 2
done

java -jar /opt/lib/app.jar

它将延迟应用程序启动,直到您的配置服务器启动为止,没有特定的时间间隔。

作为纯粹主义者,您的问题的答案是,这不是一个可接受的解决方案,因为如前所述,Docker出于某种原因从v3上删除了
healthcheck

Docker有意识地决定不支持等待容器处于“就绪”状态的特性。他们认为依赖于其他系统的应用程序应该具有故障恢复能力

在同一链接中,说明了原因:

等待数据库(例如)准备就绪的问题实际上只是分布式系统更大问题的一个子集。在生产环境中,数据库可能随时不可用或移动主机。您的应用程序需要能够适应这些类型的故障

要处理此问题,应用程序应在出现故障后尝试重新建立与数据库的连接。如果应用程序重试连接,它最终应该能够连接到数据库

基本上有三种选择:

  • 将v2.1与健康检查一起使用。看一个例子
  • 使用v3和类似或的工具 正如@ortomala lokni已经完美解释的那样
  • 使您的应用程序能够适应配置服务器故障,并使配置客户端能够在启动时重试连接
  • 推荐和可接受的解决方案为3)。你可以按上面提到的那样使用。在下面找到
    bootstrap.yml
    配置:

    spring:
      application:
        name: config-client
      profiles:
         active: dev
      cloud:
        config:
         discovery:
           enabled: true
           service-id: config-server
         fail-fast: true
         retry:
           initial-interval: 1500
           multiplier: 1.5
           max-attempts: 10000
           max-interval: 1000
    
    eureka:
      instance:
        hostname: config-client
      client:
        registerWithEureka: true
        fetchRegistry: true
        serviceUrl:
          defaultZone: ${EUREKA_SERVER:http://localhost:8761/eureka}
    
    顺便说一句,我在您的spring配置中发现了一个错误。它是
    快速故障
    ,而不是
    快速故障

    请记住包括以下依赖项(如果使用gradle,则包括类似项):

    
    org.springframework.retry
    在Eureka服务器的注册过程中,还要考虑弹性

    在使用microservices环境时,我们必须考虑到当配置服务、发现服务等平台服务短期内不可用时环境的弹性

    但我根本不是一个纯粹主义者,我不会删除人们正在使用的一些功能(这是一个自由的问题)。因此,另一种解决方案是:

    如果它对你有用,那就去吧


    因为我真的不明白为什么Docker从v3中禁止了奇妙的
    healthcheck
    命令。

    只是一个友好的提示:您不应该将配置绑定到Eureka,但反过来->Eureka应该是配置客户端。

    显示了什么错误?@JonathanJohx这是一个问题-有一个超时异常。在第二次运行中(docker重启后),它会在右侧找到配置服务器,因此您需要先等待配置服务器和eureka服务器,然后等待其他服务。对吗?是的,看看我上面的编辑。docker compose没有任何内置的等待功能,因此您必须自己添加它。90秒的等待似乎可以奏效,但感觉就像黑客一样。是的,我知道,我的感觉和你一样,因为人们不知道服务何时启动,但我找到了一种方法,我认为这是正确的,它包括一个文件bash,以检查服务是否启动。首先,如果服务启动,那么服务将启动。这是对一个不一定只有一个正确答案的问题的彻底回答。谢谢你抽出时间。你在我的配置中也发现了一个输入错误。标记这是正确的和赏金赢家,因为这是一个非常好的阅读为任何人在相同的情况。真的appr