Kubernetes Engine での専用ゲームサーバーの実行

サーバー アプリケーションをコンテナ イメージとしてパッケージ化することが主流になってきています。多くのゲーム会社は、コンテナを使用して VM の利用率を上げようとしています。また、コンテナが提供する独立した実行環境にも注目しています。しかし、関心は高いものの、何から始めればよいのかわからないというゲーム会社も少なくありません。本番環境の専用ゲームサーバーをデプロイするには、コンテナ オーケストレーション フレームワークの Kubernetes が最適です。

このチュートリアルでは、リアルタイムかつセッション ベースのマルチプレーヤー型専用ゲームサーバーGoogle Kubernetes Engine 上で実行するための拡張可能なアーキテクチャについて説明します。このアーキテクチャでは、スケーリング マネージャー プロセスが必要に応じて仮想マシン インスタンスを自動的に開始または停止します。Kubernetes ノードのマシン構成はマネージド インスタンス グループによって自動的に処理されます。

このチュートリアルでは、説明と実装を簡単にするため、単純な構造のオンライン ゲームを使って説明を進めます。より複雑な構造が必要になる個所は、その都度、指摘していきます。

目標

  • Docker を使用して、人気のあるオープンソースの専用ゲームサーバー(DGS)である OpenArena のコンテナ イメージを Linux 上に作成します。このコンテナ イメージは、複数のバイナリとベースとなる Linux イメージに必要なライブラリのみを追加します。
  • 独立した読み取り専用の永続ディスク ボリュームにアセットを格納し、実行時にコンテナにマウントします。
  • Kubernetes API と Google Cloud Platform API を使用して、基本的なスケジューラ プロセスを設定および構成し、必要に応じてノードのスピンアップとスピンダウンを行います。

料金

このチュートリアルでは、課金対象である以下の Google Cloud Platform コンポーネントを使用します。

料金計算ツールを使うと、予想使用量に基づいて費用の見積もりを出すことができます。

始める前に

このチュートリアルは Linux または macOS 環境から実行します。

  1. GCP プロジェクトを選択または作成します。

    [リソースの管理] ページに移動

  2. プロジェクトに対して課金が有効になっていることを確認します。

    課金を有効にする方法について

  3. Compute Engine API を有効にします。

    APIを有効にする

  4. Cloud SDK をインストールして初期化します。

    : このチュートリアルでは Cloud Shell を使用できません。Cloud SDK をインストールする必要があります。

  5. Kubernetes のコマンドライン インターフェースである kubectl をインストールします。
    gcloud components install kubectl
  6. GitHub にあるチュートリアルのリポジトリのクローンを作成します。
    git clone https://github.com/GoogleCloudPlatform/gke-dedicated-game-server.git
    
  7. Docker をインストールします。

    このチュートリアルでは、root ユーザーとして Docker コマンドを実行しません。root 以外のユーザーが Docker を管理できるように、インストール後の処理を行ってください。
  8. (省略可)チュートリアルの最後にゲームサーバーへの接続をテストする場合は、OpenArena ゲーム クライアントをインストールします。ゲーム クライアントを実行するには、デスクトップ環境が必要です。このチュートリアルでは、Linux または macOS でのテスト方法について説明します。

アーキテクチャ

ゲーム ソリューションの概要

クラウド上のゲーム インフラストラクチャの概要ページでは、多くのオンライン ゲーム アーキテクチャに共通するコンポーネントの概要について説明しています。このチュートリアルでは、フロントエンド サービスとして Kubernetes DGS クラスタを実装し、バックエンド サービスとしてスケーリング マネージャーを実装します。本番環境のゲーム インフラストラクチャには、これ以外に多くのフロントエンド サービスとバックエンド サービスが実装されていますが、このチュートリアルでは、これらのサービスについて説明しません。

このチュートリアルの設計上の制約

