Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Spring I/O 2018 報告会 - Spring Cloud Gateway / Spring Cloud Pipelines

1,180 views

Published on

2018/07/30 JSUG Spring I/O 2018 報告会での資料。
時間の関係で非表示にしていたスライドも表示にしています。

Published in: Software
  • Be the first to comment

Spring I/O 2018 報告会 - Spring Cloud Gateway / Spring Cloud Pipelines

  1. 1. Copyright©2018 NTT corp. All Rights Reserved. Spring I/O 2018 報告会 Spring Cloud Gateway / Spring Cloud Pipelines 2018年7月30日 NTT ソフトウェアイノベーションセンタ 堅田 淳也
  2. 2. 2Copyright©2018 NTT corp. All Rights Reserved. • 名前: 堅田 淳也 • 所属: NTTソフトウェアイノベーションセンタ • NTTの研究所のうちソフトウェアを専門に扱う • 自部署ではソフトウェア工学を研究 • Springベースのグループ共通フレームワークの整備を担当 • Spring I/Oは初参加 自己紹介
  3. 3. 3Copyright©2018 NTT corp. All Rights Reserved. • Spring Cloud Gatewayの紹介 • 聴講セッション: Introducing Spring Cloud Gateway • Spring Cloud Pipelinesの紹介 • 聴講セッション: Continuous Deployment of Your Application 話すこと
  4. 4. 4Copyright©2018 NTT corp. All Rights Reserved. Spring Cloud Gateway
  5. 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. 6. 6Copyright©2018 NTT corp. All Rights Reserved. • クライアントとサービスの間に位置し、APIのリバース プロキシとして振る舞う • マイクロサービスにおける横断的関心事を処理 • 認証・認可 • データ変換 • アクセス分析 • ルーティング • 課金 • 流量制御 • etc… APIゲートウェイ API Gateway Service A Service B Service C クライアント
  7. 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. 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. 9. 9Copyright©2018 NTT corp. All Rights Reserved. Stage 1: Hello/Fortune monolith index.html Fortuneサービスの結果 Helloサービスの結果 ボタンを押すと、2つのAPIに JavaScriptでアクセスし、結果を画面 に表示
  10. 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で実装
  11. 11. 11Copyright©2018 NTT corp. All Rights Reserved. Stage 2: Stand up gateway, point at old monolith
  12. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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. 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 まとめ
  30. 30. 30Copyright©2018 NTT corp. All Rights Reserved. Spring Cloud Pipelines
  31. 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. 32. 32Copyright©2018 NTT corp. All Rights Reserved. • 継続的デリバリー/デプロイにおける自動化の仕組み • リリースプロセスを複数のステージに分割 • 前半のステージで問題をあぶりだすことで、すばやく対 処が可能になる • ツール • Concourse • Jenkins デプロイメントパイプライン
  33. 33. 33Copyright©2018 NTT corp. All Rights Reserved. • 問題 • パイプラインを1から作るのは大変 • 開発プロジェクトごとにパイプラインを作るのは非効率 デプロイメントパイプライン
  34. 34. 34Copyright©2018 NTT corp. All Rights Reserved. デプロイメントパイプライン
  35. 35. 35Copyright©2018 NTT corp. All Rights Reserved. • デプロイメントパイプラインのベストプラクティスを 提供 • いい感じのパイプラインの雛形を自動的に作ってくれる • パイプラインの形が標準化されることで把握しやすくなる • 対応しているCIツール • Concourse • Jenkins • 最新バージョン (2018/7/21現在) • 1.0.0.M8 (2018/6/13リリース) Spring Cloud Pipelines
  36. 36. 36Copyright©2018 NTT corp. All Rights Reserved. • ライブラリではない • 中身はほぼBashスクリプト Spring Cloud Pipelines
  37. 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が起動 する
  38. 38. 38Copyright©2018 NTT corp. All Rights Reserved. • JenkinsにはSeed Jobが登録されている • Seed Job: パイプラインを生成するジョブ デモの実行 (Jenkinsの場合)
  39. 39. 39Copyright©2018 NTT corp. All Rights Reserved. • Seed Jobを実行するとパイプラインが生成される デモの実行 (Jenkinsの場合)
  40. 40. 40Copyright©2018 NTT corp. All Rights Reserved. 作成されるパイプライン • 4つの環境ごとにジョブが作られる • Build • Test • Stage • Production (Prod) Jenkinsの場合
  41. 41. 41Copyright©2018 NTT corp. All Rights Reserved. Build Build and Upload • アプリケーションのビルド • 単体テストの実行 • ビルド後のjarファイルをMavenリポジトリマネージャへ アップロード(e.g. Artifactory, Nexus) API compatibility check • APIの互換性をテスト
  42. 42. 42Copyright©2018 NTT corp. All Rights Reserved. • APIの互換性は壊れやすい • テスト環境にAPをデプロイしてからAPIの非互換問題 が発覚するのでは遅い • ビルド時にAPIの互換性までチェック • チェックには Spring Cloud Contract を利用 • 他サービス(サーバ)とのAPI連携に問題があっても早いタイミ ングで検知可能 Build – API互換性チェック
  43. 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. 44. 44Copyright©2018 NTT corp. All Rights Reserved. • アプリケーションのデプロイ方法が標準化されていない と、デプロイ方法が自動化しにくい • Spring Cloud PipelinesではPaaSの利用を前提とす る • アプリケーションのデプロイ方法を標準化 • Spring Cloud Pipelinesでは下記のPaaSが利用可能 • Cloud Foundry • Kubernetes Test – テスト環境へのデプロイ
  45. 45. 45Copyright©2018 NTT corp. All Rights Reserved. • アプリケーションをデプロイしたときに、必要に応じて DBスキーマがアップデートされる • Flyway, Liquibase • データベースのロールバックは困難 • 削除されたカラムのロールバック • スキーマバージョニングツールによってはロールバックをサポ ートしていない • アプリケーションだけロールバックする • データベースのロールバックはしない • DBスキーマの変更は後方互換性のあるものだけにする • カラムの追加など • アプリケーションの新旧2つのバージョンが同時に動く状態を 保つ Test – アプリケーションのロールバック
  46. 46. 46Copyright©2018 NTT corp. All Rights Reserved. Stage Deploy to stage • ステージング環境へデプロイ End to end tests on stage • E2Eテストの実施 Stage環境のジョブは全て手動でキックする必要がある
  47. 47. 47Copyright©2018 NTT corp. All Rights Reserved. • E2Eテスト • 遅い • もろい • 環境の用意が大変 • 商用データのマスクが必要だったりする • E2Eテストをやめる? • 議論の余地はあり • 時間をかけてテストしても、本番環境で結局バグがでる • 以下が可能ならE2Eテストをやめてもいいのではないか・・・ • エラーの存在を受け入れる • KPIの監視やメトリクスによる警告の仕組みを導入 • アプリケーションのロールバックが可能であることを保証する • Spring Cloud Pipelines ではとりあえずE2Eテストの実 施ジョブは残っている Stage – E2Eテスト
  48. 48. 48Copyright©2018 NTT corp. All Rights Reserved. Prod Deploy to Prod • 新しいAPを本番環境へデプロイ Complete switch over • 新しいAPへ切り替え Rollback • 古いAPへロールバック Prod環境のジョブは全て手動でキックする必要がある
  49. 49. 49Copyright©2018 NTT corp. All Rights Reserved. • 本番環境へのデプロイ • 他の環境へのデプロイと同様に扱いたい • A/Bテストや無停止デプロイをしたい • 何かが起きたときに簡単にロールバックしたい • PaaS (CF or K8S) + Spring Cloud Pipelines • PaaSでデプロイ方法を標準化 • PaaSが無停止デプロイをサポートしてくれる • アプリケーションのロールバックはテスト環境でテスト済み Prod – 本番環境へのデプロイ
  50. 50. 50Copyright©2018 NTT corp. All Rights Reserved. • パイプラインの雛形を提供 (Concourse or Jenkins) • 4つの環境に対してジョブを作成 • Build • ビルド & 単体テスト • API互換性テストも実施 (Spring Cloud Contract) • Test • テスト環境へのデプロイ • スモークテスト • アプリケーションのロールバックもテスト • Stage • ステージング環境へのデプロイ • E2Eテスト • Prod • 本番環境へのデプロイ • 必要に応じてアプリケーションのロールバックが可能 • PaaSを利用することでA/Bテスト、無停止デプロイが容易 に可能 まとめ

×