大規模なモバイルゲーム開発を支える仕組みづくりの話

この記事は[DeNA Advent Calendar 2021](https://qiita.com/advent-calendar/2021/dena)の20日目の記事です。

## はじめに

こんにちは。DeNAのエンジニアの今江です。普段はゲームサーバのAPI開発や開発環境の整備、インフラ構築/運用などをやっています。
本記事では、新規タイトルのリリースに向けて準備したもろもろの仕組みについて紹介できればと思います。


### 得られる知見

本記事では以下のような取り組みについて紹介します

- サーバ台数を増やしすぎないためのマスタ管理手法
- スピード感を持った開発フローを実現するためのGitOpsライクなCI/CD
- 属人的なデプロイフローを避けるためのツール開発など

大規模なシステムの開発を、運用効率良くスピード感と使いやすさを意識した仕組み作りを行いました

## ゲーム開発の現場について

ゲーム開発の特徴として「作り直しが多い」と「機能数/コンテンツ量が多い」という特性があります。

そのような特性があるため、作業者が 実装→確認→修正→… という流れを素早く回せることと、コンテンツ量産/レベルデザイン調整を行う場合に作業者だけで作業を完結できるようにすることが大切になります。
そのため、ゲーム開発ではマスタデータと呼ばれる「ゲームのパラメータを設定するデータ」を用意しそれらの作業を行います。例えば、アイテムマスタやエネミーマスタと言ったものがあります。これらのデータを編集することで新しいアイテム追加やボスのパラメータ変更などが出来るイメージです。
![スクリーンショット 2021-12-15 21.56.22.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318777/c559c362-9115-e05d-02d6-92c07aea4ab9.png)
昨今のゲーム開発では大規模化が進んでいることで、チーム規模も大きく、開発期間も数年に及ぶという状態が当たり前になっています。
そのため単純に機能開発を行うだけではなく、ゲーム開発全体がより効率的に進むように、周辺環境の整備を行うことも大切な役割になっています。
昨今の大規模化されたゲーム開発では、環境整備の如何によってゲームの開発効率に大きな影響を与えます。また開発環境が整備されていないと、自分達の開発効率が下がったり、重い運用工数が付き纏ったりします。


## サーバ台数を増やしすぎないためのマスタ管理手法

最初はサーバの運用工数を押さえるために行ったマスタデータ管理方法に関する工夫を紹介したいと思います。

### 開発環境のサーバ数増えがち問題
並行開発が当たり前のソーシャルゲームにおいては、様々な要因により気づいたら、多数の開発環境ができていたりします。
特にゲーム開発においては、チーム規模が大きい(人が多い)、並行開発、グローバル対応(日本語/英語/フランス語/etc.)、 ステークホルダーが多いなど、諸々の事情が踏まえると環境数が多くなる要因が多数あると思います。
単純にサーバ台数が多くなると、それらを運用するサーバエンジニアの負担も上がってしまうので、可能ならサーバ台数は減らしておきたいところです。

```
"開発環境が増える要因 = バージョン×用途×作業者"
```

諸説あるかもしれませんが、経験則的に上記の式で必要な環境数が決まっている気がします。

それそれ解説していきますと、

- バージョン
  - v1.0.0開発、v1.1.0開発、v1.2.0開発、... などの開発ラインに相当するものです(アップデートする単位)
  - 基本的にバージョンが変わるとサーバのコードも変わるので、開発ラインごとにサーバを分ける必要がある
- 用途
  - 開発環境、QA環境、ローカライズ環境、外向け環境、etc.
  - 開発環境とQA環境は基本的には一緒にできない
  - 最低1バージョンごとに2環境は必要(あとはタイトルごとの都合で+αで増える)

そして重要になってくるのは、次の作業者の項目になります。

### 作業者により環境が増えるパターン
作業者毎にサーバを分けないといけないパターンとは? 大きく分けると、3パターンあると思います。

- ① 作業中は環境全体に影響が出るタスク
  - 例えばメンテナンスの実装とか特殊な検証作業など
- ② 動作確認に時間変更が必要なもの
  - サーバの時間を変えられるだけだと不十分、ユーザー毎に時間を変えられる機能が必要
- ③ 作業者毎にマスタを編集出来る環境を用意する
  - これをすると人が増えるとサーバ台数が爆発してしまう。

最後の3番に関しては、ゲーム特有の問題だったりしますが、これが原因でサーバ台数が爆発的に増加しがちな気がします。


### ユーザーごとにマスタデータを切り替えられる機能
そこで作業者毎にマスタ編集する環境を用意しなくても良くするために、「作業者ごとにマスタデータのバージョンを切り替えられる機能」というのを用意しました。

![スクリーンショット 2021-12-13 1.10.50.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318777/3693b521-1e61-d975-41d2-a8e6e903719a.png)

これにより格段に必要なサーバ数が減り、バージョン×用途×”作業者(n→1)” 、チームがスケールしても必要な環境数が増えなくなりました！

### やってみた結果の話

結論、個人でマスタデータと時間をいじれれば個人環境を用意する必要がなくなりました。

この機能を実装したタイトルでは、各マスタ作業者向けに専用の環境を構築する必要がなくなり、同じバージョンのサーバが複数環境あるという状態をなくすことができました。

また、マスタ作業も個人適用→全体適用とやってもらえているので、一定インタフェースやツールを工夫することで仕組みとして根付いてもらうことができました。
例えば、管理ツール上でマスタデータのバージョン一覧を確認できるようにしたり、普段の開発でマスタバージョンという仕組みを目に付くようにして、理解が進むようにすることが大切だったと思います。


## 高速なサーバ開発を支えるGitOpsライクなCI/CDフロー

開発環境のサーバ運用の問題以外にも、開発/本番環境へのデプロイ作業もそれなりに運用工数がかかる作業になりがちです。

- デプロイの手順が複雑だったり、なんやかんや時間がかかるものになってしまっていたりする
- 大規模なシステム=仕組みも複雑になりがちで、コンポーネント数も多い、 単純なモノリシックなサーバ時代と違う
- 今、修正したこのブランチのコードを開発環境に反映したい!、またサーバエンジニア以外でもデプロイ作業 できるようにしておきたい

これらの課題を踏まえて、CI/CDツールを使ってGitOpsライクなデプロイフローを構築してみました。

![スクリーンショット 2021-12-13 1.18.33.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318777/96fb5678-1ddc-4ace-5377-75e7267cf1d3.png)


### GitOps とは？
アプリケーションとインフラの両方のコードをGitを使って管理するというCDの手法です。
アプリケーションコードは馴染み深いと思いますが、それに加えて、インフラの設定ファイル(Infrastructure as Code)もGit上で管理します。
従来の手法に比べてワークフローが全てGitの操作で完結することやGitの機能をフル活用できる (バージョン管理、変更履歴の追跡、権限管理など)

![スクリーンショット 2021-12-13 1.19.51.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318777/9adef6ee-53d0-6a4a-c67a-035f9ef1d89c.png)


### ブランチ運用について

GitOpsでフローを構築していると、ブランチ運用がそのままデプロイフローに繋がることに気がつきました。

チーム全体のブランチ運用が以下のようなルールになっていたため、
![スクリーンショット 2021-12-13 1.21.19.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318777/ba35ef41-78bc-6500-aad6-3541b0946a33.png)
踏まえて、これに従う流れで、サーバのブランチ運用は大きく分けると
「バージョンブランチ」と「開発環境ブランチ」というのを決めました。
![スクリーンショット 2021-12-13 1.22.59.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318777/b348c097-b343-5b6c-73e4-3f29d9e8ef42.png)


### CI/CDフローの構成図
そして、これらのブランチ運用をベースにデプロイフローとしては以下のような構成図になりました。
![スクリーンショット 2021-12-13 1.24.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318777/406f5f42-2207-7f24-50af-1fb56cf0c4c8.png)
デプロイするためのフローが３種類あると思うのですが、それぞれ説明します。

- ① コード修正(開発環境ブランチにpush)
  - サーバエンジニアが作業中のコードをデプロイする時に使う
  - コードをマージするとCI/CDツールが対応する環境に自動的にデプロイしてくれる
  - 普段開発者が慣れ親しんでいるGitHub上の作業だけでデプロイが完結する
- ② 手動デプロイ(jenkinsジョブをポチる)
  - ビルド済みのイメージをデプロイする時に使う、デプロイするたびにビルド待ちはしたくない(QA環境反映など)
  - エンジニア以外の職種がGitのコマンド叩くとかは厳しい、他職種のことを考えるとGitベースのフローだと敬遠される
  - またエンジニアであっても普段触っていないリポジトリを触るというのは一定の障壁がある(クライアントエンジニアがサーバのリポジトリは普通は触らない)
- ③ インフラの設定変更
  - 本番反映時や仕組みを分かっている人が使う
  - 普段は自動化されて意識していない部分を手で直してデプロイ
  - 具体的にはインフラリポジトリで管理されているGKEのYAMLファイルの設定を書き換えてPRをマージする

GitOpsによりサーバのデプロイフローがほぼGitHubの操作で完結するようになったので、効率的なデプロイフローを構築することができました。
ただ一方で、各フェーズ毎の作業者が最も使いやすいツールをインタフェースにすることも大切だったように思います。

## 属人的なデプロイフローを避けるためのツール開発など
サーバのデプロイフロー以外にも、ゲームの場合はアセット更新の作業(マスタデータ、アセットバンドルやWebViewなど)があります。これらに関してできるだけ属人性を下げ、かつ作業負荷が低いデプロイにするためのツール開発を行いました。


### デプロイ職人問題
システムの構成によると思いますが、複雑なデプロイフローになっていたりすると、デプロイ職人が生まれていたりします。
そのような状態になると、本番デプロイ出来るようになるためには修行が必要でかつ、全集中でデプロイしないといけない。ただ作業自体は単純作業なので精神だけすり減る辛い作業になりがちです。
これらの作業は、デプロイの手順書が用意され、「手順書通りに指定されたタスクを順番に指定されたパラメータを入力して叩いていく」 みたいな感じになっている気がします。


### 作業負荷を下げる
- なんたらバージョンというパラメータが複数あるのでこれをjenkinsジョブのパラメータにコピペするのがキツそう。 
- QAした環境にデプロイされているものを必ずデプロイしたい
- ツールでいい感じにサポートして、人間はツールが指示してくるのに従ってボタン押すだけで良い状態にする

![スクリーンショット 2021-12-13 1.34.01.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318777/a4593d4a-fa7d-d0a4-e92b-ff0525d18ccd.png)


### 本番デプロイツールのイメージ

ツールでいい感じにサポートして、人間はツールが指示してくるのに従ってボタン押すだけで良い状態にする

デプロイのセットアップ時に設定項目をポチポチすると、必要な作業手順をツール側が指示してくれます。
![deploy-tool-1.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318777/a7e3fde2-0b57-16f3-4795-8885bf65b107.png)
これは、手順書テンプレのコピペ→デプロイ開始をシステム化 した感じになります。
![deploy-tool-2.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318777/3410708d-565f-7275-b812-5ef7069b7a91.png)
設定した項目とデプロイ元から取得した設定情報を元にツールがデプロイ手順を用意してくれます！
![deploy-tool-3.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318777/cf495a3f-c9e6-468f-05d4-1f52b5f59c66.png)
面倒な 手順書コピペ、デプロイ時の手順の必要性判断、パラメータコピペ作業などを効率化することができました。



### その他あると良かった便利機能

- ユーザーのImport/Export機能
  - 任意の環境からユーザデータを吸い出してくる機能
  - 管理ツールからユーザーデータをZIP形式でエクスポートして任意の環境のユーザーにコピーできる
- WebView用のカスタムタグ機能
  - ユーザーのタイムゾーン&言語に合わせていい感じに時刻表記してくれるタグ、アイテム/キャラの名前/説明をマスタデータの値に変換するタグ、etc.
  - グローバルタイトルならではの辛み軽減 & よくあるヒューマンエラー防止系の機能

```bash
# ユーザーのタイムゾーン&言語に合わせていい感じに時刻表記してくれるタグ
[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 など
```

## まとめ

- マスタ周りの仕組み(環境数を増やしすぎないための仕組み)
  - マスタ切り替え機能により、個人環境を用意する必要がなくなったことで環境数が大幅に増えることを防げた
  - 概念としてそこまで難しいものではないので、学習コストを下げるためにインタフェースを工夫するのが大切だった
- 高速なサーバ開発を支えるGitOpsライクなCI/CDフロー
  - CI/CDツールを活用してGitOpsベースのデプロイフローを構築することができた
  - また各フェーズ毎の作業者が使いやすい様にデプロイ方法を工夫することもできた
- 属人的なデプロイフローを避けるためのツール開発など
  - アセット更新などに必要なデプロイ手順をツール化することで本番デプロイが誰でもできる状態になった
  - 具体的には 手順書コピペ、デプロイ時の手順の必要性判断、パラメータコピペ作業などをなくすことができた


## DeNAより
DeNAでは今年 2021年度新卒・2022年度新卒内定エンジニアの Advent Calendar もあります！
本 Advent Calendar とは違った種類、違った視点での記事をぜひお楽しみください！

▼DeNA 2021年度新卒エンジニア・2022年度新卒内定エンジニアによる Advent Calendar 2021
https://qiita.com/advent-calendar/2021/dena-21x22

また DeNA 公式 Twitter アカウント @DeNAxTech では、 Blog記事だけでなく様々な登壇の資料や動画も発信してます。ぜひフォローして下さい！
Follow @DeNAxTech