Liberent-Dev’s blog

株式会社リベル・エンタテインメントのテックブログです。

ゲームのお知らせページをJamstackで構築した

Jamstack logo

こんにちわ。 システム開発部ネットワーク課のsupercontinueです。

  • ゲーム内お知らせやガチャの情報を扱うWebアプリケーションのサーバ側の仕組みを紹介します。
  • Jamstack を採用して、低コスト・安全 な仕組みができました。

Jamstackとは

特徴

  • 基本的に、CI(継続的インテグレーション。Jenkinsなど)の利用を前提とした設計パターンです。

  • たとえば、Jamstackではない従来型設計の典型であるWordpressに比べると、低コストで安全性も高く、スケール・イン&アウトもしやすくなります

    • なぜ、安全性が高いのか?
      • コンテンツが静的配置され、バックエンドでデータベースに接続する必要がなく、サーバの仕組みが単純になり、セキュリティを担保する必要がある機能が最小限になるからです。
    • なぜ、低コストなのか?
      • 高コストになりがちなデータベースサーバが不要になります。
      • サーバ側でレンダリング(ページの生成)が不要になるため、必要なCPUパワーが少なくなります。
  • ブログやお知らせ・ガチャ・商品情報など、更新頻度があまり高くない、特定のフォーマット(レコード単位の情報)でページが構成される情報のサービスに向いています。

    • 多数ユーザーが高頻度で書き込みを行うようなサービスには向いていません。
  • 複数のシステムで構成され、それぞれは小さいですがスクリプトを記述することが多くなるため、Wordpressのように非エンジニアでも管理できる可用性は失われます。いわゆる「フルスタック・エンジニア」が必要かもしれません。

本案件の構成要素

ヘッドレスCMS

http://takano-plantuml-server.herokuapp.com/svg/SoWkIImgAStDuU8gpixCAqWiIinLoCtFoq_EAChFJLKeAIfDvU9I08E2nEJinFHK1QNm_AAKWgBKuc8bXMe5gAI2WeQpRx0cWlUuUStZvisFcniUDwy2CPesm2HhkP0qAEZgse4KjpzktlEuQV_ZvfbWnavDAuNdsrUydDt6XTiyd7eLh1IUzZSzRrtEvP2QbmBq7G00

  • ヘッドレスCMSは、データを編集・アウトプットする機能を、独立して提供します。
    • ヘッドレスCMSを使う場合、ビルド、レンダリング機能を自前で用意する必要があります

http://takano-plantuml-server.herokuapp.com/svg/SoWkIImgAStDuU8gpixCAqWiIinLoCtFoq_EAChFJLKeAIfDvU9IK2X8JCvEJ4zLK7hSFEDnS_FZvix7pMiUD-rqzWrMKgW6Ab1Gq02oDO6iMXJbJLiVDorvtDpnk77Tu-R9ZvjN0xN2TS157ZVl1Xhsk6dzu-PLZvkd0zNZDWck--NScSzdjJnkRd_SlETnqtwO3h0x57HrxK3cG-KUDyy4CtPgAbWfFD--ukNiDhXA6rrTNVnE0Ufvsj_ql7Kv5m4tGsn5TnV8oYdpdtLCuCBYQ0MGZcTTUv-sxzBaSaZDIm761G00

  • ヘッドレスCMSとして、Cockpit を使いました。
    • Mongodbにデータをアウトプットします。
    • オンプレ環境のDockerで運用しました。

f:id:Liberent-Dev:20211018142838p:plain

cockpitでの編集

  • 複数ユーザーアカウント、ロールで運用できます。

  • collectionsingletonasset の概念があります。

    • collection は複数レコードで構成されます。
      • お知らせ、ヘルプなどで使います。
    • singleton は単一レコードで構成されます。
      • ライセンス表示、利用規約などで使います。
    • どちらも、レコードのフィールドをカスタマイズできます。
      • 日付、時間、テキスト、Wysiwyg、数値、真偽値、オプション、、、
    • asset は基本的に画像ファイルです。

トップページ

f:id:Liberent-Dev:20211018135418p:plain
スクリーンショット:cockpit:トップページ

編集画面の例

f:id:Liberent-Dev:20211018135619p:plain
スクリーンショット:cockpit:記事編集1

f:id:Liberent-Dev:20211018135721p:plain
スクリーンショット:cockpit:記事編集2

アセット画面