このチュートリアルでは、学習用に拡張の余地がある単純なサンプルを作成するので、ゲームについて次の制約があることを前提にしています。

  • リアルタイムの対戦型ゲームであり、信頼できる DGS でゲームの状態をシミュレートします。
  • DGS は UDP 経由でクライアントと通信します。
  • 各 DGS プロセスで 1 つの対戦を実行します。
  • どの DGS プロセスでも、ほぼ同じ負荷が発生します。
  • 対戦には最大時間が設定されています。
  • DGS の起動時間は無視できるレベルであり、専用ゲームサーバー プロセスを事前準備しておく必要はありません。
  • ピーク後にスケールダウンする際に、コスト節減のために対戦が途中で終了させられることはありません。プレーヤーのエクスペリエンスに影響を及ぼさないことが優先されます。
  • DGS プロセスでエラーが発生して続行できなくなったときは、対戦の状態が失われます。プレーヤーは、ゲーム クライアントを使用して別の対戦に参加するものと想定されます。
  • DGS プロセスはディスクから静的アセットを読み込みますが、アセットへの書き込みは求められません。

これらの制約はゲーム業界で特殊のものではなく、実際の事例でも同様の制約がかかる場合があります。

GCP 作業環境の準備

gcloud コマンドを簡単に実行できるようにプロパティを設定します。これにより、コマンドを実行するたびに、プロパティのオプションを指定する必要がなくなります。

  1. [PROJECT_ID] にプロジェクト ID を指定して、デフォルトのプロジェクトを設定します。

    gcloud config set project [PROJECT_ID]
  2. [ZONE] に優先ゾーンを指定して、Compute Engine のデフォルト ゾーンを設定します。

    gcloud config set compute/zone [ZONE]

専用ゲームサーバーのコンテナ化

このチュートリアルでは、「GPL idTech3 テクノロジーに基づいてコミュニティが作り上げたデスマッチ FPS」といわれている OpenArena を使用します。このゲームの技術が登場してから 15 年以上になりますが、現在でも一般的な DGS パターンの優れた見本です。

  • サーバー バイナリは、ゲーム クライアントと同じコードベースからコンパイルされます。
  • サーバー バイナリには、サーバーがシミュレーションを実行するために必要なデータアセットしか含まれていません。
  • ゲームサーバーのコンテナ イメージでは、サーバー プロセスの実行に必要なバイナリと、ベースとなる OS のコンテナ イメージを参照するライブラリのみが追加されます。
  • アセットは別のボリュームからマウントされます。

このアーキテクチャには多くのメリットがあります。バイナリのみが置換され、消費するディスク容量も少ないため、イメージの配布を迅速に行い、更新の負荷を軽減できます。

コンテナ イメージの作成

Dockerfile に、ビルドするイメージを記述します。このチュートリアルの Dockerfile は、openarena/Dockerfile のリポジトリにあります。openarena/ ディレクトリから Docker の build コマンドを実行してコンテナ イメージを生成し、OpenArena サーバーのバージョン 0.8.8 というタグを付けます。

docker build -t openarena:0.8.8 .

アセット ディスクの生成

