Spring Cloudを使ったマイクロサービスシステム構築（シングル構成）


# 概要

Gateway、EurekaといったSpring Cloudを使ってマイクロサービスを構築する。ここではシングル構成での構成で実現する。

## 前提
以下のURLから雛形を作成してマイクロサービスを作成する。

https://start.spring.io/

# シングル構築でのマイクロサービス構築

まずはシングル構成で動くことを確認する。

![スクリーンショット 2020-11-28 9.44.18.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218194/abdeb338-3ac9-b6ea-f26a-b57493a4181a.png)

サーバは１台でその上に全てのマイクロサービスを実装する。ホスト名は`localhost`にした方が汎用的だが、将来クラスタ構成とするためホスト名である`ms01`を明示的に指定して構築する。

## 作成手順

最初にEurekaのマイクロサービスを作成し起動する。他のマイクロサービスはEurekaのクライアントとして動作するので、Eurekaサーバが動作している必要がある。Eurekaのクライアントが起動する際、クライアントの情報がEurekaサーバに登録される。

## Eureka
Eurekaのコードはこんな感じ。

```java:EurekaServerApplication.java
package comm.example.eurekaserver;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.server.EnableEurekaServer; //追加

@EnableEurekaServer  //追加
@SpringBootApplication
public class EurekaServerApplication {

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

```yaml:application.yml
spring:
  cloud:
    inetutils:
      preferredNetworks:
        - 10.10.10

server:
  port: 8761
eureka:
  instance:
    hostname: ms01
  client:
    registerWithEureka: false
    fetchRegistry: false
    serviceUrl:
      defaultZone: http://ms01:8761/eureka/
```

## Service-1/Service-2の作成

続きてユーザアプリケーションとしてのマイクロサービス、Service-1/Service-2を作成する。

Service-1のソース

```java:App1ServiceApplication.java
package com.example.app1service;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;  //追加

@SpringBootApplication
@EnableEurekaClient　　　//追加
public class App1ServiceApplication {

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

}
```
```java:App1Controller.java
package com.example.app1service.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class App1Controller {

    @RequestMapping("/hello")
    public String hello() {
        return "Hello from Server-A";
    }

}
```

```yaml:application.yml
spring:
  application:
    name: app1-service  # Eurekaの管理画面で表示されるサービス名

server:
  port: 8081
  
eureka:
  client:
    serviceUrl:
      defaultZone: http://ms01:8761/eureka/

```

Service-2もほぼ同様の作り。

```java:App2ServiceApplication.java
package com.example.app2service;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;  //追加

@SpringBootApplication
@EnableEurekaClient     //追加
public class App2ServiceApplication {

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

}
```

```java:App2Controller.java
package com.example.app2service.controller;

import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

@RestController
public class App2Controller {

    @RequestMapping("/goodbye")
    public String hello() {
        return "GoodBye from EurekaClient App2";
    }
}
```

```yaml:application.yml
spring:
  application:
    name: app2-service

server:
  port: 8082
  
eureka:
  client:
    serviceUrl:
      defaultZone: http://ms01:8761/eureka/
```
## Gatewayの作成

Gatewayの作り方として、ルーティングをJavaで実装するパターンもあるようだが、ここでは`application.yml`ファイルにルーティング情報を書くやり方で実現する。

```java:GatewayApplication.java
package com.example.gateway;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;

@SpringBootApplication
@EnableEurekaClient
public class GatewayApplication {

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

}
```

```yaml:application.yml
server:
  port: 8080

eureka:
  client:
    serviceUrl:
      defaultZone: http://ms01:8761/eureka/
spring:
  application:
    name: gateway-service
  cloud:
    gateway:
      routes:
      - id: app1Module
        # uri: http://ms01:8081/ #単体で動かす場合はURL直指定でもOK。ただしクラスタに対応できない。
        uri: lb://APP1-SERVICE # application:name を指定する
        predicates:
        - Path=/hello/**       # app1で利用できるURLを指定
      - id: app2Module          # app2についてもapp1と同様の設定を行う
        uri: lb://APP2-SERVICE 
        predicates:
        - Path=/goodbye/**
```

### デプロイ・起動

起動方法は全てのマイクロサービスで同じ手順なので代表例としてEurekaの手順を示すが、他のマイクロサービスも同様に起動できる。
Eclipse等でソースコードを作成後Mavenで`eureka-server-0.0.1-SNAPSHOT.jar`というjarファイルを作成する。で作成したjarファイルをサーバに転送して起動する。

なお起動順序は最初に言っているよう、Service-1/2およびGatewayはEurekaのクライアントとなるので、サーバであるEurekaを最初に起動し、その後EurekaクライアントのService-1/2およびGatewayを起動すること。
この例ではベタで起動しているが、systemctlで起動できるようサービス化してもいい。

```shell
[root@ms01 ~]# java -jar eureka-server-0.0.1-SNAPSHOT.jar
```

全てのマイクロサービスが起動したら、Eurekaの管理コンソール（っていうの？）には各マイクロサービスがEurekaのクライアントとして登録されている。

![スクリーンショット 2020-11-28 13.57.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/218194/34e4199d-01a4-cc61-61f4-ca773cfd1dfe.png)

### 単体で動くかチェックする
Service-1およびService-2については単独でも動作する。
ブラウザから下記URLを叩いて、正常に応答が帰ってくるようならSerivce-1/2は正しく動いている。

http://ms01:8081/hello
http://ms01:8082/goodbye

### Gatewayを経由して動くかチェックする

Gatewayは8080ポートで待ち受けていて、'/hello'がService-1の`/hello`に、`goodbye`がService-2の`/goodbye`に振り分けられる。
http://ms01:8080/hello
http://ms01:8080/goodbye

ここまで動作すると、シングル構成でGatewayを経由して各マイクロサービスにルーティングできるようになる。
ユーザとしては、それぞれのマイクロサービスが異なるサーバで動作していても、サーバが複数あることを気にすることなくGatewayのURLとマイクロサービスのパスを知っているとサービスにアクセス可能となる。
ただし、この構成はシングル構成のため、例えばService-1が落ちた場合、サービスの提供ができなくなる。

それだと困る場合は、こちらの[多重構成での構築](https://qiita.com/nkoseki/items/ec0de33f14b4edd36d70)を参照して多重構成にする必要がある。