Slide 1

Slide 1 text

Go+GCP+Kubernetesを活用した クラウドネイティブなゲームサーバ開発/運用事例 2022年 03月 17日 (木) Track B 15:00 - 16:00 発表者: 今江 健悟 (ゲーム事業本部 ディベロップメント統括部 技術部 第二グループ)

Slide 2

Slide 2 text

ざっくりの概要 GCP上で Go や Kubernetes, Spannerを活用した開発や運用を、大規模なサービス、チームで実現するにはどうすればよいのか? 本セッションでは、DeNA のクラウドネイティブなゲームサーバの開発と運用の取り組みや体制づくりについて紹介いたします。 ● 社内ゲームサーバー基盤Takasho(Go+GCP)を活用し、Kubernetes上にコンテナベースのゲームサーバを構築した 開発/運用事例を紹介 ● システム構成、組織体制、アーキテクチャ、データ管理周り、どんな開発環境なのか、具体的なコードの話 に関して順を追って説明 が本日のセッションの内容になります! 内容 ● クラウドネイティブなゲームサーバのシステム構成 ● Go や GCP, Kubernetes, Spannerを活用した開発/運用方法について ● ゲームサーバ開発を効率化するための工夫点 (CI/CD、Infrastructure as Codeの実践、各種運用ツールなど) 得られる知見

Slide 3

Slide 3 text

自己紹介 今江 健悟 (Kengo Imae) 株式会社ディー・エヌ・エー ゲーム事業本部 ディベロップメント統括部 技術部 第二グループ 経歴 ● 2017年4月 株式会社ディー・エヌ・エー 入社 (17新卒) ● 2017年6月 運用中タイトルにjoin ○ 運営~新機能開発、新機能チーム リードエンジニア を経験 ● 2019年10月 新規開発中タイトルにjoin ○ Go言語、Google Cloud Platform(GCP)、Kubernetes、etc. ○ E.G.G. Japan(Expert of GCP for Gaming Japan)プログラム 修了 ○ GCP Professional Cloud Architect 認定試験

Slide 4

Slide 4 text

TABLE CONTENTS 導入(ざっくりのシステム構成 / 組織体制) アーキテクチャやサービスの構成要素について 02 01 DBやデータ管理周りの話 03 開発環境について 04 具体的なコードの話 05

Slide 5

Slide 5 text

TABLE CONTENTS 導入(ざっくりのシステム構成 / 組織体制) アーキテクチャやサービスの構成要素について 02 01 DBやデータ管理周りの話 03 開発環境について 04 具体的なコードの話 05

Slide 6

Slide 6 text

ざっくりのシステム構成 ● Go+GCP+Kubernetes構成、コンテナベース ● DeNA内製のTakashoフレームワークをベースにしている ● 様々な共通部門と連携しつつ、ゲームサーバ開発を行っている ● クラウドネイティブ(※)なシステム ※ クラウドネイティブ : はじめからクラウドを利用する想定で設計されたシステムのこと、 従来のシステムと区別する際にクラウドネイティブと呼ばれている。

Slide 7

Slide 7 text

Takashoについて ● DeNA内製のWebサーバフレームワーク(Go言語、ゲームサーバの共通基盤システム) ● ゲームサーバ構築に必要な機能を提供しつつ、タイトルごとに組み込んで自由にできる高い拡張性がある ● 加えて、Takasho環境を構築するためのインフラツールなども提供している developモード serviceモード ● TakashoをWebフレームワークとして利用するモード ● サーバ機能の開発と運用は基本的にタイトルチームが行う ● 自由度が高いが、タイトル側にサーバエンジニアが必要 今回はこっち ● Takashoをゲームサーバとして利用するモード ● サーバ機能の開発と運用は基本的にTakashoチームが行う ● タイトル独自の機能開発もTakashoチームが開発 ● タイトル側にサーバの開発・運用が できるメンバーは必要ない ● 開発工数やスケジュールなどはTakashoチーム に依存する Gopherの原作者はRenee Frenchさんです。

Slide 8

Slide 8 text

Takashoについて developモード serviceモード ● TakashoをWebフレームワークとして利用するモード ● サーバ機能の開発と運用は基本的にタイトルチームが行う ● 自由度が高いが、タイトル側にサーバエンジニアが必要 ● Takashoをゲームサーバとして利用するモード ● サーバ機能の開発と運用は基本的にTakashoチームが行う ● タイトル独自の機能開発もTakashoチームが開発 ● タイトル側にサーバの開発・運用ができるメンバーは必要ない ● 開発工数やスケジュールなどはTakashoチームに依存する 他職種 サーバ 他職種 基本的に意思決定がタイトル内で完結する 内製タイトル 協働タイトル Takashoチーム 協働タイトル 協働タイトル 協働タイトル 複数のタイトルを同時開発・運用するのに適している