通常、ゲームのバイナリはアセットよりもかなり小さくなります。このため、バイナリのみを含むコンテナ イメージを作成することは理にかなっています。アセットは永続ディスクに配置し、DGS コンテナを実行する複数の VM インスタンスに接続できるようにします。このアーキテクチャでは、コスト面のメリットがあるだけでなく、すべての VM インスタンスにアセットを配布する必要がなくなります。

  1. gcloud を使用して、サイズの小さい Compute Engine VM インスタンスを作成します。

    gcloud compute instances create openarena-asset-builder \
        --machine-type f1-micro --image-family debian-9 \
        --image-project debian-cloud
  2. 永続ディスクを作成します。

    gcloud compute disks create openarena-assets --size=50GB \
        --type=pd-ssd --description="OpenArena data disk. \
        Mount read-only at /usr/share/games/openarena/baseoa/"

    永続ディスクはブートディスクと別にし、仮想マシンと一緒に削除されないように構成する必要があります。Kubernetes の persistentVolume 機能は、GKE で永続ディスクを扱うときに役に立ちます。Compute Engine では、これらの永続ディスクは、パーティション テーブルのない単一の ext4 ファイル システムである必要があります。

  3. openarena-assets 永続ディスクを openarena-asset-builder VM インスタンスに接続します。

    gcloud compute instances attach-disk openarena-asset-builder \
        --disk openarena-assets
  4. 新しいディスクをフォーマットします。

    1. openarena-asset-builder VM インスタンスにログインして、ディスクをフォーマットします。

      gcloud compute ssh openarena-asset-builder
    2. 次のステップで使用する mkfs.ext4 コマンドは、ディスク上のすべてのデータを消去するコマンドであるため、openarena-assets ディスクのデバイス ID を必ず確認してください。このチュートリアルを最初から実行していて、新しいプロジェクトを使用している場合、ID は /dev/sdb です。lsblk コマンドを実行して、接続されているディスクとそのパーティションを確認します。

      sudo lsblk

      出力を見ると、デバイス sdb には 2 つのディスクが接続しています。1 つは 10 GB の OS ディスク sda で、ここには 1 つのパーティション sda1 があります。もう 1 つは 50 GB の openarena-assets ディスクで、ここにはパーティションがありません。

      NAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINT
      sda 8:0 0 10G 0 disk
      └─sda1 8:1 0 10G 0 part /
      sdb 8:16 0 50G 0 disk
    3. openarena-assets ディスクをフォーマットします。

      sudo mkfs.ext4 -m 0 -F -E \
          lazy_itable_init=0,lazy_journal_init=0,discard /dev/[DEVICE_ID]
  5. openarena-asset-builder VM インスタンスに OpenArena をインストールし、圧縮されたアセット アーカイブを openarena-assets 永続ディスクにコピーします。

    このゲームのアセットは .pk3 ファイルで、/usr/share/games/openarena/baseoa/ ディレクトリにあります。いくつかの作業を保存するため、インストールの前に以下の一連のコマンドを実行して、このディレクトリにアセット ディスクをマウントします。インストールを実行すると、すべての .pk3 ファイルがこのディスクに保存されます。必ず前のステップで確認したデバイス ID を使用してください。

    sudo mkdir -p /usr/share/games/openarena/baseoa/
    
    sudo mount -o discard,defaults /dev/[DEVICE_ID] \
        /usr/share/games/openarena/baseoa/
    
    sudo apt-get update && sudo apt-get -y install openarena-server
  6. インスタンスを終了して削除します。

    exit
    gcloud compute instances delete openarena-asset-builder

    ディスクが Kubernetes の永続ボリュームとして使用できる状態になりました。

ゲーム開発のパイプラインの一部として永続ディスクを実装する場合は、適切なディレクトリ構造のすべてのアセット ファイルが永続ディスクに作成されるようにビルドシステムを構成します。この構成は、gcloud コマンドを実行する単純なスクリプトで行う場合もあれば、選択したビルドシステムに GCP 固有のプラグインで行う場合もあります。スループットを向上させながら障害リスクを管理できるように、永続ディスクの複数のコピーを作成して、これらのコピーに VM インスタンスをバランスよく接続することをおすすめします。

Kubernetes クラスタの設定

Kubernetes はオープンソースのコミュニティ プロジェクトで、オンプレミスを含むほとんどの環境で実行できます。

Kubernetes Engine に Kubernetes クラスタを作成する

このチュートリアルでは、n1-highcpu マシンタイプの標準の Kubernetes Engine クラスタを使用します。これは OpenArena の使用に適しています。

  1. game という名前でゲーム用の VPC ネットワークを作成します。

    gcloud compute networks create game
  2. OpenArena にファイアウォール ルールを作成します。

    gcloud compute firewall-rules create openarena-dgs --network game \
        --allow udp:27961-28061
  3. gcloud を使用して、それぞれが game ネットワークを使用する、4 個の仮想 CPU コアを持つ 3 ノードクラスタを作成します。

    gcloud container clusters create openarena-cluster \
        --network game --num-nodes 3 --machine-type n1-highcpu-4 \
        --addons KubernetesDashboard
  4. クラスタを起動した後、適切な Kubernetes 認証情報を使ってローカルシェルを設定し、新しいクラスタを制御します。

    gcloud container clusters get-credentials openarena-cluster

