LoginSignup
3
1

More than 3 years have passed since last update.

Spring Cloudでマイクロサービスを構成する(3):Service Discovery編

Last updated at Posted at 2020-10-05

Spring Cloudシリーズの第3回です。今回はService Discoveryです。

概要

今回は、Eureka(Spring Cloud Netflix Eureka )でService Discoveryのクラスタを立てます。

services.png

Spring Cloudではここ最近で方針転換があり、Spring Cloud Netflix関連プロダクトがメンテナンスモードになり、代替のプロダクトへの移行段階にあります。

Spring Cloud Netflix Projects Entering Maintenance Mode

今回は、その中でも次の世代に生き残った Eurekaを使ってService Discoveryのクラスタをdockerで立てていきます。
(最もよく知られている Service Discovery に consul がありますが、SpringBootとConsulの連携については、後の楽しみにとっておきましょう。)

環境

以下が動く環境を前提とします。

  • docker & docker-compose
  • JDK11

前回の投稿の続きですので、前回のゴール地点のソースを手元に用意し、それをベースとします。

作業ステップ

本記事では以下のステップで進めていきます。

  1. Eurekaのひな型作成
  2. 実装(アノテーションの付加と設定ファイルの記述)
  3. Dockerイメージ化とdocker-componentへの追加
  4. APIを多重化し、Serivce Discoveryに登録する
  5. Eurekaのクラスタリング

ステップ1:Eurekaのひな型作成

Spring Initializr の出番です。

ArtifactName だけdiscoveryに指定し、あとは
DependenciesEureka ServerSpringBoot Actuatorを追加しましょう。
ActuatorはEurekaに必須ではありませんが、何かと必要になるものなので追加しておきます。

eureka.png

あとはGENERATEするとスケルトンのdiscovery.zipがダウンロードできます。
 

ステップ2:実装(アノテーションの付加と設定ファイルの記述)

今回はあまりやることがありません。2つだけ。

まず1つ目。Applicationクラスにアノテーションを1つ付けます。

discovery/src/main/java/com/example/discovery/DiscoveryApplication.java
package com.example.discovery;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer;
// ★ ↑ これを追加

@SpringBootApplication
@EnableEurekaServer              // ★ これを追加
public class DiscoveryApplication {

    public static void main(String[] args) {
        SpringApplication.run(DiscoveryApplication.class, args);
    }
}

2つ目は、設定ファイルを書きます。

discovery/src/main/resources/application.yml
server:
  port: ${PORT:8761}