Slide 9

Slide 9 text

タイトルチームと共通部門(専門チーム) ● ゲーム開発は幅広い知識が求められるためタイトル外に強い味方がいてサポートしてもらえる体制になっている ● Takasho, LCX, SWET, IRIS, Sharin’チームとそれぞれの専門チームに困ったときに相談してる 本発表の内容も各専門チームのツール・ノウハウ提供のお陰で実現出来てるものが数多くあります! タイトル サーバ、インフラ MBaaS CI/CD, テスト MOサーバ クライアント Takasho LCX SWET IRIS Sharin’
 … 良い感じに 組み合わせる 相談 相談 : ツール・ノウハウ提供 : 専門領域での相談

Slide 10

Slide 10 text

TABLE CONTENTS 導入(ざっくりのシステム構成 / 組織体制) アーキテクチャやサービスの構成要素について 02 01 DBやデータ管理周りの話 03 開発環境について 04 具体的なコードの話 05

Slide 11

Slide 11 text

本セッションのアーキテクチャについて 全体的なシステム構成 1 ドメイン駆動設計(DDD)とクリーンアーキテクチャをベースにした設計思想 使用している技術 2 コンテナ(Docker)ベースのシステムでKubernetes上で構築されている Go言語、Protocol Buffers, Google Cloud Platform(GCP), CircleCI, etc. サービスの構成要素 3 APIサーバ、GMTool(管理ツール)、 バトルサーバ(MOサーバ)、Oyakata(マスタ管理)、etc. Takashoが提供している機能をベースに、タイトル独自に拡張/追加している要素がある

Slide 12

Slide 12 text

ドメイン駆動設計(DDD)とクリーンアーキテクチャ ● model, repository, service, usecase, endpoint + α の ディレクトリ/クラス構成 ● クラス間の依存が整理しやすい、関連するクラスを探しやすい、データレイヤを置き換えやすい、など 基本的には1Endpoint = 1トランザクション でAPIを実装しています。複数のUse caseを組み合わせる必要があるAPIは例外。

Slide 13

Slide 13 text

ドメイン駆動設計(DDD)とクリーンアーキテクチャ ● model, repository, service, usecase, endpoint + α の ディレクトリ/クラス構成 ● クラス間の依存が整理しやすい、関連するクラスを探しやすい、データレイヤを置き換えやすい、など 疎結合なコードになり、依存を作っているところも把握しやすい エディタでFindする関連クラスがまとめて出てくる

Slide 14

Slide 14 text