本番環境のクラスタでは、各マシンで実行する vCPU の数は主に次の 2 つの要因によって決まります。

  • 同時に実行する予定の DGS ポッドの最大数。 Kubernetes クラスタプール内のノード数には制限があります(ただし Kubernetes プロジェクトでは、将来のリリースでこの最大数を増やす予定です)。たとえば、仮想 CPU(vCPU)ごとに 1 つの DGS を実行する場合、n1-highcpu-2 マシンの 1,000 ノードクラスタで使用できる DGS ポッドの数はわずか 2,000 個です。これに対して、n1-highcpu-32 マシンの 1,000 ノードクラスタでは、最大 32,000 個のポッドを使用できます。

  • VM インスタンスの粒度。 クラスタ内のリソースの追加や削除を行う場合、クラスタの作成時に選択したタイプの単一の VM インスタンスを増減させるのが最も簡単な方法です。したがって、32 個の vCPU より少ない容量を一度に追加または削除する場合は、32 vCPU マシンを選択しないでください。

GKE でデフォルトで使用されるマネージド インスタンス グループ機能には、VM インスタンスの自動スケーリングと HTTP 負荷分散の機能が含まれています。ただし、Kubernetes クラスタの作成で使用したコマンドでは、--disable-addons HttpLoadBalancing,HorizontalPodAutoscaling フラグを使用して、これらの機能を無効にしました。

DGS は TCP ではなく UDP を使用してクライアントと通信するため、HTTP 負荷分散は不要です。オートスケーラーは CPU 使用率に基づいてインスタンス グループをスケーリングするため、DGS の負荷を正確に把握できない可能性があります。多くの DGS は、ゲームのシミュレーションを最適化するため、アイドル サイクルを消費するように設計されています。

結果として、多くのゲーム開発者は、このタイプのワークロードの要件に対応するため、DGS 対応のカスタム スケーリング マネージャー プロセスを実装しています。ただし、この場合もマネージド インスタンス グループは重要な役割を果たしています。デフォルトの GKE イメージ テンプレートには、必要な Kubernetes ソフトウェアがすべて含まれ、起動時にノードを自動的にマスターに登録します。

コンテナ イメージを GCP にアップロードする

Google では、Container Registry(gcr.io)に非公開 Docker イメージのストレージを提供しています。

  1. GKE クラスタに最も近い gcr.io リージョンを選択します(たとえば、ドキュメントにあるとおり米国では us、ヨーロッパでは eu、アジアでは asia を選択します)。リージョン情報をプロジェクト ID と一緒に環境変数の中で設定します。

    export GCR_REGION=[GCR_REGION] PROJECT_ID=[PROJECT_ID]
  2. コンテナ イメージに gcr.io レジストリ名でタグを付けます。

    docker tag openarena:0.8.8 \
        ${GCR_REGION}.gcr.io/${PROJECT_ID}/openarena:0.8.8
  3. コンテナ イメージをイメージ リポジトリにアップロードします。

    gcloud docker -- push \
        ${GCR_REGION}.gcr.io/${PROJECT_ID}/openarena:0.8.8

push が完了すると、コンテナ イメージが GKE クラスタ内で実行可能になります。後でポッド指定ファイルに入れる必要があるため、最終的なコンテナ イメージタグをメモしておきます。

Kubernetes でアセット ディスクを構成する

