Spring Boot on Kubernetes : Yahoo!ズバトク事例 #jjug_ccc

2.5K Views

May 28, 18

スライド概要

JJUG CCC 2018 Springの登壇資料です。

profile-image

2023年10月からSpeaker Deckに移行しました。最新情報はこちらをご覧ください。 https://speakerdeck.com/lycorptech_jp

シェア

またはPlayer版

埋め込む »CMSなどでJSが使えない場合

(ダウンロード不可)

関連スライド

各ページのテキスト
1.

Spring Boot on Kubernetes Yahoo!ズバトク事例 2018/05/26 ヤフー株式会社 玉利 拓郎 Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved.

2.

自己紹介 玉利 拓郎 ヤフー株式会社 2009入社 Yahoo!ウォレット Yahoo!ショッピング Yahoo!ズバトク Yahoo!マネー ↑タマリン @yotama 言語 Java 1.4 -> PHP 5.3 -> Java 8 Tamari Takuro Kotlinに浮気したい Rustも気になる Photo by Jeroen Kransen - Gouden leeuwaapje(2008) / CC BY-SA 2.0 Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 2

3.

今日話すこと • Yahoo!ズバトクでSpring Bootを どうやってKubernetesに載せたか • Kubernetesに合わせた開発フロー Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 3

4.

今日話さないこと • Kubernetesサイドの話 • Kubernetes自体の運用など Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 4

5.

アジェンダ • なぜKubernetesに移行したか • Kubernetesに載せるために必要なこと • その他導入したアーキテクチャ Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 5

6.

Yahoo!ズバトクとは “毎日ワクワク!おトクが当たる&もらえる” くじやキャンペーンを掲載するためのプラットフォーム Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 6

7.

なぜ Kubernetesに 移行したか Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 7

8.

高まる需要 • 販促サービスとしての需要が高まる • キャンペーン数は日に日に増加 Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 8

9.

アクセス数の特性 • 特定の時間にアクセス数が急激に増える • • • • キャンペーンの開始 人気キャンペーンの開催 PUSH通知 etc… Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 9

10.

大型キャンペーンでは厳戒態勢で望む必要 2000 req/s Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 10

11.

増える要望 • 様々なキャンペーンに対応するため、 機能追加要望が増大 → 開発が追いつかない Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 11

12.

移行前のシステム構成 別サービス API ほぼ全ての機能が ココに載ってる etc Web × n MySQL Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 12

13.

移行前のシステム構成 別サービス 1テーブルに数億レコード API etc Web × n DBも一極集中 MySQL Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 13

14.

現行システムではそろそろ限界 • リリース時間 大 • DB負荷 大 • スケールコスト 大 • 結合試験のコスト 大 • 改修コスト 大 Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 14

15.

運用コストを下げ、開発速度を高めたい • リリース時間の削減 • システムのスケーラビリティの確保 • テスト工数の削減 • 改修コストの削減 Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 15

16.

Kubernetes Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 16

17.

Kubernetes(k8s)とは • コンテナのオーケストレーションプラット フォーム • コンテナ化されたアプリケーションの展開、 スケーリング、運用自動化を行う Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 17

18.

Kubernetesでできること • フェイルオーバー • スケーリング • スケジューリング • ロードバランス • サービスディスカバリ Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 18

19.

Kubernetesでできること • 異常があると自動的にコンテナ再起動 • 自由にコンテナ(Pod)数を変更 • リクエストの負荷分散 • サービスへのルーティング Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 19

20.

k8sでいくつかの課題を解決できそう • リリース時間 → コンテナ管理で短縮 • スケールコスト → k8sの機能で一発 • 改修コスト • マイクロサービス化で修正箇所を集約 • (k8sならばサービスを追加するコストが低い) Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 20

21.

システム移行することに • • • • IaaS → CaaS(Kubernetes) PHP → Java モノリシック → マイクロサービス Jenkins → Concourse CI Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 21

22.

アプリケーションアーキテクチャの変更 • モノリシック → マイクロサービス • スケーラビリティの向上 • DB負荷の分散 • 改修リスクの削減 Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 22

23.

マイクロサービスアーキテクチャ くじWEB 景品 履歴 くじ MQ メール DBはサービス毎に分割 Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 後処理は非同期 23

24.

DDDで機能分割 • ドメイン駆動設計の 思想を基に、 サービスを分割 Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 24

25.

ネットワーク構成 最終的には 40サービスほどに Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 25

26.

k8sに載せるために 必要なこと Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 26

27.

k8sへ載せるのに必要なもの • k8sの基礎知識 • コンテナ • Dockerイメージの作成 • アプリケーション • クラウドネイティブ化 • Liveness probe / Readiness probe • Graceful Shutdown • k8s • manifestファイル Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 27

28.