使用している技術 ● Go+GCP+Kubernetesをベースに、クラウドネイティブな技術スタックを使っている ※クラウドネイティブ: はじめからクラウドを利用する想定で設計されたシステムのこと、従来のシステムと区別する際にクラウドネイティブと呼ばれている。 言語 ● サーバ : Takashoフレームワーク(Go言語) ● クライアント Unity (C#) ● Protocol buffers, gRPC ● REST API (JSON) 通信プロトコル CI/CD、管理ツール ● CircleCI, Jenkins, ArgoCD ● Vue.js (JavaScript) インフラ ● コンテナ技術 Docker, Kubernetes ● クラウドサービス (GCP) Google Kubernetes Engine(GKE), Cloud Spanner, Cloud Storage, Cloud MemoryStore, Cloud Pub/Sub, Operations(Cloud Logging & Monitoring), Cloud Load Balancing, Cloud DNS, etc. ● Infrastructure as code Terraform This slide is not affiliated with or otherwise sponsored by CNCF.

Slide 15

Slide 15 text

Google Kubernetes Engine (GKE) ● GCPのマネージド Kubernetes サービス、自前でKubernetsクラスタを構築するのは大変。 ● プロダクションでのDocker(コンテナ)の運用を考えるとオーケストレーションツールというのが必須 コンテナ便利なので使いたい 簡単にマシン上にコンテナを 立ち上げられる/増やせる マシン マシン コンテナ運用での考慮事項 リソース管理 スケジューリング デプロイ 死活監視 障害時の復旧 マシン マシン もう限界や… 暇や… なぜKubernetesが必要? リソース管理 オートスケーリング セルフヒーリング etc. 排除 マシン マシン 助かった 神 全部自分がやるわ Kubernetesを利用することで、コンテナ運用に必要な仕組みを自前で構築せずとも利用できるようになる!

Slide 16

Slide 16 text

サービスの構成要素 ● APIサーバ、管理ツール、WebView、マスタ管理、MBaaSなどが登場します。 ● ゲーム系のサーバは全てGKE上で動いています。基本的に gRPC or REST で通信しています。 This slide is not affiliated with or otherwise sponsored by CNCF.

Slide 17

Slide 17 text

サービスの構成要素(APIサーバ) ● APIサーバ、管理ツール、WebView、マスタ管理、MBaaSなどが登場します。 ● ゲーム系のサーバは全てGKE上で動いています。基本的に gRPC or REST で通信しています。 ゲームAPI ❶ Player API ❷ Support API ❸ Admin API ● メインのAPIサーバ ○ アプリ側と通信してゲームロジックを実行するAPIサーバ ○ 主にプレイヤーに対する操作を行うPodです ○ gRPCで通信する ● サブのAPIサーバ ○ WebViewやMBaaSの課金処理のコールバックに利用するAPIサーバ ○ こちらはREST APIを実装してるPodです ● 開発者用のAPIサーバ ○ マスタデータ投入などで使われる開発用のAPIサーバ ○ 専用のCLIを利用してgRPCで通信する、主にJenkinsなどから実行 This slide is not affiliated with or otherwise sponsored by CNCF.

Slide 18

Slide 18 text

サービスの構成要素(その他サーバ) ● APIサーバ、管理ツール、WebView、マスタ管理、MBaaSなどが登場します。 ● ゲーム系のサーバは全てGKE上で動いています。基本的に gRPC or REST で通信しています。 ❺ LCX (MBaaS) ● 内製のモバイル向け共通基盤システム(MBaaS) ○ 複数のゲームタイトルに対して共通機能を提供するサービスです。 ○ 認証機能、アプリ内決済をハンドリングする課金機能、PUSH通知などを提供 ○ Web API と コールバック通知を利用してゲームサーバ側と連携している ❻ マスタ管理(Oyakata) ● マスタデータ管理の共通基盤システム ○ Oyakata: 内製のモバイルゲームの運用に特化したマスタデータ管理用ツール 大規模モバイルゲーム運用におけるマスタデータ管理事例, CEDEC2019, 人西 聖樹, 2019/09/06 ❹ 管理ツール ● 開発者用の管理ツール ○ ユーザー情報の閲覧/アイテム補填などを提供するWebアプリ ○ 管理ツール上からサーバの設定変更やメンテナンス設定ができる This slide is not affiliated with or otherwise sponsored by CNCF.

Slide 19

Slide 19 text

● APIサーバ、管理ツール、WebView、マスタ管理、MBaaSなどが登場します。 ● ゲーム系のサーバは全てGKE上で動いています。基本的に gRPC or REST で通信しています。 サービスの構成要素(データ管理) ❼ Spanner ❽ MemoryStore(Redis) ❾ Google Cloud Storage ● ゲームデータを管理しているデータベース ○ Spanner: GCPのグローバル規模のマネージドRDBサービス ○ 基本的に全てのデータがSpannerで管理されているのでタイトルの心臓部 ○ 詳細な説明は、データ管理の章で説明します。 ● マスタデータのキャッシュなどを管理している Key-Value ストア ○ Memorystore for Redis : GCPのフルマネージド Redis サービス ○ マスタデータや新着通知などを管理して、DBへの負荷軽減を行なっている ● アセット配信などに使用しているストレージサービス ○ アプリで使用するマスタデータ、アセットバンドル、WebViewなどを配信 ○ CDNのオリジンサーバに指定して、アプリにアセット配信を行っている This slide is not affiliated with or otherwise sponsored by CNCF.

Slide 20

Slide 20 text

TABLE CONTENTS 導入(ざっくりのシステム構成 / 組織体制) アーキテクチャやサービスの構成要素について 02 01 DBやデータ管理周りの話 03 開発環境について 04 具体的なコードの話 05

Slide 21

Slide 21 text

Cloud Spanner GCPのグローバル規模のマネージドRDBサービス 1 プライマリーが複数あるプライマリー/レプリカ構成のMySQLのイメージ、NewSQLと呼ばれている種類のもの NewSQL: 新しい形態のSQLデータベースで、既存のRDBと比較して水平スケーリング・分散アーキテクチャなどの特徴を持つ RDBかつNoSQLの特性を備える 2 Spannerの実体はNoSQLで出来ている、RDBの皮を被ったNoSQL NoSQL(スケール)とRDB(スキーマ/強整合性/SQLクエリ)の特性を備えたすごいやつ、代わりにお値段が高い※1 シャーディングの複雑さを解消してくれる 3 これまではDBの負荷対策として、アプリ側でユーザー単位で保存するDBの割り振り等のロジックを実装してた このシャーディングを自動でやってくれるため、テーブルの設計さえ適切に行えばアプリ側の処理が不要になる Cloud Spanner ※1 現在は 1ノード(1,000 PU)以下のインスタンスのサイズ変更ができるようになったので更にお安くできます(PU: 処理ユニット 100PU単位の調整が可能)

Slide 22

Slide 22 text

4種類のデータタイプ ユーザーデータ ● ゲーム内で可変のデータを保存 ○ 例) ユーザーのクエスト進捗、装備の強化・ 進化状態、アイテムの個数など マスタデータ ● ゲーム内で不変のデータを保存 ○ 例) クエストの報酬設定、ボスのステータス、 装備のレアリティなど 翻訳データ ● 多言語対応を行うための言語データ ○ マスタデータのIDに対応して、JP, EN, CN, … で各言語用のカラムを持つ ○ 例1) お知らせID: 1000 → 各言語のHTML ○ 例2) 装備ID: 1001000 → 各装備の装備名 その他のデータ ● 前述の3種類に含まれないデータ ○ 例) サーバの設定情報など ● ざっくり分けると、4種類のデータをSpanner上で管理しています。

