2.5K Views
May 28, 18
スライド概要
JJUG CCC 2018 Springの登壇資料です。
2023年10月からSpeaker Deckに移行しました。最新情報はこちらをご覧ください。 https://speakerdeck.com/lycorptech_jp
Spring Boot on Kubernetes Yahoo!ズバトク事例 2018/05/26 ヤフー株式会社 玉利 拓郎 Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved.
自己紹介 玉利 拓郎 ヤフー株式会社 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
今日話すこと • Yahoo!ズバトクでSpring Bootを どうやってKubernetesに載せたか • Kubernetesに合わせた開発フロー Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 3
今日話さないこと • Kubernetesサイドの話 • Kubernetes自体の運用など Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 4
アジェンダ • なぜKubernetesに移行したか • Kubernetesに載せるために必要なこと • その他導入したアーキテクチャ Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 5
Yahoo!ズバトクとは “毎日ワクワク!おトクが当たる&もらえる” くじやキャンペーンを掲載するためのプラットフォーム Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 6
なぜ Kubernetesに 移行したか Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 7
高まる需要 • 販促サービスとしての需要が高まる • キャンペーン数は日に日に増加 Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 8
アクセス数の特性 • 特定の時間にアクセス数が急激に増える • • • • キャンペーンの開始 人気キャンペーンの開催 PUSH通知 etc… Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 9
大型キャンペーンでは厳戒態勢で望む必要 2000 req/s Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 10
増える要望 • 様々なキャンペーンに対応するため、 機能追加要望が増大 → 開発が追いつかない Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 11
移行前のシステム構成 別サービス API ほぼ全ての機能が ココに載ってる etc Web × n MySQL Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 12
移行前のシステム構成 別サービス 1テーブルに数億レコード API etc Web × n DBも一極集中 MySQL Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 13
現行システムではそろそろ限界 • リリース時間 大 • DB負荷 大 • スケールコスト 大 • 結合試験のコスト 大 • 改修コスト 大 Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 14
運用コストを下げ、開発速度を高めたい • リリース時間の削減 • システムのスケーラビリティの確保 • テスト工数の削減 • 改修コストの削減 Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 15
Kubernetes Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 16
Kubernetes(k8s)とは • コンテナのオーケストレーションプラット フォーム • コンテナ化されたアプリケーションの展開、 スケーリング、運用自動化を行う Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 17
Kubernetesでできること • フェイルオーバー • スケーリング • スケジューリング • ロードバランス • サービスディスカバリ Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 18
Kubernetesでできること • 異常があると自動的にコンテナ再起動 • 自由にコンテナ(Pod)数を変更 • リクエストの負荷分散 • サービスへのルーティング Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 19
k8sでいくつかの課題を解決できそう • リリース時間 → コンテナ管理で短縮 • スケールコスト → k8sの機能で一発 • 改修コスト • マイクロサービス化で修正箇所を集約 • (k8sならばサービスを追加するコストが低い) Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 20
システム移行することに • • • • IaaS → CaaS(Kubernetes) PHP → Java モノリシック → マイクロサービス Jenkins → Concourse CI Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 21
アプリケーションアーキテクチャの変更 • モノリシック → マイクロサービス • スケーラビリティの向上 • DB負荷の分散 • 改修リスクの削減 Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 22
マイクロサービスアーキテクチャ くじWEB 景品 履歴 くじ MQ メール DBはサービス毎に分割 Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 後処理は非同期 23
DDDで機能分割 • ドメイン駆動設計の 思想を基に、 サービスを分割 Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 24
ネットワーク構成 最終的には 40サービスほどに Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 25
k8sに載せるために 必要なこと Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 26
k8sへ載せるのに必要なもの • k8sの基礎知識 • コンテナ • Dockerイメージの作成 • アプリケーション • クラウドネイティブ化 • Liveness probe / Readiness probe • Graceful Shutdown • k8s • manifestファイル Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 27
k8sを活かすのに必要なもの • 開発フロー • CI/CD • 自動テスト Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 28
k8sの基礎知識 Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 29
Kubernetesの特徴 • コンテナ中心のインフラ • 宣言的設定 Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 30
宣言的設定 • 「望ましい状態」を記述した設定ファイル (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
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
Pod • デプロイの最小単位 • Dockerコンテナを内包 • 複数コンテナも可 Docker コンテナ Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. Pod 33
Deployment • ローリングアップデートや ロールバックを管理する • ReplicaSetを通して、Pod を生成・管理する Deployment ReplicaSet Pod Pod Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. Pod 34
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
Service VIP: 10.0.0.12 app=lot-web Service Pod Pod Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. • 仮想IPとポート • ラベルセレクタによる Podのグルーピング Pod 36
Ingress Ingress toku.yahoo.co.jp /entry /lot Lot Service • L7負荷分散 • バーチャルホスト • パスによる振り分け Entry Service Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 37
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
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
その他の構成要素 • ConfigMap • アプリケーション用の設定値を保持 • Secret • 秘密情報を保持 • Job / CronJob • バッチ処理等のジョブ Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 40
アプリケーション編 Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 41
アプリケーション周りで必要なこと • コンテナ • Dockerイメージの作成 • アプリケーション • • • • クラウドネイティブ化 Liveness probe / Readiness probe Graceful Shutdown ログ出力 Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 42
Dockerとは • コンテナの実行・管理ツール • イメージで管理するので、 環境の一貫性がある • 素早いアプリケーションの展開 Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 43
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
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
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
シェルスクリプト化する場合は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
アプリケーションへの対応 • クラウドネイティブ化 • Liveness probe / Readiness probe • Graceful Shutdown Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 48
クラウドネイティブなアプリ 基本は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
抜粋すると • 設定 • → 設定値は環境変数に格納 • ポートバインディング • → 組み込みサーバを使う • 廃棄容易性 • 起動の高速化、グレースフルシャットダウン • ログ • 標準出力に出力し、集約する Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 50
設定の環境変数からの読み込み • 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
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
ヘルスチェックエンドポイント • k8sがpodの死活チェックをするためのエ ンドポイントが2種類ある • Liveness probe • Readiness probe Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 53
Liveness probe / Readiness probe Liveness probe • アプリケーションが生きてるかどうかをチェック • NGならばpodを再作成 Readiness probe • 利用可能になっているかのチェック • OKになったらサービスイン Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 54
ズバトクでの実装方法 Liveness probe • Actuatorを使い、status 200を返すだけのエ ンドポイント作成 Readiness probe • Actuatorのhealthエンドポイントを流用 • DBのチェックなどもやってくれる Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 55
コード例 @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
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
LivenessとReadinessをわけたわけ • Liveness probeは軽くすべき • また、DB等の外部システムダウンした際 はPod再起動しても効果が薄い Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 58
Graceful Shutdown • Podが終了する際に適切な終了処理を行う • 処理中のリクエストの対応 • リソースの破棄 →実装しなかったら、処理中にエラーが発生 Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 59
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
Graceful Shutdownの実装 • 通常はアプリケーションサーバの機能を 使って実装 • Jettyではkeepalive等の扱いがうまくいか なかったので、独自でservletのFilterを使 い処理中セッションをカウントするようにし た Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 61
アプリケーションログについて • ログは標準出力に出す • Podが終了したらファイルは消滅 • マイクロサービスの場合は相関IDは必須 Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 62
相関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
開発フロー編 Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 64
k8sの仕組みを活かすためのフロー • Git上でオペレーションが完結するフロー → GitOps • Pull Requestでオペレーション • 環境毎のPull Requestは自動生成 • CI/CDは必須 Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 65
開発フロー 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
Concourseで複雑なパイプラインを実現 パイプラインの定義はYAMLで定義しGit管理 Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 67
テストの自動化 • このフローで安心してリリースするために は、テスト自動化は必須 Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 68
テストの自動化 E2E テスト 機能テスト • 3種類のテストを実装 • ユニットテスト • クラス単体 • 機能テスト • サービス単体 • E2Eテスト ユニットテスト テストピラミッド Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. • 全サービス結合 69
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
リリース時間の変化 • これまで • パッケージングからサービスアウトなどを含 むリリース完了まで数時間 • システム移行後 • 実働10分程度でデプロイ完了 Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 71
その他アーキテクチャ Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 72
データベースのスケーリング • k8sによってアプリケーションのスケーリン グはできたが、DBのスケールもしたい → シャーディングの導入 Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 73
DBシャーディングについて 振り分け Policy ID等でノードを決定 Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. • DBの水平分割 • EclipseLinkの機能を 使ってDBシャーディング • アノテーションでシャー ディングポリシーを指定 可能 74
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
ID生成の問題 アプリやDBが分散することでDBサイドでの ID発行(AUTO_INCREMENT)が扱いづらくなった • →アプリサイドでの発行が必要 • →標準規格のUUIDは36byteもあり性能面の 不安 • f48b53b8-fe1e-4670-a19a-650fda31bced Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 76
UUIDは件数が増えると性能が低下 MySQLでのINSERT時間 Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 77
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
一意になるようにMachine IDを管理 定期的にheartbeat MachineID サービス Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. machineId=1234 各サービス 79
まとめ Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 80
k8sに載せるのに必要なこと • コンテナ • Dockerイメージの作成 • アプリケーション • • • • クラウドネイティブ化 Liveness probe / Readiness probe Graceful Shutdown ログ出力 • 開発フローの対応 Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 81
k8sに移行してみて • リリース時間など、運用コストは大幅に削 減できた • 数時間 → 10分 • 負荷についてもスケールできるように • 2000 req/s ↑ • ログが集約され、調査コストも削減できた Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 82
大変だったところ • 利用技術のスイッチ • パッケージングやCI/CD、利用言語も変更したため • 社内PFとの連携 • IPベースのACLからの変更 • 考え方のスイッチ • 従来のアーキテクチャからCloud Nativeなものへ • まだ、k8sのポテンシャルを十分引き出せていない Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 83
これから • コンテナデザインパターンの活用 • 共通機能を別コンテナに切り出し • サイドカーパターンなど • リリース方法の検討 • カナリアリリース Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 84
情報技術で 人々のマネーライフの課題を解決する Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 85