Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved.
2018/05/26
Spring Boot on Kubernetes
Yahoo!ズバトク事例
ヤフー株式会社
玉利 拓郎
Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved.
自己紹介
2
玉利 拓郎
ヤフー株式会社 2009入社
Yahoo!ウォレット
Yahoo!ショッピング
Yahoo!ズバトク
Yahoo!マネー
言語
Java 1.4 -> PHP 5.3 -> Java 8
Kotlinに浮気したい Rustも気になる
@yotama
Tamari Takuro
↑タマリン
Photo by Jeroen Kransen - Gouden leeuwaapje(2008) / CC BY-SA 2.0
Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved.
今日話すこと
3
• Yahoo!ズバトクでSpring Bootを
どうやってKubernetesに載せたか
• Kubernetesに合わせた開発フロー
Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved.
今日話さないこと
4
• Kubernetesサイドの話
• Kubernetes自体の運用など
Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved.
アジェンダ
5
• なぜKubernetesに移行したか
• Kubernetesに載せるために必要なこと
• その他導入したアーキテクチャ
Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved.
Yahoo!ズバトクとは
6
“毎日ワクワク!おトクが当たる&もらえる”
くじやキャンペーンを掲載するためのプラットフォーム
Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved.
なぜ
Kubernetesに
移行したか
7
Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved.
高まる需要
8
• 販促サービスとしての需要が高まる
• キャンペーン数は日に日に増加
Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved.
アクセス数の特性
9
• 特定の時間にアクセス数が急激に増える
• キャンペーンの開始
• 人気キャンペーンの開催
• PUSH通知
• etc…
Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 10
2000 req/s
大型キャンペーンでは厳戒態勢で望む必要
Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved.
増える要望
11
• 様々なキャンペーンに対応するため、
機能追加要望が増大
→ 開発が追いつかない
Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved.
移行前のシステム構成
12
MySQL
Web × netcAPI
別サービス
ほぼ全ての機能が
ココに載ってる
Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved.
移行前のシステム構成
13
MySQL
Web × n
1テーブルに数億レコード
DBも一極集中
etcAPI
別サービス
Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved.
現行システムではそろそろ限界
14
• リリース時間 大
• DB負荷 大
• スケールコスト 大
• 結合試験のコスト 大
• 改修コスト 大
Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved.
運用コストを下げ、開発速度を高めたい
15
• リリース時間の削減
• システムのスケーラビリティの確保
• テスト工数の削減
• 改修コストの削減
Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved. 16
Kubernetes
Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved.
Kubernetes(k8s)とは
17
• コンテナのオーケストレーションプラット
フォーム
• コンテナ化されたアプリケーションの展開、
スケーリング、運用自動化を行う
Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved.
Kubernetesでできること
18
• フェイルオーバー
• スケーリング
• スケジューリング
• ロードバランス
• サービスディスカバリ
Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved.
Kubernetesでできること
19
• 異常があると自動的にコンテナ再起動
• 自由にコンテナ(Pod)数を変更
• リクエストの負荷分散
• サービスへのルーティング
Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved.
k8sでいくつかの課題を解決できそう
20
• リリース時間 → コンテナ管理で短縮
• スケールコスト → k8sの機能で一発
• 改修コスト
• マイクロサービス化で修正箇所を集約
• (k8sならばサービスを追加するコストが低い)
Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved.
システム移行することに
21
• IaaS → CaaS(Kubernetes)
• PHP → Java
• モノリシック → マイクロサービス
• Jenkins → Concourse CI
Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved.
アプリケーションアーキテクチャの変更
22
• モノリシック → マイクロサービス
• スケーラビリティの向上
• DB負荷の分散
• 改修リスクの削減
Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved.
マイクロサービスアーキテクチャ
23
くじ
くじWEB
景品
履歴
MQ
メール
DBはサービス毎に分割 後処理は非同期
Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved.
DDDで機能分割
24
• ドメイン駆動設計の
思想を基に、
サービスを分割
Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved.
ネットワーク構成
25
最終的には
40サービスほどに
Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved.
k8sに載せるために
必要なこと
26
Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved.
k8sへ載せるのに必要なもの
27
• k8sの基礎知識
• コンテナ
• Dockerイメージの作成
• アプリケーション
• クラウドネイティブ化
• Liveness probe / Readiness probe
• Graceful Shutdown
• k8s
• manifestファイル
Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved.
k8sを活かすのに必要なもの
28
• 開発フロー
• CI/CD
• 自動テスト
Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved.
k8sの基礎知識
29
Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved.
Kubernetesの特徴
30
• コンテナ中心のインフラ
• 宣言的設定
Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved.
宣言的設定
31
• 「望ましい状態」を記述した設定ファイル
(manifest)で定義
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
imagePullPolicy: Always
YAMLで設定を書く
Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved.
Kubernetesのリソース構成イメージ
32※飽くまでイメージです
Ingress
Service
Deployment
Pod Pod Pod
Service
Deployment
Pod Pod Pod
cluster
namespace
transaction
それぞれのリソースをYAMLで定義する
1サービスのセット
Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved.
Pod
33
• デプロイの最小単位
• Dockerコンテナを内包
• 複数コンテナも可
Docker
コンテナ
Pod
Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved.
Deployment
34
• ローリングアップデートや
ロールバックを管理する
• ReplicaSetを通して、Pod
を生成・管理する
Deployment
Pod Pod Pod
ReplicaSet
Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved.
Deploymentの定義
35
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.
Service
36
• 仮想IPとポート
• ラベルセレクタによる
Podのグルーピング
Pod Pod Pod
Service
VIP: 10.0.0.12
app=lot-web
Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved.
Ingress
37
• L7負荷分散
• バーチャルホスト
• パスによる振り分け
Ingress
Lot Service Entry Service
toku.yahoo.co.jp
/lot /entry
Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved.
Ingressの定義
38
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.
Ingress
39
• Ingressは前方一致でしか
振り分けられない
• ズバトクではnginxで振り分
けを実施
Ingress
lot Service entry Service
toku.yahoo.co.jp
/campaing01/lot /campaign01/entry
nginx
Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved.
その他の構成要素
40
• ConfigMap
• アプリケーション用の設定値を保持
• Secret
• 秘密情報を保持
• Job / CronJob
• バッチ処理等のジョブ
Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved.
アプリケーション編
41
Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved.
アプリケーション周りで必要なこと
42
• コンテナ
• Dockerイメージの作成
• アプリケーション
• クラウドネイティブ化
• Liveness probe / Readiness probe
• Graceful Shutdown
• ログ出力
Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved.
Dockerとは
43
• コンテナの実行・管理ツール
• イメージで管理するので、
環境の一貫性がある
• 素早いアプリケーションの展開
Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved.
Dockerfile
44
• 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.
Dockerイメージの作成と実行
45
# Dockerイメージをビルド
$ docker build . -t hoge/myapp
# Dockerコンテナを実行
$ docker run -d --rm -it hoge/myapp:latest
Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved.
Dockerfile例
46
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.
シェルスクリプト化する場合はexecをつける
47
exec java ${JAVA_OPTS} -Djava.security.egd=file:/dev/./urandom -jar $1
PIDが1になるように、javaコマンドの前にexecをつける
Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved.
アプリケーションへの対応
48
• クラウドネイティブ化
• Liveness probe / Readiness probe
• Graceful Shutdown
Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved.
クラウドネイティブなアプリ
49
基本はTwelve-factor app
クラウドで動くアプリケー
ションが従うべき12のプラク
ティス
1. コードベース
2. 依存関係
3. 設定
4. バックエンドサービス
5. ビルド、リリース、実行
6. プロセス
7. ポートバインディング
8. 並行性
9. 廃棄容易性
10. 開発/本番一致
11. ログ
12. 管理プロセス
Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved.
抜粋すると
50
• 設定
• → 設定値は環境変数に格納
• ポートバインディング
• → 組み込みサーバを使う
• 廃棄容易性
• 起動の高速化、グレースフルシャットダウン
• ログ
• 標準出力に出力し、集約する
Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved.
設定の環境変数からの読み込み
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.
k8sで環境変数に注入
52
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
key: datasource-url
k8s/deployment.yaml
env:
- name: 環境変数名
valueFrom: 値の取得元
(ConfigMap or Secret)
Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved.
ヘルスチェックエンドポイント
53
• k8sがpodの死活チェックをするためのエ
ンドポイントが2種類ある
• Liveness probe
• Readiness probe
Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved.
Liveness probe / Readiness probe
54
Liveness probe
• アプリケーションが生きてるかどうかをチェック
• NGならばpodを再作成
Readiness probe
• 利用可能になっているかのチェック
• OKになったらサービスイン
Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved.
ズバトクでの実装方法
55
Liveness probe
• Actuatorを使い、status 200を返すだけのエ
ンドポイント作成
Readiness probe
• Actuatorのhealthエンドポイントを流用
• DBのチェックなどもやってくれる
Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved.
コード例
56
@Endpoint(id = "liveness")
public class LivenessEndpoint {
@ReadOperation
public Health execute() {
return Health.up().build();
}
}
@Endpoint(id = "readiness")
public class ReadinessEndpoint {
private final HealthEndpoint healthEndpoint;
public ReadinessEndpoint(HealthEndpoint healthEndpoint) {
this.healthEndpoint = healthEndpoint;
}
@ReadOperation
public Health execute() {
return this.healthEndpoint.health();
}
}
Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved.
Liveness probe / Readiness probe
57
livenessProbe:
httpGet:
path: /liveness
port: 9990
initialDelaySeconds: 60
timeoutSeconds: 1
periodSeconds: 5
readinessProbe:
httpGet:
path: /readiness
port: 9990
initialDelaySeconds: 20
timeoutSeconds: 5
periodSeconds: 5
deployment.yamlに設定を記述
management:
security:
enabled: false
port: 9990
endpoints:
health:
path: readiness
application.yml
外部からアクセス出来ないように
actuatorのportを9990に
Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved.
LivenessとReadinessをわけたわけ
58
• Liveness probeは軽くすべき
• また、DB等の外部システムダウンした際
はPod再起動しても効果が薄い
Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved.
Graceful Shutdown
59
• Podが終了する際に適切な終了処理を行う
• 処理中のリクエストの対応
• リソースの破棄
→実装しなかったら、処理中にエラーが発生
Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved.
Graceful Shutdownの実装
60
• ActuatorのShutdown Endpointを拡張し、
処理中のリクエストがなくなるまでWait
※ActuatorのShutdownEndpointはGracefulではないので注意
lifecycle:
preStop:
httpGet:
path: /shutdown
port: 9990
deployment.yaml
Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved.
Graceful Shutdownの実装
61
• 通常はアプリケーションサーバの機能を
使って実装
• Jettyではkeepalive等の扱いがうまくいか
なかったので、独自でservletのFilterを使
い処理中セッションをカウントするようにし
た
Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved.
アプリケーションログについて
62
• ログは標準出力に出す
• Podが終了したらファイルは消滅
• マイクロサービスの場合は相関IDは必須
Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved.
相関ID
63
• Spring Cloud Sleuthを使用
• 依存を追加するだけでリクエストで一意な
IDをログに出力
• サービス数が多いのでこれがなければ運
用がつらくなる
time:2018-03-22T13:52:22.855+09:00 level:INFO trace_id:8f01dc2dc4a7f7b6 span_id:8f01dc2dc4a7f7b6
time:2018-03-22T13:52:23.123+09:00 level:INFO trace_id:8f01dc2dc4a7f7b6 span_id:8f01dc2dc4a7f7b6
Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved.
開発フロー編
64
Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved.
k8sの仕組みを活かすためのフロー
65
• Git上でオペレーションが完結するフロー
→ GitOps
• Pull Requestでオペレーション
• 環境毎のPull Requestは自動生成
• CI/CDは必須
Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved.
開発フロー
66
Deploy
GitHub Docker
registry
1. clone 3. プルリクエスト
2. 開発/テスト
Concourse CI
7. マージ
4. テスト/ビルド
5. パブリッシュ
6. プルリクエスト
develop e2e production
・・・
Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved.
Concourseで複雑なパイプラインを実現
67
パイプラインの定義はYAMLで定義しGit管理
Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved.
テストの自動化
68
• このフローで安心してリリースするために
は、テスト自動化は必須
Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved.
テストの自動化
69
• 3種類のテストを実装
• ユニットテスト
• クラス単体
• 機能テスト
• サービス単体
• E2Eテスト
• 全サービス結合
E2E
テスト
機能テスト
ユニットテスト
テストピラミッド
Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved.
E2Eテスト
70
• 全サービスを通してのテスト
• JUnit
• Selenium
@Test
public void 抽選_01_くじを引く() throws Exception {
ログインケース
.ログインする(xxxx);
抽選ケース
.Action_抽選画面を開く(CAMPAIGN_PATH)
.Verify_抽選_抽選画面を表示(xxxx)
.Verify_抽選_キャンペーン期間表示();
}
Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved.
リリース時間の変化
71
• これまで
• パッケージングからサービスアウトなどを含
むリリース完了まで数時間
• システム移行後
• 実働10分程度でデプロイ完了
Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved.
その他アーキテクチャ
72
Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved.
データベースのスケーリング
73
• k8sによってアプリケーションのスケーリン
グはできたが、DBのスケールもしたい
→ シャーディングの導入
Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved.
DBシャーディングについて
74
• DBの水平分割
• EclipseLinkの機能を
使ってDBシャーディング
• アノテーションでシャー
ディングポリシーを指定
可能
振り分け
Policy
ID等でノードを決定
Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved.
JPAのEntity実装
75
@Entity
@Data
@Table(name = ”sample")
@IdClass(SamplePk.class)
@Partitioning(
name = ”sampleIdPartitioning",
partitioningClass = SampleIdPartitioningPolicy.class)
@Partitioned(”sampleIdPartitioning")
@AllArgsConstructor
@NoArgsConstructor
public class SampleJpaEntity {
@Id
Long sampleId;
@Id
Integer hogeId;
PartitioningPolicyを設定するだけ
Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved.
ID生成の問題
76
アプリやDBが分散することでDBサイドでの
ID発行(AUTO_INCREMENT)が扱いづらくなった
• →アプリサイドでの発行が必要
• →標準規格のUUIDは36byteもあり性能面の
不安
• f48b53b8-fe1e-4670-a19a-650fda31bced
Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved.
UUIDは件数が増えると性能が低下
77
MySQLでのINSERT時間
Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved.
64bitの独自ID体系を採用
78
timestamp(41bit) : 現在のunixtime(milliseconds)から、ある時点のunixtimeを引いた値
machine id(12bit) : 生成器ごとに割り当てられたID
sequence(10bit) : 生成器ごとに採番するsequence番号
BIGINTに収まりほぼインクリメンタルなので、MySQLで
効率的に扱える
timestamp machine id sequence
41bit 12bit 10bit
63bit
Twitterのsnowflakeを参考に実装
Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved.
一意になるようにMachine IDを管理
79
各サービス
MachineID
サービス
定期的にheartbeat
machineId=1234
Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved.
まとめ
80
Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved.
k8sに載せるのに必要なこと
81
• コンテナ
• Dockerイメージの作成
• アプリケーション
• クラウドネイティブ化
• Liveness probe / Readiness probe
• Graceful Shutdown
• ログ出力
• 開発フローの対応
Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved.
k8sに移行してみて
82
• リリース時間など、運用コストは大幅に削
減できた
• 数時間 → 10分
• 負荷についてもスケールできるように
• 2000 req/s ↑
• ログが集約され、調査コストも削減できた
Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved.
大変だったところ
83
• 利用技術のスイッチ
• パッケージングやCI/CD、利用言語も変更したため
• 社内PFとの連携
• IPベースのACLからの変更
• 考え方のスイッチ
• 従来のアーキテクチャからCloud Nativeなものへ
• まだ、k8sのポテンシャルを十分引き出せていない
Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved.
これから
84
• コンテナデザインパターンの活用
• 共通機能を別コンテナに切り出し
• サイドカーパターンなど
• リリース方法の検討
• カナリアリリース
Copyright © 2017 Yahoo Japan Corporation. All Rights Reserved.
情報技術で
人々のマネーライフの課題を解決する
85

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

  • 1.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. 2018/05/26 Spring Boot on Kubernetes Yahoo!ズバトク事例 ヤフー株式会社 玉利 拓郎
  • 2.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. 自己紹介 2 玉利 拓郎 ヤフー株式会社 2009入社 Yahoo!ウォレット Yahoo!ショッピング Yahoo!ズバトク Yahoo!マネー 言語 Java 1.4 -> PHP 5.3 -> Java 8 Kotlinに浮気したい Rustも気になる @yotama Tamari Takuro ↑タマリン Photo by Jeroen Kransen - Gouden leeuwaapje(2008) / CC BY-SA 2.0
  • 3.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. 今日話すこと 3 • Yahoo!ズバトクでSpring Bootを どうやってKubernetesに載せたか • Kubernetesに合わせた開発フロー
  • 4.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. 今日話さないこと 4 • Kubernetesサイドの話 • Kubernetes自体の運用など
  • 5.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. アジェンダ 5 • なぜKubernetesに移行したか • Kubernetesに載せるために必要なこと • その他導入したアーキテクチャ
  • 6.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. Yahoo!ズバトクとは 6 “毎日ワクワク!おトクが当たる&もらえる” くじやキャンペーンを掲載するためのプラットフォーム
  • 7.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. なぜ Kubernetesに 移行したか 7
  • 8.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. 高まる需要 8 • 販促サービスとしての需要が高まる • キャンペーン数は日に日に増加
  • 9.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. アクセス数の特性 9 • 特定の時間にアクセス数が急激に増える • キャンペーンの開始 • 人気キャンペーンの開催 • PUSH通知 • etc…
  • 10.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. 10 2000 req/s 大型キャンペーンでは厳戒態勢で望む必要
  • 11.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. 増える要望 11 • 様々なキャンペーンに対応するため、 機能追加要望が増大 → 開発が追いつかない
  • 12.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. 移行前のシステム構成 12 MySQL Web × netcAPI 別サービス ほぼ全ての機能が ココに載ってる
  • 13.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. 移行前のシステム構成 13 MySQL Web × n 1テーブルに数億レコード DBも一極集中 etcAPI 別サービス
  • 14.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. 現行システムではそろそろ限界 14 • リリース時間 大 • DB負荷 大 • スケールコスト 大 • 結合試験のコスト 大 • 改修コスト 大
  • 15.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. 運用コストを下げ、開発速度を高めたい 15 • リリース時間の削減 • システムのスケーラビリティの確保 • テスト工数の削減 • 改修コストの削減
  • 16.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. 16 Kubernetes
  • 17.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. Kubernetes(k8s)とは 17 • コンテナのオーケストレーションプラット フォーム • コンテナ化されたアプリケーションの展開、 スケーリング、運用自動化を行う
  • 18.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. Kubernetesでできること 18 • フェイルオーバー • スケーリング • スケジューリング • ロードバランス • サービスディスカバリ
  • 19.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. Kubernetesでできること 19 • 異常があると自動的にコンテナ再起動 • 自由にコンテナ(Pod)数を変更 • リクエストの負荷分散 • サービスへのルーティング
  • 20.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. k8sでいくつかの課題を解決できそう 20 • リリース時間 → コンテナ管理で短縮 • スケールコスト → k8sの機能で一発 • 改修コスト • マイクロサービス化で修正箇所を集約 • (k8sならばサービスを追加するコストが低い)
  • 21.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. システム移行することに 21 • IaaS → CaaS(Kubernetes) • PHP → Java • モノリシック → マイクロサービス • Jenkins → Concourse CI
  • 22.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. アプリケーションアーキテクチャの変更 22 • モノリシック → マイクロサービス • スケーラビリティの向上 • DB負荷の分散 • 改修リスクの削減
  • 23.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. マイクロサービスアーキテクチャ 23 くじ くじWEB 景品 履歴 MQ メール DBはサービス毎に分割 後処理は非同期
  • 24.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. DDDで機能分割 24 • ドメイン駆動設計の 思想を基に、 サービスを分割
  • 25.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. ネットワーク構成 25 最終的には 40サービスほどに
  • 26.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. k8sに載せるために 必要なこと 26
  • 27.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. k8sへ載せるのに必要なもの 27 • k8sの基礎知識 • コンテナ • Dockerイメージの作成 • アプリケーション • クラウドネイティブ化 • Liveness probe / Readiness probe • Graceful Shutdown • k8s • manifestファイル
  • 28.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. k8sを活かすのに必要なもの 28 • 開発フロー • CI/CD • 自動テスト
  • 29.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. k8sの基礎知識 29
  • 30.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. Kubernetesの特徴 30 • コンテナ中心のインフラ • 宣言的設定
  • 31.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. 宣言的設定 31 • 「望ましい状態」を記述した設定ファイル (manifest)で定義 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 imagePullPolicy: Always YAMLで設定を書く
  • 32.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. Kubernetesのリソース構成イメージ 32※飽くまでイメージです Ingress Service Deployment Pod Pod Pod Service Deployment Pod Pod Pod cluster namespace transaction それぞれのリソースをYAMLで定義する 1サービスのセット
  • 33.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. Pod 33 • デプロイの最小単位 • Dockerコンテナを内包 • 複数コンテナも可 Docker コンテナ Pod
  • 34.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. Deployment 34 • ローリングアップデートや ロールバックを管理する • ReplicaSetを通して、Pod を生成・管理する Deployment Pod Pod Pod ReplicaSet
  • 35.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. Deploymentの定義 35 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:
  • 36.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. Service 36 • 仮想IPとポート • ラベルセレクタによる Podのグルーピング Pod Pod Pod Service VIP: 10.0.0.12 app=lot-web
  • 37.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. Ingress 37 • L7負荷分散 • バーチャルホスト • パスによる振り分け Ingress Lot Service Entry Service toku.yahoo.co.jp /lot /entry
  • 38.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. Ingressの定義 38 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
  • 39.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. Ingress 39 • Ingressは前方一致でしか 振り分けられない • ズバトクではnginxで振り分 けを実施 Ingress lot Service entry Service toku.yahoo.co.jp /campaing01/lot /campaign01/entry nginx
  • 40.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. その他の構成要素 40 • ConfigMap • アプリケーション用の設定値を保持 • Secret • 秘密情報を保持 • Job / CronJob • バッチ処理等のジョブ
  • 41.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. アプリケーション編 41
  • 42.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. アプリケーション周りで必要なこと 42 • コンテナ • Dockerイメージの作成 • アプリケーション • クラウドネイティブ化 • Liveness probe / Readiness probe • Graceful Shutdown • ログ出力
  • 43.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. Dockerとは 43 • コンテナの実行・管理ツール • イメージで管理するので、 環境の一貫性がある • 素早いアプリケーションの展開
  • 44.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. Dockerfile 44 • DockerfileでImageを定義 FROM openjdk:8 ARG JAR_FILE COPY ${JAR_FILE} app.jar ENTRYPOINT ["java", "-Djava.security.egd=file:/dev/./urandom", "-jar", "/app.jar"] ベースのイメージ プロセス起動用のコマンド
  • 45.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. Dockerイメージの作成と実行 45 # Dockerイメージをビルド $ docker build . -t hoge/myapp # Dockerコンテナを実行 $ docker run -d --rm -it hoge/myapp:latest
  • 46.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. Dockerfile例 46 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"] ズバトクでは オプション指定簡略化のため 外部スクリプト化
  • 47.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. シェルスクリプト化する場合はexecをつける 47 exec java ${JAVA_OPTS} -Djava.security.egd=file:/dev/./urandom -jar $1 PIDが1になるように、javaコマンドの前にexecをつける
  • 48.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. アプリケーションへの対応 48 • クラウドネイティブ化 • Liveness probe / Readiness probe • Graceful Shutdown
  • 49.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. クラウドネイティブなアプリ 49 基本はTwelve-factor app クラウドで動くアプリケー ションが従うべき12のプラク ティス 1. コードベース 2. 依存関係 3. 設定 4. バックエンドサービス 5. ビルド、リリース、実行 6. プロセス 7. ポートバインディング 8. 並行性 9. 廃棄容易性 10. 開発/本番一致 11. ログ 12. 管理プロセス
  • 50.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. 抜粋すると 50 • 設定 • → 設定値は環境変数に格納 • ポートバインディング • → 組み込みサーバを使う • 廃棄容易性 • 起動の高速化、グレースフルシャットダウン • ログ • 標準出力に出力し、集約する
  • 51.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. 設定の環境変数からの読み込み 51 • Spring Bootはプロパティを環境変数から バインドできる property spring.datasource.url=jdbc:mysql://localhost:3306/test 環境変数 SPRING_DATASOURCE_URL=jdbc:mysql://localhost:3306/test 以下は等価
  • 52.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. k8sで環境変数に注入 52 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 key: datasource-url k8s/deployment.yaml env: - name: 環境変数名 valueFrom: 値の取得元 (ConfigMap or Secret)
  • 53.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. ヘルスチェックエンドポイント 53 • k8sがpodの死活チェックをするためのエ ンドポイントが2種類ある • Liveness probe • Readiness probe
  • 54.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. Liveness probe / Readiness probe 54 Liveness probe • アプリケーションが生きてるかどうかをチェック • NGならばpodを再作成 Readiness probe • 利用可能になっているかのチェック • OKになったらサービスイン
  • 55.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. ズバトクでの実装方法 55 Liveness probe • Actuatorを使い、status 200を返すだけのエ ンドポイント作成 Readiness probe • Actuatorのhealthエンドポイントを流用 • DBのチェックなどもやってくれる
  • 56.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. コード例 56 @Endpoint(id = "liveness") public class LivenessEndpoint { @ReadOperation public Health execute() { return Health.up().build(); } } @Endpoint(id = "readiness") public class ReadinessEndpoint { private final HealthEndpoint healthEndpoint; public ReadinessEndpoint(HealthEndpoint healthEndpoint) { this.healthEndpoint = healthEndpoint; } @ReadOperation public Health execute() { return this.healthEndpoint.health(); } }
  • 57.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. Liveness probe / Readiness probe 57 livenessProbe: httpGet: path: /liveness port: 9990 initialDelaySeconds: 60 timeoutSeconds: 1 periodSeconds: 5 readinessProbe: httpGet: path: /readiness port: 9990 initialDelaySeconds: 20 timeoutSeconds: 5 periodSeconds: 5 deployment.yamlに設定を記述 management: security: enabled: false port: 9990 endpoints: health: path: readiness application.yml 外部からアクセス出来ないように actuatorのportを9990に
  • 58.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. LivenessとReadinessをわけたわけ 58 • Liveness probeは軽くすべき • また、DB等の外部システムダウンした際 はPod再起動しても効果が薄い
  • 59.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. Graceful Shutdown 59 • Podが終了する際に適切な終了処理を行う • 処理中のリクエストの対応 • リソースの破棄 →実装しなかったら、処理中にエラーが発生
  • 60.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. Graceful Shutdownの実装 60 • ActuatorのShutdown Endpointを拡張し、 処理中のリクエストがなくなるまでWait ※ActuatorのShutdownEndpointはGracefulではないので注意 lifecycle: preStop: httpGet: path: /shutdown port: 9990 deployment.yaml
  • 61.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. Graceful Shutdownの実装 61 • 通常はアプリケーションサーバの機能を 使って実装 • Jettyではkeepalive等の扱いがうまくいか なかったので、独自でservletのFilterを使 い処理中セッションをカウントするようにし た
  • 62.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. アプリケーションログについて 62 • ログは標準出力に出す • Podが終了したらファイルは消滅 • マイクロサービスの場合は相関IDは必須
  • 63.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. 相関ID 63 • Spring Cloud Sleuthを使用 • 依存を追加するだけでリクエストで一意な IDをログに出力 • サービス数が多いのでこれがなければ運 用がつらくなる time:2018-03-22T13:52:22.855+09:00 level:INFO trace_id:8f01dc2dc4a7f7b6 span_id:8f01dc2dc4a7f7b6 time:2018-03-22T13:52:23.123+09:00 level:INFO trace_id:8f01dc2dc4a7f7b6 span_id:8f01dc2dc4a7f7b6
  • 64.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. 開発フロー編 64
  • 65.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. k8sの仕組みを活かすためのフロー 65 • Git上でオペレーションが完結するフロー → GitOps • Pull Requestでオペレーション • 環境毎のPull Requestは自動生成 • CI/CDは必須
  • 66.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. 開発フロー 66 Deploy GitHub Docker registry 1. clone 3. プルリクエスト 2. 開発/テスト Concourse CI 7. マージ 4. テスト/ビルド 5. パブリッシュ 6. プルリクエスト develop e2e production ・・・
  • 67.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. Concourseで複雑なパイプラインを実現 67 パイプラインの定義はYAMLで定義しGit管理
  • 68.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. テストの自動化 68 • このフローで安心してリリースするために は、テスト自動化は必須
  • 69.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. テストの自動化 69 • 3種類のテストを実装 • ユニットテスト • クラス単体 • 機能テスト • サービス単体 • E2Eテスト • 全サービス結合 E2E テスト 機能テスト ユニットテスト テストピラミッド
  • 70.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. E2Eテスト 70 • 全サービスを通してのテスト • JUnit • Selenium @Test public void 抽選_01_くじを引く() throws Exception { ログインケース .ログインする(xxxx); 抽選ケース .Action_抽選画面を開く(CAMPAIGN_PATH) .Verify_抽選_抽選画面を表示(xxxx) .Verify_抽選_キャンペーン期間表示(); }
  • 71.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. リリース時間の変化 71 • これまで • パッケージングからサービスアウトなどを含 むリリース完了まで数時間 • システム移行後 • 実働10分程度でデプロイ完了
  • 72.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. その他アーキテクチャ 72
  • 73.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. データベースのスケーリング 73 • k8sによってアプリケーションのスケーリン グはできたが、DBのスケールもしたい → シャーディングの導入
  • 74.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. DBシャーディングについて 74 • DBの水平分割 • EclipseLinkの機能を 使ってDBシャーディング • アノテーションでシャー ディングポリシーを指定 可能 振り分け Policy ID等でノードを決定
  • 75.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. JPAのEntity実装 75 @Entity @Data @Table(name = ”sample") @IdClass(SamplePk.class) @Partitioning( name = ”sampleIdPartitioning", partitioningClass = SampleIdPartitioningPolicy.class) @Partitioned(”sampleIdPartitioning") @AllArgsConstructor @NoArgsConstructor public class SampleJpaEntity { @Id Long sampleId; @Id Integer hogeId; PartitioningPolicyを設定するだけ
  • 76.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. ID生成の問題 76 アプリやDBが分散することでDBサイドでの ID発行(AUTO_INCREMENT)が扱いづらくなった • →アプリサイドでの発行が必要 • →標準規格のUUIDは36byteもあり性能面の 不安 • f48b53b8-fe1e-4670-a19a-650fda31bced
  • 77.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. UUIDは件数が増えると性能が低下 77 MySQLでのINSERT時間
  • 78.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. 64bitの独自ID体系を採用 78 timestamp(41bit) : 現在のunixtime(milliseconds)から、ある時点のunixtimeを引いた値 machine id(12bit) : 生成器ごとに割り当てられたID sequence(10bit) : 生成器ごとに採番するsequence番号 BIGINTに収まりほぼインクリメンタルなので、MySQLで 効率的に扱える timestamp machine id sequence 41bit 12bit 10bit 63bit Twitterのsnowflakeを参考に実装
  • 79.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. 一意になるようにMachine IDを管理 79 各サービス MachineID サービス 定期的にheartbeat machineId=1234
  • 80.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. まとめ 80
  • 81.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. k8sに載せるのに必要なこと 81 • コンテナ • Dockerイメージの作成 • アプリケーション • クラウドネイティブ化 • Liveness probe / Readiness probe • Graceful Shutdown • ログ出力 • 開発フローの対応
  • 82.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. k8sに移行してみて 82 • リリース時間など、運用コストは大幅に削 減できた • 数時間 → 10分 • 負荷についてもスケールできるように • 2000 req/s ↑ • ログが集約され、調査コストも削減できた
  • 83.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. 大変だったところ 83 • 利用技術のスイッチ • パッケージングやCI/CD、利用言語も変更したため • 社内PFとの連携 • IPベースのACLからの変更 • 考え方のスイッチ • 従来のアーキテクチャからCloud Nativeなものへ • まだ、k8sのポテンシャルを十分引き出せていない
  • 84.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. これから 84 • コンテナデザインパターンの活用 • 共通機能を別コンテナに切り出し • サイドカーパターンなど • リリース方法の検討 • カナリアリリース
  • 85.
    Copyright © 2017Yahoo Japan Corporation. All Rights Reserved. 情報技術で 人々のマネーライフの課題を解決する 85