Slide 23

Slide 23 text

Cloud Spannerでのデータの管理方法 ● 基本的なテーブル設計はユーザーデータ(User~s)とマスタデータ(~Masters)に分かれる ● ユーザーデータは「ユーザーのステータスなど」、マスタデータは「ゲームで固定のパラメータ情報など」 ユーザーデータ マスタデータ

Slide 24

Slide 24 text

ユーザーデータ: 分散処理とUUIDについて ● Spannerは分散DBなので、データが分散されて管理されている。 ● PKはデータの性質に関係なく分散させておくのがベストプラクティスなのでUUIDv4を使ってる Root Node Split A ~ C D ~ G H ~ M N ~ S T ~ Z 例えばAのデータが たくさん書き込まれると こんな感じに内部でよしなにやってくれるが、できるだけPKの範囲をバラけさせるためにUUIDを使ってる とはいえ、UUIDを使っていても偏りは発生することがある Node Split AA~AH AI~AZ こんな感じにSplitが分割される B ~ G

Slide 25

Slide 25 text

インターリーブの話 ● Spannerにはインターリーブという、テーブル間の親子関係を作る仕組みがあります。 Node Split C ~ D E ~ F A ~ B ユーザーA1 ユーザーA2 ユーザーA3 : UserId ItemId Num A1 Item1 1 A1 Item2 5 A1 Item3 3 UserId EquipmentId Level A1 EquipmentId1 10 A1 EquipmentId2 2 ■ アイテム情報 ■ 装備情報 ● インターリーブにより、関連するテーブルのレコードが 「物理的に同じ場所(=Split)に配置される」ようになります ● 同じ場所に必要なものがあるのでパフォーマンスも良くなる CREATE TABLE Users ( UserId STRING(36) NOT NULL, ) PRIMARY KEY(UserId); CREATE TABLE UserEquipments ( UserId STRING(36) NOT NULL, ID STRING(36) NOT NULL, EquipmentId INT64 NOT NULL, ) PRIMARY KEY(UserId, ID), INTERLEAVE IN PARENT Users ON DELETE CASCADE; DDLのサンプル

Slide 26

Slide 26 text

マスタデータ: MasterRevisionを使ったデータ管理 ● マスタデータには「マスタリビジョン(MasterRevision)」という概念がある ● 名前の通り、マスタデータのバージョニングを行なっている仕組み、有効なマスタの切り替えもできる 間に他のテーブルも あるが一旦省略 ● Spannerの同時insert数の制限があるので MasterRevisionごとに分けている ● MasterRevisionを使うことでユーザーごと に反映するマスタを切り替えたりもできる 補足説明

Slide 27

Slide 27 text

ミューテーション の話 ● ミューテーションは、Spanner によってアトミックに適用される一連の操作(挿入、更新、削除)を表す単位 ● マスタデータをバージョン分けしている理由の一つに、このミューテーション制限によるものがあります。 20,000 ミューテーション 問題があるので、小分けにしてレコードを追加する必要がある テーブルのカラム数やINDEX、DB操作の種類によって算出方法が変わるので注意 マスタリビジョンA マスタリビジョンB マスタ投入 マスタリビジョンA マスタリビジョンB マスタ投入 制限超えないよう に頑張って操作する うむ 参照 切り替えた おわった “
 “
 https://cloud.google.com/spanner/docs/dml-versus-mutations#what_are_mutations_

Slide 28

Slide 28 text

