4
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 3 years have passed since last update.

Spring Cloudでマイクロサービスを構成する(4):API Gateway編

Last updated at Posted at 2020-10-06

Spring Cloudシリーズの第4回です。

概要

今回は「Spring Cloud Gateway」を使ってAPI Gatewayを立てることにします。

services.png

Spring Cloundファミリーでは従来、「Zuul」が使われていましたが、Zuulはメンテナンスモードとなり、「WebFlux&Nettyベースの」「Spring Gloud Gateway」が代替プロダクトとなっています。

API GatewayはAPIの前段に建てるリバースプロキシとして働きます。
API Gatewayの役割としては、クライアントとAPIの間に入り、API側に持ち込みたくない関心事を前段でさばくことにあります。

下の図は、API Gateway向けの別プロダクト「KrakenD」のドキュメントから拝借しています。
krakend_gateway.pnt.PNG

フィルタリング、入出力の返還、APIの集約、ログや統計情報取得、認証回り(SSLを解いたり、トークンをチェックしたり付加したり)、Throtting(流量制御でいいのかな?)といったところが代表例です。

個人的には2つを重要視していて、SpirngベースのSpring Cloud Gatewayには期待しています。

  • APIの前段に構えるので、パフォーマンスが良いこと。
    • 並行してアクセス数を多くさばける必要あり。
  • カスタマイズ性に富んでいること。
    • API Gatewayに機能追加がしやすいこと。(やりたいことがシンプルにできる)

環境

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

  • docker & docker-compose
  • JDK11

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

作業ステップ

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

  1. API Gatewayのひな型作成
  2. 実装(アノテーションの付加と設定ファイルの記述)
  3. Dockerイメージ化とdocker-componentへの追加

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

Spring Initializr の出番です。

ArtifactName だけgatewayに指定し、あとは
DependenciesGatewayEureka ClientSpring Cloud LoadBalancerSpringBoot Actuatorを追加しましょう。
ActuatorはGatewayに必須ではありませんが、何かと必要になるものなので追加しておきます。

Dependencies 説明
Gateway Spring Cloud Gateway を導入するために追加
Eureka Discovery Client Eurekaからサービスのリストを取得するために追加
Spring Cloud Loadbalancer クライアントサイド・ロードバランスのライブラリを追加
Spring Boot Actuator Spring Boot の内部情報を参照するために追加

gateway.png

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

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

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

まず1つ目。
Applicationクラスにアノテーションを1つ付けます。
これでService Discoveryを参照できるようになります。

gateway/src/main/java/com/example/gateway/GatewayApplication.java
package com.example.gateway;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.discovery.EnableDiscoveryClient; // ★追加する

@SpringBootApplication
@EnableDiscoveryClient // ★追加する
public class GatewayApplication {

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

やること2つ目。設定ファイル「application.yml」を書きます。
src/main/resources/application.propertiesは不要になるので、削除してください。

gateway/src/main/resources/application.yml
server:
  port: ${PORT:5000}

spring:
  main:
    banner-mode: "off"
  application:
    name: gateway

