More Related Content
Similar to Spring I/O 2018 報告会 - Spring Cloud Gateway / Spring Cloud Pipelines (20)
Spring I/O 2018 報告会 - Spring Cloud Gateway / Spring Cloud Pipelines
- 1. Copyright©2018 NTT corp. All Rights Reserved.
Spring I/O 2018 報告会
Spring Cloud Gateway / Spring Cloud Pipelines
2018年7月30日
NTT ソフトウェアイノベーションセンタ
堅田 淳也
- 2. 2Copyright©2018 NTT corp. All Rights Reserved.
• 名前: 堅田 淳也
• 所属: NTTソフトウェアイノベーションセンタ
• NTTの研究所のうちソフトウェアを専門に扱う
• 自部署ではソフトウェア工学を研究
• Springベースのグループ共通フレームワークの整備を担当
• Spring I/Oは初参加
自己紹介
- 3. 3Copyright©2018 NTT corp. All Rights Reserved.
• Spring Cloud Gatewayの紹介
• 聴講セッション: Introducing Spring Cloud Gateway
• Spring Cloud Pipelinesの紹介
• 聴講セッション: Continuous Deployment of Your Application
話すこと
- 5. 5Copyright©2018 NTT corp. All Rights Reserved.
• タイトル
• Introducing Spring Cloud Gateway
• 発表者
• Spencer Gibb (Pivotal)
• 概要
• デモによる Spring Cloud Gateway の紹介
• 全編デモのため、スライドはなし
• デモシナリオ: モノリシックなアプリをマイクロサービスへ移行
• リンク
• デモアプリ
• https://github.com/spencergibb/monolith-to-microservices
• YouTube
• https://www.youtube.com/watch?v=NkgooKSeF8w
セッション概要
- 6. 6Copyright©2018 NTT corp. All Rights Reserved.
• クライアントとサービスの間に位置し、APIのリバース
プロキシとして振る舞う
• マイクロサービスにおける横断的関心事を処理
• 認証・認可
• データ変換
• アクセス分析
• ルーティング
• 課金
• 流量制御
• etc…
APIゲートウェイ
API
Gateway
Service A
Service B
Service C
クライアント
- 7. 7Copyright©2018 NTT corp. All Rights Reserved.
• Spring BootベースのAPIゲートウェイ
• Spring Framework 5 / Spring Boot 2.0 上で動作
• シンプルだが十分なAPIルーティング機能を提供
• リアクティブ対応
• 従来の Zuul 1 (+ Spring Cloud Netflix)との大きな違い
• Zuul 2 はノンブロッキングで動作するようになったが、
Spring Cloud でサポートする予定はなし
• Nettyランタイムが必須
• 最新バージョン (2018/7/21現在)
• 2.0.0.RELEASE (2018/6/19リリース)
Spring Cloud Gateway
- 8. 8Copyright©2018 NTT corp. All Rights Reserved.
Stage 1:
Hello/Fortune monolith
• モノリシックなAPを段階的にマイクロサービス化していく
• APは3つの機能を提供
1. Helloサービス (API)
2. Fortuneサービス (API)
3. UI (index.html)
Monolith
/service/hello
/service/randomfortune
Helloサービス
• URL: /service/hello
• パラメータで渡された名前に、”Hello”
を付加した文字列を返すAPI
Fortuneサービス
• URL: /service/randomfortune
• Fortune(格言)をランダムで返すAPI
- 9. 9Copyright©2018 NTT corp. All Rights Reserved.
Stage 1:
Hello/Fortune monolith
index.html
Fortuneサービスの結果
Helloサービスの結果
ボタンを押すと、2つのAPIに
JavaScriptでアクセスし、結果を画面
に表示
- 10. 10Copyright©2018 NTT corp. All Rights Reserved.
Stage 2:
Stand up gateway, point at old monolith
• APIゲートウェイを追加
• まずは全てのリクエストをMonolithに転送
Monolith
<<API Gateway>>
Gateway
• Spring Initializr からプロジェクトを作成
• ルーティング設定をJava Configで実装
- 12. 12Copyright©2018 NTT corp. All Rights Reserved.
Stage 2:
Stand up gateway, point at old monolith
@SpringBootApplication
public class GatewayApplication {
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route(p -> p.path("/**")
.uri("http://localhost:8081"))
.build();
}
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
}
<<API Gateway>>
Gateway
• RouteLocatorBuilderのroutes()メソッドを使ってルーティン
グを設定
• ここでは全てのアクセス(/**)を
Monolith(http://localhost:8081)へルーティング
RouteLocatorインスタンスをBean登録
- 13. 13Copyright©2018 NTT corp. All Rights Reserved.
Stage 3:
Move UI to separate app (path rewrite)
• UIサービスを分離
• 静的リソースへのアクセスはUIサービスへ転送
Monolith
<<API Gateway>>
Gateway
UI
• UIサービスをMonolithから分離
• UI (HTML, CSS, JavaScript)
へのアクセスはUIサービスへ
• それ以外(API)はMonolithへ
- 14. 14Copyright©2018 NTT corp. All Rights Reserved.
Stage 3:
Move UI to separate app (path rewrite)
@SpringBootApplication
public class GatewayApplication {
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route("index", p -> p.path("/")
.filters(f -> f.setPath("/index.html"))
.uri("http://localhost:8082"))
.route("ui", p -> p.path("/").or().path("/css/**").or().path("/js/**")
.uri("http://localhost:8082"))
.route("monolith", p -> p.path("/**")
.uri("http://localhost:8081"))
.build();
}
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
}
route単位で以下を設定していく
• routeのID
• Predicate (routeにマッチする条件)
• フィルタ
• ルーティング先URI
<<API Gateway>>
Gateway
問題点
ルーティング先URIがハードコーディングなのでスケールできない
- 15. 15Copyright©2018 NTT corp. All Rights Reserved.
Stage 4:
Add service discovery
• サービスディスカバリを導入してUIサービスへのロードバランシングを行う
Monolith
<<API Gateway>>
Gateway
UI
UI
<<Service Discovery>>
Eureka Server
Eurekaサーバを追加
UIサーバへのルーティング
をEureka経由に変更
UIサーバを多重化
- 16. 16Copyright©2018 NTT corp. All Rights Reserved.
Stage 4:
Add service discovery
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
• Gateway / UIサービスにEurekaクライアントの依存関係を追加
• Gatewayのapplication.ymlでサービスディスカバリを有効化
<<API Gateway>>
Gateway UI
pom.xml
spring:
application.name: gateway
cloud:
gateway:
discovery:
locator:
enabled: true
application.yml
<<API Gateway>>
Gateway
- 17. 17Copyright©2018 NTT corp. All Rights Reserved.
Stage 4:
Add service discovery
@SpringBootApplication
public class GatewayApplication {
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route("index", p -> p.path("/")
.filters(f -> f.setPath("/index.html"))
.uri("lb://ui"))
.route("ui", p -> p.path("/").or().path("/css/**").or().path("/js/**")
.uri("lb://ui"))
.route("monolith", p -> p.path("/**")
.uri("http://localhost:8081"))
.build();
}
public static void main(String[] args) {
SpringApplication.run(GatewayApplication.class, args);
}
}
<<API Gateway>>
Gateway
ルーティング先URIを
“lb://サービスID” に変更
- 18. 18Copyright©2018 NTT corp. All Rights Reserved.
Stage 5:
Move hello service
• MonolithからHelloサービスを切り出す
• HelloサービスのAPIを変更する
Monolith
<<API Gateway>>
Gateway
UI
UI
<<Service Discovery>>
Eureka Server
Hello
Hello
Service
• HelloサービスをMonolithから分離
• Helloサービスのパラメータの受け取り方を変更
• 旧: /hello?name={name}
• 新: /hello/{name}
- 19. 19Copyright©2018 NTT corp. All Rights Reserved.
Stage 5:
Move hello service
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route("hello_rewrite", p -> p.path("/service/hello/**")
.filters(f -> f.filter((exchange, chain) -> {
String name = exchange.getRequest().getQueryParams().getFirst("name");
String path = "/hello/" + name;
ServerHttpRequest request = exchange.getRequest().mutate()
.path(path)
.build();
return chain.filter(exchange.mutate().request(request).build());
}))
.uri("lb://hello"))
…(以下略)…
<<API Gateway>>
Gateway
• リクエストからnameのクエリパラメータを取得
• 新しいURLの組み立て: “/hello/{name}”
• 後続のフィルタに新しいURLのリクエストを渡す
- 20. 20Copyright©2018 NTT corp. All Rights Reserved.
<<API Gateway>>
Gateway
Stage 6:
Add circuit breaker to old fortune service with fallback
• Monolith(Fortuneサービス)の呼び出しにサーキットブレーカーを適用する
Monolith
UI
UI
<<Service Discovery>>
Eureka Server
Hello
Hello
Service
• Monolithが落ちたときにデフォル
トのFortuneを返す形でフォール
バックする
- 21. 21Copyright©2018 NTT corp. All Rights Reserved.
Stage 6:
Add circuit breaker to old fortune service with fallback
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-hystrix</artifactId>
</dependency>
• GatewayにHystrixの依存性を追加
<<API Gateway>>
Gateway
pom.xml
- 22. 22Copyright©2018 NTT corp. All Rights Reserved.
Stage 6:
Add circuit breaker to old fortune service with fallback
@RestController
@SpringBootApplication
public class GatewayApplication {
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route("fortune", p -> p.path("/service/randomfortune")
.filters(f -> f.hystrix(c -> c.setFallbackUri("forward:/defaultfortune")))
.uri("http://localhost:8081"))
…(中略)…
.build();
}
@RequestMapping("/defaultfortune")
public String defaultFortune() {
return "When you feel sad: start dot spring dot io.";
}
<<API Gateway>>
Gateway
• フォールバック先を設定
• フォールバック先
• 固定のFortuneを返す
- 23. 23Copyright©2018 NTT corp. All Rights Reserved.
Stage 7:
Move fortune service as v2
• MonolithからFortuneサービスを切り出す
Monolith
<<API Gateway>>
Gateway
UI
UI
<<Service Discovery>>
Eureka Server
Hello
Fortune
ServiceHello
Hello
Service
• FortuneサービスをMonolithか
ら分離
- 24. 24Copyright©2018 NTT corp. All Rights Reserved.
Stage 7:
Move fortune service as v2
@RestController
@SpringBootApplication
public class GatewayApplication {
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route("fortune_rewrite", p -> p.path("/service/randomfortune")
.filters(f -> f.setPath("/fortune")
.hystrix(c -> c.setFallbackUri("forward:/defaultfortune")))
.uri("lb://fortune"))
…(以下略)…
<<API Gateway>>
Gateway
• ルーティング先をFortuneサービスへ変更
- 25. 25Copyright©2018 NTT corp. All Rights Reserved.
Stage 8:
Add rate limiting to fortune v2
• Fortuneサービスの呼び出しに流量制御を適用する
Monolith
<<API Gateway>>
Gateway
UI
UI
<<Service Discovery>>
Eureka Server
Hello
Fortune
ServiceHello
Hello
Service
• 秒間最大1アクセスに制限
- 26. 26Copyright©2018 NTT corp. All Rights Reserved.
Stage 8:
Add rate limiting to fortune v2
• GatewayにSpring Data Redisの依存関係を追加
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-redis</artifactId>
</dependency>
<<API Gateway>>
Gateway
pom.xml
- 27. 27Copyright©2018 NTT corp. All Rights Reserved.
@RestController
@SpringBootApplication
public class GatewayApplication {
@Bean
public RouteLocator customRouteLocator(RouteLocatorBuilder builder) {
return builder.routes()
.route("fortune_api", p -> p.path("/v2/fortune").and().host("api.monolith.com")
.filters(f -> f.setPath("/fortune")
.requestRateLimiter().rateLimiter(RedisRateLimiter.class,
c -> c.setBurstCapacity(1).setReplenishRate(1))
.configure(c -> c.setKeyResolver(exchange ->
Mono.just(exchange.getRequest().getHeaders().getFirst("X-Fortune-Key")))))
.uri("lb://fortune"))
…(以下略)…
Stage 8:
Add rate limiting to fortune v2
<<API Gateway>>
Gateway
• ユーザあたり秒間最大1リクエストに制限
• ユーザの識別にはHTTPヘッダ”X-Fortune-Key”を使用
(本来はAPIキーなどで識別すべき)
- 28. 28Copyright©2018 NTT corp. All Rights Reserved.
Stage 8:
Add rate limiting to fortune v2
$ curl -s -i -H 'Host:api.monolith.com' -H 'X-Fortune-Key:user' http://localhost:8080/v2/fortune
HTTP/1.1 200 OK
Content-Type: text/plain;charset=UTF-8
Content-Length: 59
"Your ability for accomplishment will follow with success."
$ curl -s -i -H 'Host:api.monolith.com' -H 'X-Fortune-Key:user' http://localhost:8080/v2/fortune
HTTP/1.1 429 Too Many Requests
content-length: 0
アクセス成功時
流量制限にひっかかった場合
- 29. 29Copyright©2018 NTT corp. All Rights Reserved.
• Spring Cloud Gateway
• route単位でルーティング情報を設定
• サービスディスカバリ(e.g. Eureka)と連携して名前解決・クライ
アントロードバランシングが可能
• lb://<サービスID>
• Hystrixと連携してサーキットブレーカーを実現可能
• Redisを利用した流量制御が可能
• デモアプリはGitHub上で公開
• https://github.com/spencergibb/monolith-to-
microservices
• 各Stageにタグがうってあり、Stageごとの差分確認も簡単
• 動かすにはEureka ServerとRedisも別途自分で起動する必要あり
• Redisはdocker起動が便利
• docker run --name gateway-redis -p 6379:6379 --rm redis
まとめ
- 31. 31Copyright©2018 NTT corp. All Rights Reserved.
• タイトル
• Continuous Deployment of Your Application
• 発表者
• Marcin Grzejszczak (Pivotal)
• 概要
• 継続的デプロイメントにおける課題とSpring Cloud Pipelinesに
よる解決法の紹介
• リンク
• スライド
• https://docs.google.com/presentation/d/10Pib-
EjegE1WdMmBpkIlpeL_XqgBSfX5I5nZ-
6flBDs/edit#slide=id.g3ad752ba38_0_82
• YouTube
• まだない
セッション概要
- 32. 32Copyright©2018 NTT corp. All Rights Reserved.
• 継続的デリバリー/デプロイにおける自動化の仕組み
• リリースプロセスを複数のステージに分割
• 前半のステージで問題をあぶりだすことで、すばやく対
処が可能になる
• ツール
• Concourse
• Jenkins
デプロイメントパイプライン
- 35. 35Copyright©2018 NTT corp. All Rights Reserved.
• デプロイメントパイプラインのベストプラクティスを
提供
• いい感じのパイプラインの雛形を自動的に作ってくれる
• パイプラインの形が標準化されることで把握しやすくなる
• 対応しているCIツール
• Concourse
• Jenkins
• 最新バージョン (2018/7/21現在)
• 1.0.0.M8 (2018/6/13リリース)
Spring Cloud Pipelines
- 37. 37Copyright©2018 NTT corp. All Rights Reserved.
• JenkinsとArtifactoryを起動
デモの実行 (Jenkinsの場合)
git clone https://github.com/spring-cloud/spring-cloud-pipelines
cd spring-cloud-pipelines/jenkins
./start.sh yourGitUsername yourGitPassword yourForkedGithubOrg
http://localhost:8080 http://localhost:8081
Dockerコンテナ上でJenkinsとArtifactoryが起動
する
- 40. 40Copyright©2018 NTT corp. All Rights Reserved.
作成されるパイプライン
• 4つの環境ごとにジョブが作られる
• Build
• Test
• Stage
• Production (Prod)
Jenkinsの場合
- 41. 41Copyright©2018 NTT corp. All Rights Reserved.
Build
Build and Upload
• アプリケーションのビルド
• 単体テストの実行
• ビルド後のjarファイルをMavenリポジトリマネージャへ
アップロード(e.g. Artifactory, Nexus)
API compatibility check
• APIの互換性をテスト
- 42. 42Copyright©2018 NTT corp. All Rights Reserved.
• APIの互換性は壊れやすい
• テスト環境にAPをデプロイしてからAPIの非互換問題
が発覚するのでは遅い
• ビルド時にAPIの互換性までチェック
• チェックには Spring Cloud Contract を利用
• 他サービス(サーバ)とのAPI連携に問題があっても早いタイミ
ングで検知可能
Build – API互換性チェック
- 43. 43Copyright©2018 NTT corp. All Rights Reserved.
Test
Deploy to test
• テスト環境へAPをデプロイ
Tests on test
• スモークテストの実施
Deploy to test latest prod version
• APをロールバック
Tests on test latest prod version
• ロールバックしたAPのスモークテス
トを実施
- 44. 44Copyright©2018 NTT corp. All Rights Reserved.
• アプリケーションのデプロイ方法が標準化されていない
と、デプロイ方法が自動化しにくい
• Spring Cloud PipelinesではPaaSの利用を前提とす
る
• アプリケーションのデプロイ方法を標準化
• Spring Cloud Pipelinesでは下記のPaaSが利用可能
• Cloud Foundry
• Kubernetes
Test – テスト環境へのデプロイ
- 45. 45Copyright©2018 NTT corp. All Rights Reserved.
• アプリケーションをデプロイしたときに、必要に応じて
DBスキーマがアップデートされる
• Flyway, Liquibase
• データベースのロールバックは困難
• 削除されたカラムのロールバック
• スキーマバージョニングツールによってはロールバックをサポ
ートしていない
• アプリケーションだけロールバックする
• データベースのロールバックはしない
• DBスキーマの変更は後方互換性のあるものだけにする
• カラムの追加など
• アプリケーションの新旧2つのバージョンが同時に動く状態を
保つ
Test – アプリケーションのロールバック
- 46. 46Copyright©2018 NTT corp. All Rights Reserved.
Stage
Deploy to stage
• ステージング環境へデプロイ
End to end tests on stage
• E2Eテストの実施
Stage環境のジョブは全て手動でキックする必要がある
- 47. 47Copyright©2018 NTT corp. All Rights Reserved.
• E2Eテスト
• 遅い
• もろい
• 環境の用意が大変
• 商用データのマスクが必要だったりする
• E2Eテストをやめる?
• 議論の余地はあり
• 時間をかけてテストしても、本番環境で結局バグがでる
• 以下が可能ならE2Eテストをやめてもいいのではないか・・・
• エラーの存在を受け入れる
• KPIの監視やメトリクスによる警告の仕組みを導入
• アプリケーションのロールバックが可能であることを保証する
• Spring Cloud Pipelines ではとりあえずE2Eテストの実
施ジョブは残っている
Stage – E2Eテスト
- 48. 48Copyright©2018 NTT corp. All Rights Reserved.
Prod
Deploy to Prod
• 新しいAPを本番環境へデプロイ
Complete switch over
• 新しいAPへ切り替え
Rollback
• 古いAPへロールバック
Prod環境のジョブは全て手動でキックする必要がある
- 49. 49Copyright©2018 NTT corp. All Rights Reserved.
• 本番環境へのデプロイ
• 他の環境へのデプロイと同様に扱いたい
• A/Bテストや無停止デプロイをしたい
• 何かが起きたときに簡単にロールバックしたい
• PaaS (CF or K8S) + Spring Cloud Pipelines
• PaaSでデプロイ方法を標準化
• PaaSが無停止デプロイをサポートしてくれる
• アプリケーションのロールバックはテスト環境でテスト済み
Prod – 本番環境へのデプロイ
- 50. 50Copyright©2018 NTT corp. All Rights Reserved.
• パイプラインの雛形を提供 (Concourse or Jenkins)
• 4つの環境に対してジョブを作成
• Build
• ビルド & 単体テスト
• API互換性テストも実施 (Spring Cloud Contract)
• Test
• テスト環境へのデプロイ
• スモークテスト
• アプリケーションのロールバックもテスト
• Stage
• ステージング環境へのデプロイ
• E2Eテスト
• Prod
• 本番環境へのデプロイ
• 必要に応じてアプリケーションのロールバックが可能
• PaaSを利用することでA/Bテスト、無停止デプロイが容易
に可能
まとめ