内製ツール(マスタデータ、アセット) ● マスタデータは「Oyakata※1」、アセット配信は「Aladin/AssetFetcher/Abdool※2」というツールを使用 ● サーバ側での使い方としては Oyakata→DB、Aladin→CDNにデータを同期させている感じです マスタデータ管理ツール「Oyakata」 アセットバンドルの配信フロー ※1 大規模モバイルゲーム運用におけるマスタデータ管理事例, CEDEC2019, 人西 聖樹, 2019/09/06 ※2 モバイルゲームを支えるリソース管理基盤のつくりかた, DeNA TechCon 2021, 大竹 悠人, 2021/03/03

Slide 29

Slide 29 text

TABLE CONTENTS 導入(ざっくりのシステム構成 / 組織体制) アーキテクチャやサービスの構成要素について 02 01 DBやデータ管理周りの話 03 開発環境について 04 具体的なコードの話 05

Slide 30

Slide 30 text

チームもシステムも大規模 ● チーム人数が多い ● コンポーネント数も多い ● 開発ラインも多い もろもろ整備されていないとキツい “
 “
 特徴

Slide 31

Slide 31 text

開発環境のための取り組み ● 大規模なシステムの開発を、運用効率良く行うためにやったこと ● 開発サーバの管理 ○ 開発環境を増やしすぎないための取り組み ● 開発フロー ○ CI/CDツールを使ったGitOpsベースのデプロイフロー ○ Infrastructure as Code の実践 ● 開発ツール系 ○ ゲーム用の管理ツール(Vue.js)の紹介 ○ 属人的なデプロイフローを避けるためのツール開発 ○ その他便利機能に関して (ユーザーインポートやカスタムタグ機能など ) やったこと 3 1 2

Slide 32

Slide 32 text

開発環境のサーバ群 ● 基本的に開発環境は複数のサーバが必要で、大規模なチームになると必要なサーバ台数は相当数になります ● 今回の例では 本番環境 > staging環境 > QA環境 > sandbox環境 と その他専用環境を構築しています 安定 sandbox-01 sandbox-02 ・・・ qa-01 qa-02 ・・・ 開発者は作業内容に 応じて環境を切り替える 本番環境 staging 専用環境

Slide 33

Slide 33 text

開発環境のサーバ数増えがち問題 ● 開発環境は増えがち、並行開発が当たり前のモバイルゲームにおいては無尽蔵に開発環境が増えていく ● ゲーム開発の場合、人が多い、並行開発、グローバルタイトル(日本語/英語/フランス語/etc.)、ステーク ホルダーが多いなど、諸々の事情が踏まえると環境数が多くなる要因が多数ある 開発環境が増える要因 = バージョン×用途×作業者 “
 “
 諸説あるかもしれませんが、上記の式で必要な環境数が決まるかと思います

Slide 34

Slide 34 text

開発環境が増える要因 = バージョン×用途×作業者 ● 基本的にバージョンが変わるとサーバのコードも変わる ● masterブランチ一本運用だと未来の機能が入るので厳しい “
 “
 バージョン 用途 作業者 要注意!! ➔ v1.0.0開発、v1.1.0開発、v1.2.0開発、… ● 開発環境とQA環境は一緒にできない ● 最低1バージョンごとに2環境は必要 ● あとはタイトルごとの都合で+αで増える ➔ → 開発環境、QA環境、LQA環境、専用環境、etc. ➔ → 作業者毎にサーバを分けないといけないパターンとは? 大きく分けると、経験則的に3パターン。 1. 作業中は環境全体に影響が出るタスク a. 例えばメンテナンスの実装とか特殊な検証作業など 2. 動作確認に時間変更が必要なもの a. サーバの時間を変えられるだけだと不十分 b. ユーザー毎に時間を変えられる機能が必要 3. 作業者毎にマスタ編集用の環境を用意する a. これをすると人が増えると サーバ台数が爆発してしまう。 3 1 2

Slide 35

Slide 35 text

ユーザーごとにマスタデータを切り替えられる機能 ● 作業者毎にマスタ編集する環境を用意しなくても良くするために作った機能、格段に必要なサーバ数が減る ● バージョン×用途×作業者(n→1) 、チームがスケールしても必要な環境数が増えなくなった!! 1. 複数人がマスタデータを編集して開発環境に反映する 2. 自分の変更が他の人に影響するので個人環境を用意する 必要があった 3. 開発人数が多くなるのと無限にサーバが増えるので辛い 従来の方式 1. マスタリビジョンを更新せず、自分用のマスタデータを登録できる 2. 各ユーザーごとに有効にするマスタリビジョンを設定できる 3. 開発人数が増えても一つのサーバでマスタデータを開発できる 今回の方式 sandbox Aさん環境 Bさん環境 … … 同じサーバ は無理 人が増える : マスタデータ編集のための個人環境はいらない

Slide 36

Slide 36 text