通常の DGS では、ゲームアセットへの書き込みを必要としないため、各 DGS ポッドに読み取り専用アセットを含む永続ディスクをマウントできます。この処理を行うには、Kubernetes の persistentVolume リソースと persistentVolumeClaim リソースを使用します。

  1. 前に作成したアセット ディスクにバインドする Kubernetes persistentVolume リソースの定義を含む asset-volume.yaml を適用します。

    kubectl apply -f openarena/k8s/asset-volume.yaml
  2. asset-volumeclaim.yaml を適用します。このファイルには Kubernetes persistentVolumeClaim リソースの定義が含まれています。これにより、ポッドがアセット ディスクをマウントできるようになります。

    kubectl apply -f openarena/k8s/asset-volumeclaim.yaml

    次のコマンドを実行して、ボリュームが Bound 状態であることを確認します。

    kubectl get persistentVolume

    予想される出力:

    NAME           CAPACITY   ACCESSMODES   RECLAIMPOLICY   STATUS    CLAIM                      STORAGECLASS   REASON    AGE
    asset.volume   50Gi       ROX           Retain          Bound     default/asset.disk.claim   assets                   3m

    同様に、クレームがバインド状態であることを確認します。

    kubectl get persistentVolumeClaim

    予想される出力:

    NAME               STATUS    VOLUME         CAPACITY   ACCESSMODES   STORAGECLASS   AGE
    asset.disk.claim   Bound     asset.volume   50Gi       ROX           assets         25s

DGS ポッドの構成

スケジューリング タスクとネットワーキング タスクは Kubernetes によって処理されるため、DGS コンテナの起動時間とシャットダウン時間は無視できます。したがって、このチュートリアルでは DGS インスタンスを必要に応じてスピンアップします。

各 DGS インスタンスは 1 回の対戦時間だけ持続します。対戦時間は OpenArena DGS サーバーの構成ファイルで制限されています。対戦が完了すると、コンテナが正常に終了します。プレーヤーが再度プレイしたい場合、別のゲームをリクエストすることになります。この設計は、ポッド ライフサイクルのさまざまな側面を簡略化するだけでなく、スケーリング マネージャーのセクションで説明するように、自動スケーリング ポリシーの基礎となります。

このチュートリアルではゲーム クライアント コードのフォークや変更を行わないため、このフローは OpenArena とシームレスではありません。市販のゲームでは、別の対戦のリクエストは前回の対戦結果画面や読み込み時間の背後で実行され、ユーザーからは見えません。対戦間で新しいサーバー インスタンスに接続するコードは、ネットワークの問題やサーバーのクラッシュなどの予期せぬ状況でクライアントの再接続を処理する場合でも必要になるため、開発時間が余分にかかることはありません。

わかりやすくするために、このチュートリアルでは GKE ノードにデフォルトのネットワーク構成があるものとします。この構成では、各ノードにパブリック IP アドレスが割り当てられ、クライアント接続を許可します。

専用のゲームサーバー プロセスの管理

市販のゲームサーバーの場合、コンテナ内での DGS の実行に必要な DGS 以外の機能は、可能な限り DGS バイナリに直接統合しています。

ベスト プラクティスでは、DGS がマッチメーカーやスケーリング マネージャーと直接通信を行わずに、その状態を Kubernetes API に公開します。外部プロセスは、サーバーに直接クエリを送信するのではなく、適切な Kubernetes エンドポイントから DGS の状態を読み取ります。Kubernetes API への直接アクセスの詳細については、Kubernetes のドキュメントをご覧ください。

有効期間が限定され、成功条件が定義されたコンテナ内で単一のプロセスを実行するのが Kubernetes ジョブのユースケースのように見えますが、実際にはジョブを使用する必要はありません。DGS プロセスはジョブの並列実行機能を必要としません。また、自動的に再起動することで成功を保証する必要もありません。通常、セッションベースの DGS がなんらかの理由で終了し、状態が失われた場合、プレーヤーは別の DGS に参加します。そのため、このユースケースでは個々の Kubernetes ポッドをスケジューリングするほうが適切です。

本番環境では、DGS ポッドは Kubernetes API を使用してマッチメーカーによって直接開始されます。このチュートリアルでは、DGS ポッドリソースを記述している YAML ファイルが openarena/k8s/openarena-pod.yaml のチュートリアル リポジトリに含まれています(このファイルは、人が読める形式になっています)。専用のゲームサーバー ポッドを構成する場合は、アセット ディスクが複数のポッドに読み取り専用でマウントできるように、ボリューム プロパティに注意する必要があります。

スケーリング マネージャーの設定