eureka:
  shouldUseDns: false
  instance:
    hostname: ${CONTAINER_NAME:localhost}
    preferIpAddress: false
  client:
    registerWithEureka: false
    fetchRegistry: false
    serviceUrl:
      defaultZone: ${ZONE:http://localhost:8761/eureka}
  server:
    enableSelfPreservation: true
spring:
  main:
    banner-mode: "off"
  cloud:
    loadbalancer:
      ribbon:
        enabled: false

management:
  endpoints:
    web:
      exposure:
        include: "*"

いくつかわざとらしく後で環境変数で書き換えられるようにしていますが、基本はデフォルト値で動くようにしています。

discovery/src/main/resources/application.propertiesは不要になるので、削除してください。

さて、ここまでくればEurekaサーバを起動できます。

$ cd discovery
$ ./mvn clean spring-boot:run

http://localhost:8761 にアクセスしてみてください。Eurekaのホーム画面が出ればOKです。

ステップ3:Dockerイメージ化とdocker-componentへの追加

この段階でさっさとDockerイメージ化をしてdocker-composeで操れるようにしておきましょう。
前回のディレクトリ構造に以下のようにdiscoverディレクトリを配置します。

その上で、Dockerfileを作成し、とdocker-compose.ymlに追記します。

spring-msa
├── account
│   └── ・・・
├── db
│   └── init
├── docker-compose.yml   <-- ★追記する
└── sd                  <-- ★配置する
    ├── Dockerfile   <-- ★作成する
    ├── HELP.md
    ├── mvnw
    ├── mvnw.cmd
    ├── pom.xml
    └── src
        ├── main
        │   ├── java
        │   └── resources
        └── test
discovery/Dockerfile
FROM openjdk:11-jdk-slim
ADD target/discovery-*.jar /discovery.jar
ENV CONTAINER_NAME=localhost \
    PORT=8761 \
    OPTS_ARGS=''

ENTRYPOINT ["java", "-jar", "/discovery.jar", "${OPTS_ARGS}"]
docker-compose.yml
version: '3'
・・・
services:
  db:
    ・・・
  adminer:
    ・・・
  sd:
    image: spring-msa/eureka
    container_name: sd
    build:
      context: ./discovery
      dockerfile: Dockerfile
    environment:
      - CONTAINER_NAME=sd
      - PORT=8761
      - ZONE=http://sd:8761/eureka/
    ports:
      - "8761:8761"

  account:
    ・・・

これで準備OK.
mvn wrapperでJARを作ったあとに、Dockerイメージを作成します。

$ cd discovery
$ .mvnw clean package
$ cd ..
$ docker-compose build sd

これでdocker-composeで起動・停止できるようになりました。

(起動)
$ docker-compose up -d sd
(停止)
$ docker-compose stop sd

コンテナの8761ポートをホストの8761ポートにbindしているので、
http://localhost:8761 で先ほどのEurekaのダッシュボードが見れるはずです。

何かがおかしければdokerのログをみてください。

$ docker-compose logs -f sd

ステップ4:APIを多重化し、Serivce Discoveryに登録する

このままだとService Discoveryは立ち上がったものの、何もサービスが登録されていません。
そこで、前回作ったaccountサービスを登録してみましょう。

pom.xmlapplication.yml に手をいれます。

account/pom.xml
@@ -15,6 +15,9 @@
    <description>Demo project for Spring Boot</description>

    <properties>
+       <spring-cloud.version>Hoxton.SR7</spring-cloud.version>
+       <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
+       <project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
        <java.version>11</java.version>
    </properties>

@@ -47,6 +50,10 @@
            <artifactId>lombok</artifactId>
            <optional>true</optional>
        </dependency>
+       <dependency>
+           <groupId>org.springframework.cloud</groupId>
+           <artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
+       </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
@@ -65,6 +72,18 @@
        </dependency>
    </dependencies>
+
+   <dependencyManagement>
+       <dependencies>
+           <dependency>
+               <groupId>org.springframework.cloud</groupId>
+               <artifactId>spring-cloud-dependencies</artifactId>
+               <version>${spring-cloud.version}</version>
+               <type>pom</type>
+               <scope>import</scope>
+           </dependency>
+       </dependencies>
+   </dependencyManagement>

    <build>
        <plugins>
            <plugin>

account/src/main/resources/application.yml

spring:
  ・・・
  r2dbc:
     url: ${DB_URL:r2dbc:postgresql://localhost:5432/db}
     username: ${DB_USER:postgres}
     password: ${DB_PASSWD:postgres}
+  cloud:
+    loadbalancer:
+      ribbon:
+        enabled: false

 management:
   endpoints:
@@ -22,3 +26,16 @@ management:
   endpoint:
     health:
       show-details: always
+
+eureka:
+  client:
+    serviceUrl:
+      defaultZone: ${DISCOVERY:http://localhost:8761/eureka/}
+    should-use-dns: false
+  instance:
+    instanceId: ${CONTAINER_NAME:account}
+    hostname: ${CONTAINER_NAME:localhost}
+    preferIpAddress: false
+
docker-component.yml
services:
  ・・・
  account:
    image: spring-msa/account-api
    container_name: account
    build:
      context: ./account
      dockerfile: Dockerfile
    ports:
      - "9001:9001"
    depends_on:
      - db
    environment:
      - CONTAINER_NAME=account
      - PORT=9001
      - DB_USER=${DB_USER:-postgres}
      - DB_PASSWD=${DB_PASSWORD:-postgres}
      - DB_URL=${DB_URL:-r2dbc:postgresql://db:5432/db}
      - DISCOVERY=http://sd:8761/eureka  # ★ここを追加
    networks:
      - default

JARを作ってdocker-composeでdokcerイメージのビルドを含めて一気に起動してみましょう。
Service Discoveryも起動しておきます。

$ docker-compose up -d sd
$ cd account
$ ./mvnw clean package
$ cd ..
$ docker-compose up -d --build account

http:/localhost:8761 にアクセスしてしばらくすると、ACCOUNT-APIが1インスタンス登録されているのがわかると思います。

では、さらにACCOUNT-APIサービスのインスタンスを2つ追加しましょう。
docker-compose.ymlのaccountサービスの記載をコピーして、サービス名などの名前やポート番号を書き換えます。
同じDockerイメージを使って、3つのDockerコンテナを動かします。
ポート等はdocker-compose.ymlの環境変数で外から指定することで、重複しないようにします。

サービス名 コンテナ名 ポート番号
account account 9001
account2 account2 9002 ←これを追加
account3 account3 9003 ←これを追加
docker-component.yml
  ・・・
services:
  ・・・
  account:
  ・・・
  account2:
    image: spring-msa/account-api
    container_name: account2     # ★
    ports:
      - "9002:9002"     # ★
    depends_on:
      - db
    environment:
      - CONTAINER_NAME=account2     # ★
      - PORT=9002     # ★
      - DB_USER=${DB_USER:-postgres}
      - DB_PASSWD=${DB_PASSWORD:-postgres}
      - DB_URL=${DB_URL:-r2dbc:postgresql://db:5432/db}
      - DISCOVERY=http://sd:8761/eureka
    networks:
      - default
  account3:
    image: spring-msa/account-api
    container_name: account3     # ★
    ports:
      - "9003:9003"     # ★
    depends_on:
      - db
    environment:
      - CONTAINER_NAME=account3     # ★
      - PORT=9003     # ★
      - DB_USER=${DB_USER:-postgres}
      - DB_PASSWD=${DB_PASSWORD:-postgres}
      - DB_URL=${DB_URL:-r2dbc:postgresql://db:5432/db}
      - DISCOVERY=http://sd:8761/eureka
    networks:
      - default

追加したacocunt2、account3のサービスを起動します。

$ docker-compose up -d account2 account3

http://localhost:8761 にアクセスするとインスタンス数が3になっているのが確認できると思います。

ステップ5:Eurekaのクラスタリング

さて、Service Discoveryのサービスを立てることができましたが、1プロセスだと心もとないので、冗長化を試します。

これもdocker-compose.ymlの編集のみで対応可能です。

sdサービスのエントリをコピーして、ポート番号等を調整します。

サービス名 コンテナ名 ポート番号
sd sd 3001
sd2 sd2 3002 ←これを追加
docker-compose.yml
version: '3'
・・・
services:
  db:
    ・・・
  adminer:
    ・・・
  sd:
    image: spring-msa/eureka
    container_name: sd
    build:
      context: ./discovery
      dockerfile: Dockerfile
    environment:
      - CONTAINER_NAME=sd
      - PORT=8761
      - ZONE=http://sd2:3001/eureka/  # ★自分以外のEurekaインスタンスをカンマ区切りで記載する
    ports:
      - "3001:3001"
  sd2:
    image: spring-msa/eureka
    container_name: sd2
    environment:
      - CONTAINER_NAME=sd2
      - PORT=3001
      - ZONE=http://sd:3001/eureka/  # ★自分以外のEurekaインスタンスをカンマ区切りで記載する
    ports:
      - "3002:3002"
  account:
    ・・・
    environment:
      ・・・
      - DISCOVERY=http://sd:3001/eureka,http://sd2:3002/eureka # ★すべてのEurekaインスタンスをカンマ区切りで羅列する
    ・・・
  account2:
    ・・・
    environment:
      ・・・
      - DISCOVERY=http://sd:3001/eureka,http://sd2:3002/eureka # ★すべてのEurekaインスタンスをカンマ区切りで羅列する
    ・・・
  account3:
    ・・・
    environment:
      ・・・
      - DISCOVERY=http://sd:3001/eureka,http://sd2:3002/eureka # ★すべてのEurekaインスタンスをカンマ区切りで羅列する

これでsdとsd2を起動しましょう。

localhost:3001 と localhost:3002 にアクセスすると、両方とも「DS Replicas」の欄に他方のEurekaサーバへのリンクが表示されていて、
ACOCUNT-APIアプリが、accout,account2,account3の3件登録されているのが確認できると思います。

eureka-ha.png

さいごに

わりとシンプルにService Discoveryのクラスタができました。
ここまでのソースは以下に置いています。

次回はService Discoveryを利用してAPIに分散アクセス(ロードバランシング)する
「API Gateway」を追加しましょう。

 
ではでは。

3
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
1