Spring 配置服务器无法通过 docker-compose 访问,直到客户端重新启动
Spring Config server not reachable with docker-compose until client is restarted
我有 'discovery first' Eureka、Config Server 和我的客户端设置。
问题是这3个服务是按顺序启动的,但是client-server好像注册的太早了,一直找不到config-server。我尝试了一个第三方库,它允许等待 config-server:8888 可用,但这似乎也不总是有效。它类似于竞争条件。
解决方法是,如果我 docker restart
客户端服务器在一切正常后,它会注册并找到配置服务器。
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
当我docker restart
客户:
Fetching config from server at : http://a80b001d04a7:8888/
Located environment: name=client-server, profiles=[default], label=null, version=053c8e1b14dc0281d5af0349c9b2cf012c1a346f, state=null
不确定我的 JAVA_OPTS 属性是否没有根据我的 docker-compose.yml 设置得足够快,或者存在一些网络竞争条件,或者什么。我在这个问题上来回折腾了太久了。
我的配置如下:
这是我的 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
这是尤里卡服务器 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
这是客户端-服务器 bootstrap.yml:
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 等待库 (https://github.com/ufoscout/docker-compose-wait),我可以让客户端-服务器等待 eureka 和配置可用,然后等待 90 秒(Eureka 文档建议注册最多可能需要 90 秒),而且它似乎始终如一地工作。
这是可以接受的解决方案吗?感觉有点乱。
最好的解决方案可能是 , to make your application resilient to config-server failure. But you can also solve the problem by using the wait-for
script from Eficode 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_SERVICE_NAME
和 CONFIGSERVER_PORT
的环境变量可以在您的 Docker Compose environment file 中定义。
如果需要等待多个服务,可以合并this pull request,在命令行参数中列出所有需要的服务如:
command: wait-for $SERVICE1_NAME $SERVICE1_PORT $SERVICE2_NAME $SERVICE2_PORT -- java $JVM_OPTIONS -jar client.war $SPRING_OPTIONS
使用 docker-compose 时,服务依赖总是很棘手。
您的解决方案可以接受,因为 "there is no other way"。
为了避免第三方库,这就是我在同一场景中所做的:
我在 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
它会延迟应用程序启动,直到您的配置服务器启动,没有特定的时间间隔。
作为纯粹主义者,您问题的答案是否,这不是一个可以接受的解决方案,因为正如here所述,Docker已删除healthcheck
由于某种原因从 v3 开始:
Docker have made a conscious decision not to support features that wait for containers to be in a "ready" state. They argue that applications depending on other systems should be resilient to failure.
在同一个link中,说明了原因:
The problem of waiting for a database (for example) to be ready is really just a subset of a much larger problem of distributed systems. In production, your database could become unavailable or move hosts at any time. Your application needs to be resilient to these types of failures.
To handle this, your application should attempt to re-establish a connection to the database after a failure. If the application retries the connection, it should eventually be able to connect to the database.
那么基本上就三种选择:
- 将 v2.1 与
healhcheck
一起使用。看一个例子 here
- 使用 v3 和类似 wait-for-it 的工具或
dockerize 正如@ortomala-lokni 已经完美解释的那样
- 使您的应用程序能够适应配置服务器故障并能够配置客户端在启动时重试连接
推荐且可接受的解决方案是 3)。您可以使用 Spring Retry as it is mentioned here。在下面找到 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 配置中发现了一个错误。它是 fail-fast
而不是 fast-fail
.
请记住包含以下依赖项(如果您使用的是 gradle,则包含类似项):
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency>
你可以找到一个非常好的配置(和解释)here 还考虑了在 Eureka Server 中注册过程中的弹性。
When having a microservices environment we must think of the resiliency of our environment when platform services like config-service, discovery-service are not available for a short period of time.
但我根本不是纯粹主义者,我不会删除人们正在使用的某些功能(这是自由的问题)。因此,另一种解决方案是:
If it is working for you, then go ahead
因为我真的不明白为什么 Docker 抑制了来自 v3.healthcheck
的神奇命令。
友情提示:您不应该将 Config 绑定到 Eureka,反之亦然 -> Eureka 应该是 Config 客户端。
我有 'discovery first' Eureka、Config Server 和我的客户端设置。
问题是这3个服务是按顺序启动的,但是client-server好像注册的太早了,一直找不到config-server。我尝试了一个第三方库,它允许等待 config-server:8888 可用,但这似乎也不总是有效。它类似于竞争条件。
解决方法是,如果我 docker restart
客户端服务器在一切正常后,它会注册并找到配置服务器。
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
当我docker restart
客户:
Fetching config from server at : http://a80b001d04a7:8888/
Located environment: name=client-server, profiles=[default], label=null, version=053c8e1b14dc0281d5af0349c9b2cf012c1a346f, state=null
不确定我的 JAVA_OPTS 属性是否没有根据我的 docker-compose.yml 设置得足够快,或者存在一些网络竞争条件,或者什么。我在这个问题上来回折腾了太久了。
我的配置如下:
这是我的 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
这是尤里卡服务器 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
这是客户端-服务器 bootstrap.yml:
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 等待库 (https://github.com/ufoscout/docker-compose-wait),我可以让客户端-服务器等待 eureka 和配置可用,然后等待 90 秒(Eureka 文档建议注册最多可能需要 90 秒),而且它似乎始终如一地工作。
这是可以接受的解决方案吗?感觉有点乱。
最好的解决方案可能是 wait-for
script from Eficode 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_SERVICE_NAME
和 CONFIGSERVER_PORT
的环境变量可以在您的 Docker Compose environment file 中定义。
如果需要等待多个服务,可以合并this pull request,在命令行参数中列出所有需要的服务如:
command: wait-for $SERVICE1_NAME $SERVICE1_PORT $SERVICE2_NAME $SERVICE2_PORT -- java $JVM_OPTIONS -jar client.war $SPRING_OPTIONS
使用 docker-compose 时,服务依赖总是很棘手。
您的解决方案可以接受,因为 "there is no other way"。 为了避免第三方库,这就是我在同一场景中所做的:
我在 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
它会延迟应用程序启动,直到您的配置服务器启动,没有特定的时间间隔。
作为纯粹主义者,您问题的答案是否,这不是一个可以接受的解决方案,因为正如here所述,Docker已删除healthcheck
由于某种原因从 v3 开始:
Docker have made a conscious decision not to support features that wait for containers to be in a "ready" state. They argue that applications depending on other systems should be resilient to failure.
在同一个link中,说明了原因:
The problem of waiting for a database (for example) to be ready is really just a subset of a much larger problem of distributed systems. In production, your database could become unavailable or move hosts at any time. Your application needs to be resilient to these types of failures.
To handle this, your application should attempt to re-establish a connection to the database after a failure. If the application retries the connection, it should eventually be able to connect to the database.
那么基本上就三种选择:
- 将 v2.1 与
healhcheck
一起使用。看一个例子 here - 使用 v3 和类似 wait-for-it 的工具或 dockerize 正如@ortomala-lokni 已经完美解释的那样
- 使您的应用程序能够适应配置服务器故障并能够配置客户端在启动时重试连接
推荐且可接受的解决方案是 3)。您可以使用 Spring Retry as it is mentioned here。在下面找到 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 配置中发现了一个错误。它是 fail-fast
而不是 fast-fail
.
请记住包含以下依赖项(如果您使用的是 gradle,则包含类似项):
<dependency>
<groupId>org.springframework.retry</groupId>
<artifactId>spring-retry</artifactId>
</dependency>
你可以找到一个非常好的配置(和解释)here 还考虑了在 Eureka Server 中注册过程中的弹性。
When having a microservices environment we must think of the resiliency of our environment when platform services like config-service, discovery-service are not available for a short period of time.
但我根本不是纯粹主义者,我不会删除人们正在使用的某些功能(这是自由的问题)。因此,另一种解决方案是:
If it is working for you, then go ahead
因为我真的不明白为什么 Docker 抑制了来自 v3.healthcheck
的神奇命令。
友情提示:您不应该将 Config 绑定到 Eureka,反之亦然 -> Eureka 应该是 Config 客户端。