スケーリング マネージャーとは、GKE ノードとして使用される仮想マシンの数を、その時点の DGS 負荷に基づいてスケーリングする単純なプロセスです。スケーリングは、永続的に動作する一連のスクリプトを使用し、実行中の DGS ポッドの数とリクエストされた DGS ポッドの合計数を検査して、必要に応じてノードプールのサイズを変更します。スクリプトは、適切なライブラリと Cloud SDK を含む Docker コンテナ イメージにパッケージングされています。Docker イメージは、次の手順で作成して gcr.io に push できます。

  1. 必要に応じて、gcr.io の GCR_REGION 値と PROJECT_ID をビルドおよび push スクリプトの環境変数に設定します。以前、コンテナ イメージをアップロードしたときに、すでにこの手順を実行している場合はスキップできます。

    export REGION=[GCR_REGION] PROJECT_ID=[PROJECT_ID]
  2. スクリプト ディレクトリに移動します。

    cd scaling-manager
  3. ビルド スクリプトを実行して、すべてのコンテナ イメージをビルドし、gcr.io に push します。

    ./build-and-push.sh
  4. テキスト エディタで、scaling-manager/k8s/openarena-scaling-manager-deployment.yaml の Kubernetes デプロイ ファイルを開きます。

    スケーリング マネージャー スクリプトは Kubernetes デプロイ内で実行されるように設計されているため、これらのプロセスは障害が発生すると必ず再起動されます。

  5. 次の表に示すとおり、環境変数をデプロイ用の値に変更します。

    環境変数 デフォルト値 備考
    REGION [GCR_REGION] 置換が必要。 gcr.io リポジトリのリージョン。
    PROJECT_ID [PROJECT_ID] 置換が必要。 プロジェクトの名前。
    GKE_BASE_INSTANCE_NAME gke-openarena-cluster-default-pool-[REPLACE_ME] 置換が必要。 GKE クラスタごとに異なる。[REPLACE_ME] の値を取得するには、gcloud compute instance-groups managed list コマンドを実行する。
    GCP_ZONE [ZONE] 置換が必要。 このチュートリアルの冒頭で指定した GCP ゾーンの名前。
    K8S_CLUSTER openarena-cluster Kubernetes クラスタの名前。
  6. 親ディレクトリに戻ります。

    cd ..
  7. Kubernetes クラスタにデプロイを追加します。

    kubectl apply \
        -f scaling-manager/k8s/openarena-scaling-manager-deployment.yaml

ノードのスケーリング方法

ノードのスケーリングを行うため、スケーリング マネージャーが Kubernetes API を使用して現在のノードの使用状況を確認します。必要に応じて、マネージャーは基盤となる仮想マシンを実行する Kubernetes Engine クラスタでマネージド インスタンス グループのサイズを変更します。

DGS ポッドに対するスケーリングの問題

DGS スケーリングの一般的な問題点は次のとおりです。

  • CPU とメモリの使用量の標準的な指標では、ゲームサーバー インスタンスのスケーリングを開始するのに十分な情報を取得できないことがあります。
  • 最適化された DGS コンテナを既存のノードでスケジューリングするには数秒かかるため、十分活用されていない利用可能なノードのバッファを維持する必要があります。しかし、ノードの追加には数分かかる場合があり、これは待機中のプレーヤーにとっては許容できないレイテンシです。
  • 多くのオートスケーラーはポッドのシャットダウンを正常に処理できません。削除対象のノードからポッドをドレインすることが重要です。対戦を実行しているノードを 1 つでも停止することは許されません。

このチュートリアルで提供しているスクリプトは基本的で、シンプルな設計ですが、ロジックを簡単に追加できます。一般的な DGS にはよく知られているパフォーマンス特性があり、これらを指標とすることで、VM インスタンスを追加または削除するタイミングを判断できます。一般的なスケーリング指標には、このチュートリアルで使用されている CPU あたりの DGS インスタンスの数や使用可能なプレーヤー スロットなどが含まれています。

スケールアップ