k8sを活かすのに必要なもの • 開発フロー • CI/CD • 自動テスト Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 28

29.

k8sの基礎知識 Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 29

30.

Kubernetesの特徴 • コンテナ中心のインフラ • 宣言的設定 Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 30

31.

宣言的設定 • 「望ましい状態」を記述した設定ファイル (manifest)で定義 Copyright © 2017 apiVersion: extensions/v1beta1 kind: Deployment metadata: labels: app: campaign name: campaign spec: selector: matchLabels: app: campaign template: metadata: labels: app: campaign spec: containers: - image: docker-registry.xxxx.yahoo.co.jp:xxxx/zubatoku/zubatoku-campaign:latest name: campaign Yahoo JapanimagePullPolicy: Corporation. All Rights Reserved. Always YAMLで設定を書く 31

32.

Kubernetesのリソース構成イメージ transaction Ingress Service Service Deployment Deployment Pod Pod Pod Pod Pod Pod namespace 1サービスのセット それぞれのリソースをYAMLで定義する Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. cluster ※飽くまでイメージです 32

33.

Pod • デプロイの最小単位 • Dockerコンテナを内包 • 複数コンテナも可 Docker コンテナ Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. Pod 33

34.

Deployment • ローリングアップデートや ロールバックを管理する • ReplicaSetを通して、Pod を生成・管理する Deployment ReplicaSet Pod Pod Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. Pod 34

35.

Deploymentの定義 apiVersion: apps/v1 kind: Deployment metadata: name: nginx-deployment labels: app: nginx spec: replicas: 3 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: containers: - name: nginx image: nginx:1.7.9 ports: Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 35

36.

Service VIP: 10.0.0.12 app=lot-web Service Pod Pod Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. • 仮想IPとポート • ラベルセレクタによる Podのグルーピング Pod 36

37.

Ingress Ingress toku.yahoo.co.jp /entry /lot Lot Service • L7負荷分散 • バーチャルホスト • パスによる振り分け Entry Service Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 37

38.

Ingressの定義 apiVersion: extensions/v1beta1 kind: Ingress metadata: name: test-ingress spec: rules: - host: myservice.yahoo.co.jp http: paths: - path: /lot backend: serviceName: lot servicePort: 80 - path: /entry backend: serviceName: entry servicePort: 80 Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 38

39.

Ingress Ingress toku.yahoo.co.jp nginx /campaing01/lot lot Service • Ingressは前方一致でしか 振り分けられない • ズバトクではnginxで振り分 けを実施 /campaign01/entry entry Service Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 39

40.

その他の構成要素 • ConfigMap • アプリケーション用の設定値を保持 • Secret • 秘密情報を保持 • Job / CronJob • バッチ処理等のジョブ Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 40

41.

アプリケーション編 Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 41

42.

アプリケーション周りで必要なこと • コンテナ • Dockerイメージの作成 • アプリケーション • • • • クラウドネイティブ化 Liveness probe / Readiness probe Graceful Shutdown ログ出力 Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 42

43.

Dockerとは • コンテナの実行・管理ツール • イメージで管理するので、 環境の一貫性がある • 素早いアプリケーションの展開 Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 43

44.
[beta]
Dockerfile
• DockerfileでImageを定義
FROM openjdk:8

ベースのイメージ