やってみた結果の話 ● 必要なサーバ台数は格段に減ったが、それでも開発環境が30個ほど必要になった ● マスタを切り替えるための仕組みが、他の便利機能の土台になっていたりする (例えばアセット類とか)。 ● ローカルサーバのマスタデータを編集するための仕組みが必要 (DB書き換える?ツール用意する?工数かかる) ● ローカルサーバがバグったときに、サーバエンジニアが原因調査 するのが辛い ● サーバ更新があるときに各作業者のローカルサーバを更新させる フローと仕組みが必要 マスタ切り替え以外の案 ● ユーザーIDを打ち込むのがしんどいのでメールアドレスで切り替えられるようにした ● ROMからデバッグ機能でバージョン一覧表示と切り替え機能を作ってもらった ● 管理ツール上からマスターバージョン一覧が 見れるようになっている、など この仕組み自体の低難易度化の方法 作業者毎にローカルサーバを立ててもらう案 個人用サーバ方式よりは仕組みが難しい問題 プランナーにも個人適用→全体適用とやってもらえているので仕組みとしては根付いている 概念としてそこまで難しいものではないので、学習コストを下げるためにインタフェースを工夫するのが大切だった → 「個人でマスタと時間をいじれれば個人環境を用意する必要がなくなった」

Slide 37

Slide 37 text

GMTool: ゲーム用の管理ツール ● 管理ツールはフロントをVue.js、サーバ 側はTakashoの枠組みで作っています ● この管理ツール上に、開発環境向けの便利機能の開発などを行なっています ユーザー検索 ユーザーデータ一覧

Slide 38

Slide 38 text

マスタ切り替え関連の周辺ツール ● 管理ツール上からマスターデータがバージョン管理されていることが確認できる & 切り替えボタン ● マスタデータを投入するための Jenkinsジョブに 全体反映 or 個人反映用のフラグがある マスタデータのバージョン一覧が見れる 全体反映のON/OFFフラグ

Slide 39

Slide 39 text

開発環境へのデプロイ ● デプロイの手順が複雑だったり、なんやかんや時間がかかるものだったりする (リリース手順書) ● 大規模なシステム=仕組みも複雑になりがちで、コンポーネント数も多い、 単純なモノリシックなサーバ時代と違う ● 今修正したこのブランチのコードを開発環境に反映したい!、またサーバエンジニア以外でもデプロイ作業 できるようにしておきたい CI/CDツールを使ってGitOpsライクなデプロイフローを構築 “
 “
 CIツール CDツール バージョン管理 This slide is not affiliated with or otherwise sponsored by CNCF.

Slide 40

Slide 40 text

GitOps ● GitHubを使用してアプリケーションとインフラの構成を宣言的に管理するためのCI/CDの手法です。 ● Gitリポジトリを信頼できる情報源としてCIとCDの責任分界点を明確にしているという特徴があります ○ 似た手法のCIOpsと比較すると CIOps: push型、GitOps: pull型 で仕組みの違いがある ○ またCIOpsの場合は、CIツールにデプロイに必要な権限を持たせる必要がある ● これらの手法はワークフローが全てGitの操作で完結することやGitの機能をフル活用できる(バージョン管 理、変更履歴の追跡、権限管理など)というメリットがあります - GitHub - テスト - CI/CD - ビルド デプロイ ▼ - 環境 - Git操作 差分検知 アプリケーションコード インフラ設定 - Image Repo - 更新

Slide 41

Slide 41 text

ゲームサーバのブランチ運用 ● チーム全体のブランチ運用の話 GitHubを軸にフローを構築するので ブランチ運用がそのままデプロイフローに繋がる 1. X:メジャーアップデートバージョン。周年の大型アップデート時に数字を上げるイメージ 2. YY:クライアントアップデートで数字を上げる 3. ZZ:不具合修正やデータアップデート時に数字を上げる verXYYZZ (例: ver10000) 踏まえて、サーバのブランチ運用 ● これに従う流れで、サーバのブランチ運用は大きく分けると「バージョンブランチ」と「開発環境ブランチ」というのを決めました。 1. リリース予定のバージョン用のブランチ 2. このブランチにPRがマージされると、そのバージョン用 のイメージのビルドが行われます。 バージョンブランチ 1. 開発環境に紐づくブランチ、開発環境に作業中の コードをデプロイするためのブランチです。 2. このブランチに修正をマージ & プッシュするとその 時点のコードが対応する環境にデプロイされます。 開発環境ブランチ 例: ver10100 例: sandbox-01 ver10100 → ver10110 → ver10111 → ver10200 → ・・・
 リリース データ 更新 不具合 修正 アプデ

Slide 42

Slide 42 text