このチュートリアルでは、スケールアップについて特別な処理を行う必要はありません。わかりやすくするため、このチュートリアルではポッドのプロパティ limits および requests をポッドの YAML ファイル(openarena/k8s/openarena-pod.yaml)で設定し、各 DGS におよそ 1 個の割合で vCPU を予約しています。これは OpenArena にとっては十分な値です。

クラスタは n1-highcpu インスタンス ファミリーを使って作成されたので、1 個の vCPU に対してメモリ 600 MB という固定率になります。vCPU あたり 1 個の DGS ポッドがスケジューリングされている場合、メモリは十分な量といえます。したがって、クラスタ内のポッド数とクラスタ内のすべてのノードの CPU 数の比較に基づいてスケールアップを行うことができます。この比率によって使用可能な残りのリソースが決まるため、値がしきい値を下回った場合にノードを追加できます。このチュートリアルでは、vCPU の 70% 以上がポッドに割り当てられている場合にノードが追加されます。

本番環境のオンライン ゲームのバックエンドでは、DGS の CPU、メモリ、ネットワークの使用状況を正確にプロファイリングし、limitsrequests のポッド プロパティを適切に設定することをおすすめします。多くのゲームでは、DGS シナリオごとに複数のポッドタイプを作成し、ゲームタイプ、特定のマップ、プレーヤー スロット数などの異なるプロファイルを設定するほうが理にかなっています。このような検討事項は、このチュートリアルの範囲外ですので、これ以上は触れません。

スケールダウン

スケールダウンは、スケールアップとは異なり、複数のステップから構成されるプロセスで、Kubernetes 対応のカスタム DGS スケーリング マネージャーが実行される理由の 1 つになっています。このチュートリアルでは、scaling-manger.sh が以下のステップを自動的に処理します。

  1. 削除すべき適切なノードを選択します。このチュートリアルでは、カスタムゲームに完全に対応する Kubernetes スケジューラは使用しないので、ノードは API によって返される順に選択されます。

  2. 選択したノードを Kubernetes で使用不可とマークします。これにより、ノードで追加のポッドが起動されなくなります。

  3. abandon-instance コマンドを使用して、選択したノードをマネージド インスタンス グループから削除します。これにより、マネージド インスタンス グループがインスタンスを再作成しなくなります。

また、node-stopper.sh スクリプトは、放棄されたスケジュール不可のノードをモニタリングし、DGS ポッドが存在しないことを確認します。ノード上ですべての対戦が終了してポッドが終了すると、スクリプトは VM インスタンスをシャットダウンします。

DGS ポッドの数をスケーリングする

本番環境の標準的なゲーム バックエンドでは、新しい DGS インスタンスを追加するタイミングがマッチメーカーによって制御されます。DGS ポッドは対戦終了時に終了するように構成されているため(前の設計上の制約を参照)、DGS ポッドの数を減らす明示的なアクションは必要ありません。新しい対戦を要求する十分な数のリクエストがマッチメーカー システムに送信されない場合、対戦終了後に、DGS ポッドは Kubernetes クラスタから自身を削除します。

セットアップのテスト

ここまでで、OpenArena コンテナ イメージを作成してコンテナ レジストリに push し、DGS Kubernetes クラスタを開始しました。さらに、ゲームのアセット ディスクを生成し、Kubernetes で使用できるように構成して、スケーリング マネージャーのデプロイを開始しました。では、DGS ポッドを起動してみましょう。

新しい DGS インスタンスをリクエストする

本番環境の標準的なシステムでは、マッチメーカー プロセスが対戦相手を選択すると、Kubernetes API を使用してインスタンスを直接リクエストします。ここでは、チュートリアルの設定をテストすることが目的ですので、インスタンスを直接リクエストすることにします。

  1. テキスト エディタで openarena/k8s/openarena-pod.yaml を開き、実行するコンテナ イメージが指定されている行を探します。

  2. docker tag コマンドを実行して、openarena コンテナ イメージのタグに一致するように値を変更します(このチュートリアルの前述の説明を参照)。

  3. openarena-pod.yaml ファイルを指定して、kubectl apply コマンドを実行します。

    kubectl apply -f openarena/k8s/openarena-pod.yaml
  4. しばらく待ち、ポッドの状態を確認します。

    kubectl get pods

    出力は次のようになります。

    NAME             READY     STATUS    RESTARTS   AGE
    openarena.dgs    1/1       Running   0          25s