ARG JAR_FILE
COPY ${JAR_FILE} app.jar
ENTRYPOINT ["java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "/app.jar"]

プロセス起動用のコマンド

Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved.

44

45.

Dockerイメージの作成と実行 # Dockerイメージをビルド $ docker build . -t hoge/myapp # Dockerコンテナを実行 $ docker run -d --rm -it hoge/myapp:latest Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 45

46.

Dockerfile例 FROM docker-registry.xxxx.yahoo.co.jp:xxxx/xxxx/openjdk:8 RUN groupadd -r zubatoku && useradd -r -g zubatoku zubatoku COPY ./app.jar ./app.jar COPY ./run.sh ./run.sh EXPOSE 8080 USER zubatoku ENV TZ=Asia/Tokyo ¥ JAVA_GC_OPTS="" ¥ JAVA_HEAP_OPTS="" ¥ JAVA_METASPACE_OPTS="" ¥ JAVA_EXTRA_OPTS="" ¥ JAVA_OPTS="" ズバトクでは オプション指定簡略化のため 外部スクリプト化 ENTRYPOINT ["./run.sh", "app.jar"] Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 46

47.

シェルスクリプト化する場合はexecをつける exec java ${JAVA_OPTS} -Djava.security.egd=file:/dev/./urandom -jar $1 PIDが1になるように、javaコマンドの前にexecをつける Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 47

48.

アプリケーションへの対応 • クラウドネイティブ化 • Liveness probe / Readiness probe • Graceful Shutdown Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 48

49.

クラウドネイティブなアプリ 基本はTwelve-factor app クラウドで動くアプリケー ションが従うべき12のプラク ティス Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 1. 2. 3. 4. 5. 6. 7. 8. 9. 10. 11. 12. コードベース 依存関係 設定 バックエンドサービス ビルド、リリース、実行 プロセス ポートバインディング 並行性 廃棄容易性 開発/本番一致 ログ 管理プロセス 49

50.

抜粋すると • 設定 • → 設定値は環境変数に格納 • ポートバインディング • → 組み込みサーバを使う • 廃棄容易性 • 起動の高速化、グレースフルシャットダウン • ログ • 標準出力に出力し、集約する Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 50

51.

設定の環境変数からの読み込み • Spring Bootはプロパティを環境変数から バインドできる 以下は等価 property spring.datasource.url=jdbc:mysql://localhost:3306/test 環境変数 SPRING_DATASOURCE_URL=jdbc:mysql://localhost:3306/test Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 51

52.

k8sで環境変数に注入 env: - name: SPRING_DATASOURCE_INITIALIZE value: "false" - name: APPLICATION_LOGGING_LEVEL valueFrom: configMapKeyRef: name: campaign-config key: application.logging.level optional: true - name: LOGGING_LEVEL_ROOT valueFrom: configMapKeyRef: name: campaign-config key: logging.level.root optional: true - name: SPRING_DATASOURCE_URL valueFrom: secretKeyRef: name: campaign-env Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. key: datasource-url k8s/deployment.yaml env: - name: 環境変数名 valueFrom: 値の取得元 (ConfigMap or Secret) 52

53.

ヘルスチェックエンドポイント • k8sがpodの死活チェックをするためのエ ンドポイントが2種類ある • Liveness probe • Readiness probe Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 53

54.

Liveness probe / Readiness probe Liveness probe • アプリケーションが生きてるかどうかをチェック • NGならばpodを再作成 Readiness probe • 利用可能になっているかのチェック • OKになったらサービスイン Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 54

55.

ズバトクでの実装方法 Liveness probe • Actuatorを使い、status 200を返すだけのエ ンドポイント作成 Readiness probe • Actuatorのhealthエンドポイントを流用 • DBのチェックなどもやってくれる Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 55

56.

コード例 @Endpoint(id = "liveness") public class LivenessEndpoint { @Endpoint(id = "readiness") public class ReadinessEndpoint { private final HealthEndpoint healthEndpoint; public ReadinessEndpoint(HealthEndpoint healthEndpoint) { this.healthEndpoint = healthEndpoint; } @ReadOperation public Health execute() { return Health.up().build(); } @ReadOperation public Health execute() { return this.healthEndpoint.health(); } } } Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 56

57.

Liveness probe / Readiness probe deployment.yamlに設定を記述 livenessProbe: httpGet: path: /liveness port: 9990 initialDelaySeconds: 60 timeoutSeconds: 1 periodSeconds: 5 readinessProbe: httpGet: path: /readiness port: 9990 initialDelaySeconds: 20 timeoutSeconds: 5 periodSeconds: 5 Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. application.yml management: security: enabled: false port: 9990 endpoints: health: path: readiness 外部からアクセス出来ないように actuatorのportを9990に 57

58.

LivenessとReadinessをわけたわけ • Liveness probeは軽くすべき • また、DB等の外部システムダウンした際 はPod再起動しても効果が薄い Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 58

59.

Graceful Shutdown • Podが終了する際に適切な終了処理を行う • 処理中のリクエストの対応 • リソースの破棄 →実装しなかったら、処理中にエラーが発生 Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 59

60.

Graceful Shutdownの実装 • ActuatorのShutdown Endpointを拡張し、 処理中のリクエストがなくなるまでWait lifecycle: preStop: httpGet: path: /shutdown port: 9990 deployment.yaml ※ActuatorのShutdownEndpointはGracefulではないので注意 Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 60

61.

Graceful Shutdownの実装 • 通常はアプリケーションサーバの機能を 使って実装 • Jettyではkeepalive等の扱いがうまくいか なかったので、独自でservletのFilterを使 い処理中セッションをカウントするようにし た Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 61

62.

アプリケーションログについて • ログは標準出力に出す • Podが終了したらファイルは消滅 • マイクロサービスの場合は相関IDは必須 Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 62

63.

相関ID • Spring Cloud Sleuthを使用 • 依存を追加するだけでリクエストで一意な IDをログに出力 • サービス数が多いのでこれがなければ運 用がつらくなる time:2018-03-22T13:52:22.855+09:00 time:2018-03-22T13:52:23.123+09:00 level:INFO trace_id:8f01dc2dc4a7f7b6 level:INFO trace_id:8f01dc2dc4a7f7b6 Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. span_id:8f01dc2dc4a7f7b6 span_id:8f01dc2dc4a7f7b6 63

64.

開発フロー編 Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 64

65.

k8sの仕組みを活かすためのフロー • Git上でオペレーションが完結するフロー → GitOps • Pull Requestでオペレーション • 環境毎のPull Requestは自動生成 • CI/CDは必須 Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 65

66.

開発フロー 7. マージ 5. パブリッシュ 4. テスト/ビルド GitHub Docker registry Concourse CI 6. プルリクエスト 1. clone 3. プルリクエスト Deploy ・・・ 2. 開発/テスト develop Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. e2e production 66

67.

Concourseで複雑なパイプラインを実現 パイプラインの定義はYAMLで定義しGit管理 Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 67

68.

テストの自動化 • このフローで安心してリリースするために は、テスト自動化は必須 Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 68

69.

テストの自動化 E2E テスト 機能テスト • 3種類のテストを実装 • ユニットテスト • クラス単体 • 機能テスト • サービス単体 • E2Eテスト ユニットテスト テストピラミッド Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. • 全サービス結合 69

70.

E2Eテスト • 全サービスを通してのテスト • JUnit • Selenium @Test public void 抽選_01_くじを引く() throws Exception { ログインケース .ログインする(xxxx); 抽選ケース .Action_抽選画面を開く(CAMPAIGN_PATH) .Verify_抽選_抽選画面を表示(xxxx) .Verify_抽選_キャンペーン期間表示(); } Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 70

71.

リリース時間の変化 • これまで • パッケージングからサービスアウトなどを含 むリリース完了まで数時間 • システム移行後 • 実働10分程度でデプロイ完了 Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 71

72.

その他アーキテクチャ Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 72

73.

データベースのスケーリング • k8sによってアプリケーションのスケーリン グはできたが、DBのスケールもしたい → シャーディングの導入 Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 73

74.

DBシャーディングについて 振り分け Policy ID等でノードを決定 Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. • DBの水平分割 • EclipseLinkの機能を 使ってDBシャーディング • アノテーションでシャー ディングポリシーを指定 可能 74

75.

JPAのEntity実装 @Entity @Data @Table(name = ”sample") PartitioningPolicyを設定するだけ @IdClass(SamplePk.class) @Partitioning( name = ”sampleIdPartitioning", partitioningClass = SampleIdPartitioningPolicy.class) @Partitioned(”sampleIdPartitioning") @AllArgsConstructor @NoArgsConstructor public class SampleJpaEntity { @Id Long sampleId; @Id Integer hogeId; Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 75

76.

ID生成の問題 アプリやDBが分散することでDBサイドでの ID発行(AUTO_INCREMENT)が扱いづらくなった • →アプリサイドでの発行が必要 • →標準規格のUUIDは36byteもあり性能面の 不安 • f48b53b8-fe1e-4670-a19a-650fda31bced Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 76

77.

UUIDは件数が増えると性能が低下 MySQLでのINSERT時間 Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 77

78.

64bitの独自ID体系を採用 timestamp machine id sequence 41bit 12bit 10bit 63bit timestamp(41bit) : 現在のunixtime(milliseconds)から、ある時点のunixtimeを引いた値 machine id(12bit) : 生成器ごとに割り当てられたID sequence(10bit) : 生成器ごとに採番するsequence番号 BIGINTに収まりほぼインクリメンタルなので、MySQLで 効率的に扱える Twitterのsnowflakeを参考に実装 Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 78

79.

一意になるようにMachine IDを管理 定期的にheartbeat MachineID サービス Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. machineId=1234 各サービス 79

80.

まとめ Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 80

81.

k8sに載せるのに必要なこと • コンテナ • Dockerイメージの作成 • アプリケーション • • • • クラウドネイティブ化 Liveness probe / Readiness probe Graceful Shutdown ログ出力 • 開発フローの対応 Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 81

82.

k8sに移行してみて • リリース時間など、運用コストは大幅に削 減できた • 数時間 → 10分 • 負荷についてもスケールできるように • 2000 req/s ↑ • ログが集約され、調査コストも削減できた Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 82

83.

大変だったところ • 利用技術のスイッチ • パッケージングやCI/CD、利用言語も変更したため • 社内PFとの連携 • IPベースのACLからの変更 • 考え方のスイッチ • 従来のアーキテクチャからCloud Nativeなものへ • まだ、k8sのポテンシャルを十分引き出せていない Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 83

84.

これから • コンテナデザインパターンの活用 • 共通機能を別コンテナに切り出し • サイドカーパターンなど • リリース方法の検討 • カナリアリリース Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 84

85.

情報技術で 人々のマネーライフの課題を解決する Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 85