  cloud:
    gateway:
      routes:
        - id: account
          uri: lb://ACCOUNT-API
          predicates:
            - Path=/api/**
          filters:
          - RewritePath=/api(?<segment>/?.*), $\{segment}
    loadbalancer:
      ribbon:
        enabled: false

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

eureka:
  instance:
    prefer-ip-address: false
  client:
    registerWithEureka: false
    serviceUrl:
      defaultZone: ${DISCOVERY:http://localhost:8761/eureka}

Routesの箇所がルーティングの定義です。
今回は1つだけRouteの定義をしており、以下を指定しています。

  • ServiceDiscoveryから「ACCOUNT-API」サービスのインスタンスリストを取得し、負荷分散してリクエストする。(uri)
  • リクエストされたパス「/api/xxx」 に対し、アクセス先パスを「/xxx」に書き換えてサービスへリクエストする。(predicates/filters)

また、eureka.client.serviceUrl.defaultZone には、Service Discovery(Eurekaサーバ)のURLを指定します。

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

Dockerイメージを作成してdocker-composeで操れるようにしましょう。
前回のディレクトリ構造に以下のようにgatewayディレクトリを配置します。

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

spring-msa
├── account
│   └── ・・・
├── db
│   └── init
├── docker-compose.yml   <-- ★追記する
├── gateyway            <-- ★配置する
│   └── Dockerfile   <-- ★作成する
└── sd      
    └── ・・・
discovery/Dockerfile
FROM openjdk:11-jdk-slim
ADD target/gateway-*.jar /gateway.jar
ENV CONTAINER_NAME=localhost \
    PORT=5000 \
    OPTS_ARGS=''

ENTRYPOINT ["java", "-jar", "/gateway.jar", "${OPTS_ARGS}"]
docker-compose.yml
version: '3'
・・・
services:
  db:
    ・・・
  adminer:
    ・・・
  gateway:
    image: spring-msa/gateway
    container_name: gw
    build:
      context: ./gateway
      dockerfile: Dockerfile
    environment:
      - CONTAINER_NAME=gw
      - PORT=5000
      - DISCOVERY=http://sd:3001/eureka/,http://sd2:3002/eureka/
    ports:
      - "5000:5000"
  sd:
    ・・・
  account:
    ・・・

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

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

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

(全サービスを起動)
$ docker-compose up -d
(GWの停止)
$ docker-compose stop gw
(全サービスの停止と破棄)
$ docker-compose down
(全サービスの停止とVolumeを含めた破棄)
$ docker-compose down -v

コンテナの5000ポートをホストの5000ポートにbindしているので、
http://localhost:5000/api/info でアクセスできます。

下記のように繰り返し/api/infoを呼ぶと、Service Discoveryが返すサービスインスタンスのリストを使って
呼び先のACCOUNT-APIが負荷分散されているのがわかると思います。
組み込まれているロードバランサのデフォルトのアルゴリズムがRoundRobinなため、順番にリクエスト先が振られている状態です。

$ curl localhost:5000/api/info
{"containerName":"account","port":"9001","hostAddress":"172.18.0.9","hostName":"c1f0f98a3859"}
$ curl localhost:5000/api/info
{"containerName":"account2","port":"9002","hostAddress":"172.18.0.7","hostName":"27d40318d8bc"}
$ curl localhost:5000/api/info
{"containerName":"account3","port":"9003","hostAddress":"172.18.0.8","hostName":"7c2abf523dcf"}
$ curl localhost:5000/api/info
{"containerName":"account","port":"9001","hostAddress":"172.18.0.9","hostName":"c1f0f98a3859"}
$ curl localhost:5000/api/info
{"containerName":"account2","port":"9002","hostAddress":"172.18.0.7","hostName":"27d40318d8bc"}
$ curl localhost:5000/api/info
{"containerName":"account3","port":"9003","hostAddress":"172.18.0.8","hostName":"7c2abf523dcf"}

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

$ docker-compose logs -f gw

さいごに

ここまでのソースを以下に置いています。

ここまで来てようやく土台ができつつあります。

これからやってみたいこととしては、API Gatewayに機能追加を試すことです。
ロードバランスのアルゴリズムをカスタマイズしたり、APIに負荷をかけすぎないようにアクセス流量制御を追加してみたいところです。

と、なると、
その前にもう少し準備をしておく必要があります。

  • どこのAPIサービスにリクエストが行って1リクエストの中でどこにどれだけ時間がかかっているのか。
  • リクエスト数はそれぞれのサービスでどれだけさばけているのか。
  • そもそも負荷をかけたときにサービスはどのくらい余裕があるのか。

などなど、アクセスのトレースや、コンテナ/サービスのモニタリングをができる状態で負荷テストツールで負荷をかけられるようにしておきたいところです。

次回からはその辺を進めていきたいと思います。

ではでは。

4
4
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
4
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?