ゲームサーバのデプロイフロー 1. CircleCI経由 (開発環境ブランチにpush) 2. Jenkinsジョブ経由 (ボタンポチるだけ) 3. GitHub経由 (インフラの設定変更) Jenkinsジョブ ポチる 開発環境ブランチにpush インフラの設定変更 ● 開発を続けていて3通りあるのが良さそうとなった 開発者が作業用のコードをデプロイするときに使う ● コードをマージするとCI/CDツールが対応する 環境に自動的にデプロイしてくれる ● 普段開発者が慣れ親しんでいるGitHub上の作業 だけでデプロイが完結する ビルド済みのイメージをデプロイする時に使う ● デプロイするたびにビルド待ちはしたくない(QA環境反映など) ● エンジニア以外の職種がGitのコマンド叩くは厳しい 本番反映時や仕組みを分かっている人が使う ● 普段は自動化されて意識していない部分を 手で直してデプロイ ● 具体的にはインフラリポジトリで管理されて いるGKEのYAMLファイルの設定を書き換えて PRをマージする

Slide 43

Slide 43 text

ゲームサーバのデプロイフロー ● 3種類のデプロイフローをメンテしてるのではなく、ユースケースに合わせてショートカットを用意してるイメージです アプリ CI Pipeline Image Repo インフラ CI Pipeline 環境 コード修正 手動デプロイ インフラ設定変更 Build デプロイ (いろんな職種向け) (分かってる人向け) (サーバエンジニア向け) 各フェーズ毎の作業者が最も使いやすいツールをインタフェースにしてる

Slide 44

Slide 44 text

デプロイ職人問題 ● 複雑なデプロイフロー、デプロイ職人問題、本番デプロイ出来るようになるためには修行が必要、 全集中でデプロイしないといけない。 ● この状態になっているとデプロイ出来る様になる人材がなかなか育たないし、リリース時の忙しいタイミング で自分しかデプロイ出来ない状態だとやばい。 ● 大体のデプロイが手順書通りに指定されたjenkinsジョブを順番に指定されたパラメータを入力して叩いていく 感じになる 全集中!! うっす デプロイへの道 は長いぞ 順番ミスった?

Slide 45

Slide 45 text

本番デプロイを良い感じにしたい ● なんたらバージョンというパラメータも複数あるのでこれをjenkinsジョブのパラメータにコピペするのもキツそう。 ● QAした環境にデプロイされているものを必ずデプロイしたい ● ツールでいい感じにサポートして、人間はツールが指示してくるのに従ってボタン押すだけで良い状態にする あのQA環境に サインオフ出しました 準備したで おう なんたらバージョンが多い 環境指定でデプロイしたい 機械が良い感じにして欲しい

Slide 46

Slide 46 text

デプロイのセットアップの時に項目をポチポチする 本番デプロイツールの話 ● ツールで良い感じにサポートして、人間はツールが指示してくるのに従ってボタン押すだけで良い状態にする 必要な作業手順をツール側が指示してくれる 準備したで おう

Slide 47

Slide 47 text

本番デプロイツールの話 ● 手順書テンプレのコピペ→デプロイ開始をシステム化 左メニューが出てくるので必要な項目を項目を選択していく ポチる ポチる デプロイ元の環境を選ぶ デプロイ元の 設定情報が取れる

Slide 48

Slide 48 text

後はこの手順を上からやるだけ! 面倒なJenkinsジョブへのパラメータのコピペも必要なし 本番デプロイツールの話 ● 設定した項目とデプロイ元から取得した設定情報を元にツールがデプロイ手順を用意してくれる! このリンクを押すとパラメータが セットされた状態で開く

Slide 49

Slide 49 text

その他の便利機能 ● ユーザーのImport/Export機能 ○ 任意の環境からユーザデータ吸い出してくる機能 ○ GMToolからユーザーデータをZIP形式でエクスポートして任意の環境のユーザーにコピーできる ● WebView用のカスタムタグ機能 ○ スケジュールIDを開催期間表示に変換するタグ、アイテム/キャラの名前/説明をマスタデータの値に 変換するタグ、ユーザーのタイムゾーン&言語に合わせていい感じに時刻表記してくれるタグ、etc. ○ グローバルタイトルならではの辛み軽減 & よくあるヒューマンエラー防止系の機能 [Date:DateTime format=g date=2021/4/7 time=3:00] → 2021/04/07 12:00 → 4/7/2021 at 3:00 a.m. → 07/04/2021 à 05:00 など [Label:ItemName id=11100001] → 普通の剣 → Common Sword など

Slide 50

Slide 50 text

TABLE CONTENTS 導入(ざっくりのシステム構成 / 組織体制) アーキテクチャやサービスの構成要素について 02 01 DBやデータ管理周りの話 03 開発環境について 04 具体的なコードの話 05

Slide 51

Slide 51 text