f:id:Liberent-Dev:20211018135742p:plain
スクリーンショット:cockpit:アセット一覧

ビルド・スクリプト

  • 下記のように、Cockpitの提供するREST APIを使って、jsonデータを持ってきます。
## お知らせ
if [ "${ENV_VERSION}" = ".prod" ]; then
    INFOMATION_FILTER='{"sort":{"releaseDate":-1,"releaseTime":-1},"filter":{"production":true}}'
else
    INFOMATION_FILTER='{"sort":{"releaseDate":-1,"releaseTime":-1}}'
fi
curl -s ${CMS_API}/collections/get/information?token=${COCKPIT_API_TOKEN} \
 -H "Accept: application/json" -H "Content-type: application/json" \
 -d ${INFOMATION_FILTER} \
 | python -m json.tool > gae/collections/information.json
  • ゲームのレポジトリから、ゲームのマスターデータ(キャラクターやガチャなど)も参照します。

  • 生成する静的データのディレクトリ構成

    • collections 以下には、複数レコードで構成されるjsonデータを置きます。

      例)

      • お知らせ information.json
      • ヘルプ help.json
      • ガチャ gacha.json
    • singletons 以下には、1レコードで構成されるjsonデータを置きます。

      例)

      • ライセンス表記 License.json
      • 利用規約 TermsOfService.json
  • 画像などのファイルは、Cockpitの特定の場所にファイルとして保存されています。 デプロイ時に、CDNに同じファイルをコピーします。

サイト構成

http://takano-plantuml-server.herokuapp.com/svg/SoWkIImgAStDuU8gpixCAqWiIinLoCtFoq_EAChFJLKeAIfDvUBYKW22WiJaxCJqL0KbTqTNXRpyb5Izh68bXMgm70XeP9JavkWeP1NhA2GN5siYn8jJYyfIYu2gaSHUpftvV5RBu-Rsnyrx7ZVjLtYoO_VZnjLPnVbv44Mrg5Owk_YXM8LT-_CfkvyszoCReF6uUThZvfMFcvOzRjhskAabF3KfB3Er_77JUh3eaiTDYnutRtxStA6feAjhXzKBf1g1yAs2bGBSXK_xfptTDvqi0mdx5TbEF5h0eGjsrDJ7JOiVDwy6IW7jVzmy2wni1yZMfWrS3gbvAS040G00

  • html, js, cssは、CDNに置くことも可能ですが、サイズが小さく更新しやすいのでGAEに置きます。
  • 今回は node.js を使いましたが、サーバのスクリプトはとても小さいので、goでもpythonでもなんでもいいと思います。

Webページ

  • ページの開発は riot を使いました。
    • vueのようにメジャーではありませんが、覚えることが少なくて楽で、ビルドも早いしサイズも小さいです。

f:id:Liberent-Dev:20211018153352p:plain

  • ブラウザやWebViewから、お知らせなどのデータを取得するには、フィルタなどを指定して、下記のようにAPIで動的に取得します。
      var url = '/api/collections/get/information';

      fetch(url, {
        method: 'post',
        headers: {
          'Accept': 'application/json',
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({
          filter: {infoType: self.infoType},
          limit: self.limit,
          skip: self.limit * (self.page - 1),
          sort: {releaseDate:-1, releaseTime:-1},
        })
      })
  • サーバ側のスクリプト server.jsは、起動時に静的データを全てメモリに読み込み、リクエストに応じて、データを返します。
    const information = require('./collections/information.json');
    app.post('/api/collections/get/:collection', (req, res) => {
        // 指定した条件で抽出したデータをjsonで返す。
        ...
    app.get('/api/singletons/get/:singletonname', (req, res) => {
        // 指定した条件で抽出したデータをjsonで返す。
        ...

おわりに

  • Jamstackは「コストとセキュリティが気になる」、「スクリプトが得意」なエンジニアに向いています。

  • ブラックボックスがほとんどないので、問題が発生した時、解決できないリスクが少ないし、セキュリティも担保しやすいです。

    • Wordpressで深めの問題が起こったら、ほとんどの人は自力ではどうしようもないのとは対照的です。
  • 導入にあたっては、CMSを使う人やサービスを運用する人の理解や、その人たちへのサポートが必要です。


リベル・エンタテインメントでは、このような最新技術などの取り組みに興味のある方を募集しています。もしご興味を持たれましたら下記サイトにアクセスしてみてください。 https://liberent.co.jp/recruit/