DGS に接続する

ポッドが起動したら、OpenArena クライアントを起動して、DGS に接続できることを確認します。

macOS または Linux デスクトップ:

export NODE_NAME=$(kubectl get pod openarena.dgs \
    -o jsonpath="{.spec.nodeName}")
export DGS_IP=$(gcloud compute instances list \
    --filter="name=( ${NODE_NAME} )" \
    --format='table[no-heading](EXTERNAL_IP)')
openarena +connect ${DGS_IP}

スケーリング マネージャーのテスト

スケーリング マネージャーは、DGS ポッドの数に基づいて Kubernetes クラスタ内の VM インスタンス数をスケーリングします。スケーリング マネージャーをテストするには、一定の期間内に多くのポッドをリクエストし、ノードの数が適切に増加するかどうか確認する必要があります。ノードのスケールダウンを確認するには、サーバー構成ファイルで対戦時間に制限を定義する必要があります。openarena/single-match.cfg にあるチュートリアルのサーバー構成ファイルでは、対戦時間が 5 分に制限されています。このファイルは、デフォルトでチュートリアルの DGS ポッドで使用されます。次のスクリプトを実行してテストを行います。このスクリプトは、5 分間に一定の間隔で DGS ポッドを追加します。

./scaling-manager/tests/test-loader.sh

kubectl get nodes を定期的に実行することで、ノードのスケールアップとスケールダウンの回数を確認できます。

クリーンアップ

このチュートリアルで使用したリソースについて、Google Cloud Platform アカウントに課金されないようにする手順は次のとおりです。

プロジェクトを削除する

課金を停止する最も簡単な方法は、チュートリアル用に作成したプロジェクトを削除することです。

プロジェクトを削除する手順は次のとおりです。

  1. GCP Console で [プロジェクト] ページに移動します。

    プロジェクト ページに移動

  2. プロジェクト リストで、削除するプロジェクトを選択し、[削除] をクリックします。
  3. ダイアログでプロジェクト ID を入力し、[シャットダウン] をクリックしてプロジェクトを削除します。

GKE クラスタの削除

プロジェクト全体を削除したくない場合は、次のコマンドを実行して GKE クラスタを削除します。

gcloud container clusters delete openarena-cluster

永続ディスクを削除する

永続ディスクを削除する手順は次のとおりです。

  1. GCP Console で、[Compute Engine のディスク] メニューに移動します。

    [Compute Engine のディスク] ページに移動

  2. 削除するディスクを選択します。

  3. ページ上部にある [削除] ボタンをクリックします。

次のステップ

このチュートリアルでは、専用のゲームサーバーをコンテナ内で実行し、ゲームの負荷に基づいて Kubernetes クラスタを自動スケーリングするベアボーン アーキテクチャを説明しました。基本的なクライアントサイド サポートをプログラミングすることで、セッション間でのシームレスなプレーヤーの移行など、多くの機能を追加できます。プレーヤーがグループを形成し、サーバー間でグループを移動できるようにするために、マッチメイキング サービスとは別にプラットフォーム サービスを作成することもできます。このサービスを使用してグループを作成し、グループ招待状の送信、受信、拒否を行ったり、プレーヤーのグループを専用のゲームサーバー インスタンスに送信することもできます。

また、よりインテリジェントなゲームを展開するため、DGS ポッドのノードを選択できる Kubernetes カスタム スケジューラがよく利用されています。ほとんどのゲームでは、ポッドをまとめて処理するカスタム スケジューラが必要になります。これにより、ピーク後にスケールダウンするときに、削除するノードの順序を簡単に決めることができます。

GCP で DGS を実行するためのガイド:

このページは役立ちましたか?評価をお願いいたします。

フィードバックを送信...