gRPCによるAPIの追加方法 ● protobufのスキーマファイルを元に様々なコードが自動生成される、ゲームロジックの実装に集中できる ● クリーンアーキテクチャだとファイル数が多くなるので model, repository 辺りの必要なものが揃う $ make schemacompile_server takasho_tool がサーバ側の必要なファイル群を作ってくれる ← 青枠のところが   自動生成される

Slide 52

Slide 52 text

自動生成コードの例 ● マスタデータを簡単に取得するための仕組み (master_manager.Instance().GetXxxx…) ● クライアント-サーバ側での定数の同期(Enumクラスの自動生成) ● ~Enumで終わるマスタ名はEnumテーブルとして扱われる ● 該当のテーブルから定数クラスを自動生成している

Slide 53

Slide 53 text

Storedデータ: 更新された差分だけレスポンスする仕組み ● どのAPIにもStoredデータというのが含まれていて、ユーザーデータの更新差分だけをクライアントに返している ● 毎回全てのデータを返すと通信量に問題が出ることと、クライアント-サーバ間の不整合なども防ぎやすい ゲーム側で状態を変化させた時 ↑ 更新があったらフラグを立てておくと そのタイプだけレスポンスに含まれる ← これ

Slide 54

Slide 54 text

トランザクション関連のコード(シャーディングからの開放) ● Spannerのおかげもあり、開発者が普段意識しないといけないものはRW/ROトランザクションくらい ● 接続先を意識する/レプリ遅延の考慮(例: 最新のデータが必要なのでprimaryに問い合わせる)などから開放 Rwの場合 Roの場合 「なんで、ここだけprimaryからデータ取ってきてるんでしたっけ?」みたいなことが無くなる

Slide 55

Slide 55 text

Spannerの負荷試験や運用を通しての注意点 RWトランザクションは比較的Abortしやすい ● しかもAbortすると全体的に負荷がかかって、他のトランザクションもAbortし始める ● RWトランザクションで他ユーザーがアクセスするテーブルはSELECTしてはならない ● 誰か一人が書き込んで、他の人が読み込むテーブルはROトランザクションで読み込む ● 同じレコードを複数人が更新するのは厳しいので、冗長でも自分専用のレコードに書き込む 空SELECTは重いので基本的には避ける ● MySQLとかでよくある SELECTして無ければINSERT、あったらUPDATE はあまりやらないほうが良い ● 事前に全件取得しておいてコード上で存在確認する(空SELECTの発生数を抑える対処法) ● 全件SELECTが空SELECTになるケースが高いものは初期レコードを入れておく ← 例えば、ギルド的な機能は  コード上で存在確認できるように  初期レコードを登録しておく方式を取ってます // … ← (省略) 1 2

Slide 56

Slide 56 text

Spannerの負荷試験や運用を通しての注意点 SpannerのCPU負荷は60%超えるようだと危険 ● 80%超えたらエラー率がかなり上がるので注意。Spannerのドキュメントにも65%以下にすることが推奨されている ● 高 CPU 使用率に関するアラート: https://cloud.google.com/spanner/docs/cpu-utilization#recommended-max インデックスも出来るだけ貼らない ● 基本的にはRWトランザクションはインターリーブしたテーブルだけを扱う ● インデックスで検索するときもROトランザクションでやらないとAbortしやすい ● ユーザーを横断した検索は苦手、管理ツールでもSpannerに対して主キー以外の検索が厳しい IN句もあまり使わない方が良い ● 主キーでINで5件取ってくるより、100件全件取得したほうが負荷が軽かったりする※1 ● また、クエリパラメータの上限950個にも注意(APIの入力パラメータに上限を設ける、将来のデータ増の考慮) ● クエリに関する上限: https://cloud.google.com/spanner/quotas#query_limits 3 4 5 ※1 ただし、レコード数が膨大になると逆転する可能性がありえます、現状の想定は数百件オーダーです。

Slide 57

Slide 57 text

まとめ ● Takashoを使ったdevelopモードのシステム、専門チームと連携しつつ大規模システムを作ってる 導入(ざっくりのシステム構成 / 組織体制) アーキテクチャやサービスの構成要素について DBやデータ管理周りの話 開発環境について 具体的なコードの話 01 02 ● DDD+クリーンアーキテクチャをベースに、Go+GCP+Kubernetsを使ったコンテナベースの構成 03 04 05 ● Spanner: シャーディング不要でどこまでもスケールするRDB、その特性を活かしたデータ管理など ● Spannerを使ったマスタデータの並行開発の工夫、GitOpsやIasCの実践、便利ツールの紹介 ● 自動生成を前提にしたAPI開発、独自の自動生成コードや運用ノウハウを紹介しました