web-dev-qa-db-ja.com

クライアントが再起動されるまで、Spring Configサーバーはdocker-composeで到達できません

Eureka、Config Server、およびクライアントで「ディスカバリーファースト」の設定をしています。

問題は、これらの3つのサービスが順番に開始することですが、クライアントサーバーは登録が早すぎるようで、構成サーバーを見つけることができません。 config-server:8888が利用可能になるまで待機できるサードパーティのライブラリを試しましたが、それでも常に機能するとは限りません。競合状態に似ています。

回避策は、すべてが起動した後でクライアントサーバーをdocker restartした場合、登録され、config-serverが正常に検出されることです。

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

これは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}

これがconfig-server 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秒かかることが示されています)、それは一貫して機能しているようです。

これは許容できる解決策ですか?少しハックのように感じます。

8
thedude19

あなたの質問に対する純粋な答えは[〜#〜] no [〜#〜]です、それは受け入れられる解決策ではありません。 ここ 、Dockerは何らかの理由でv3からhealthcheckを削除しました:

Dockerは、コンテナーが「準備完了」状態になるのを待つ機能をサポートしないことを意識的に決定しました。彼らは、他のシステムに依存するアプリケーションは、障害に対して回復力があるべきだと主張しています。

同じリンクで、理由が説明されています:

(たとえば)データベースの準備が整うのを待つという問題は、分散システムのはるかに大きな問題のほんの一部にすぎません。本番環境では、データベースがいつでも使用できなくなったり、ホストを移動したりする可能性があります。アプリケーションは、これらのタイプの障害に対して回復力を持つ必要があります。

これを処理するには、アプリケーションは、障害発生後にデータベースへの接続を再確立する必要があります。アプリケーションが接続を再試行すると、最終的にはデータベースに接続できるはずです。

基本的に、3つのオプションがあります。

  1. healhcheckでv2.1を使用します。例を見る ここ
  2. @ ortomala-lokniはすでに完全に説明されているため、v3と wait-for-it または dockerize のようなツールを使用します。
  3. アプリケーションをconfig-serverの障害から回復できるようにし、config-clientが起動時に接続を再試行できるようにします

推奨される許容可能なソリューションは3)です。 Spring Retry は、 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}

ところで私はあなたの春の構成にエラーを見つけました。 fail-fastではなくfast-failです。

次の依存関係を含めることを忘れないでください(gradleを使用している場合は同様)。

<dependency>
    <groupId>org.springframework.retry</groupId>
    <artifactId>spring-retry</artifactId>
</dependency>

Eurekaサーバーでの登録プロセス中の復元力も考慮に入れて、非常に適切な構成(および説明) ここ を見つけることができます。

マイクロサービス環境を使用する場合、config-service、discovery-serviceなどのプラットフォームサービスが短期間利用できない場合の環境の復元力を考慮する必要があります。

しかし、私はまったく純粋主義者ではなく、人々が使用している一部の機能を削除しなかったでしょう(それは自由の問題です)。したがって、代替ソリューションは次のとおりです。

それがあなたのために働いているなら、次に進んでください

Dockerがv3からの素晴らしいhealthcheckコマンドを抑制した理由がよくわからないからです。

3
Carlos Cavero

最良の解決策は、おそらく Carlos Caveroが言ったように で、アプリケーションを構成サーバーの障害から回復できるようにすることです。ただし、Githubで Eficodewait-for スクリプトを使用して問題を解決することもできます。

スクリプトをコンテナーにコピーし、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環境ファイル で定義できます。

複数のサービスを待つ必要がある場合は、 このプルリクエスト をマージし、必要なすべてのサービスを次のようなコマンドラインパラメータにリストできます。

command: wait-for $SERVICE1_NAME $SERVICE1_PORT $SERVICE2_NAME $SERVICE2_PORT -- Java $JVM_OPTIONS -jar client.war $SPRING_OPTIONS
3
Ortomala Lokni

Docker-composeを使用する場合、サービスの依存関係は常にトリッキーです。

「他に方法はない」ので、あなたの解決策は受け入れられます。サードパーティのライブラリを回避するために、これは同じシナリオで私が行うことです。

Dockerfileにnetcat-openbsdentrypointというbashファイル、およびアプリケーション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

特定の間隔なしで、設定サーバーが起動するまでアプリケーションの起動を遅らせます。

2
Mateus