この記事について
GoogleとUbisoftにより開発されたオープンソースのゲームプラットフォームAgonesに関する理解を深めていく。
Agonesについて
Agonesにより、デベロッパーはFPSやMMOといったマルチプレイヤーゲームにおけるインフラまわりの課題をオフロードし、バックエンドのロジック開発にフォーカスできるようになる。
ゲーム開発におけるインフラまわりの課題
大規模なオンラインゲームにおけるバックエンドでは、真っ先に以下の項目が検討課題となるだろう。どちらもAgonesが解決する課題だ。
- ホスティングとスケーラビリティ
- ゲームサーバーのライフサイクル管理
ホスティングとスケーラビリティ
- クラウドにデプロイすればサーバー調達のリードタイム不要
- GKEの場合、クラスタにノードを15,000まで拡張可能
allocatorの構成によってはマルチクラスタにもできるようだ。これにより、より大規模なゲームサーバーのスケールアウト・インにも対応可能。
ゲームサーバーのライフサイクル管理
クライアントの接続からゲームサーバーのデプロイ、終了といったライフサイクルをAgonesが担う。これにより開発者はゲームサーバーのロジックに専念できるようなる。
デプロイ
GKEのデプロイ
TerraformでGKEをさくっとデプロイする。
$ cat gke.tf
resource "google_service_account" "default" {
account_id = "service-account-id"
display_name = "Service Account"
}
resource "google_container_cluster" "agones-cluster" {
name = "agones-gke-cluster"
location = "asia-northeast1-b"
remove_default_node_pool = true
initial_node_count = 1
}
resource "google_container_node_pool" "primary_preemptible_nodes" {
name = "agones-node-pool"
location = "asia-northeast1-b"
cluster = google_container_cluster.agones-cluster.name
node_count = 1
node_config {
preemptible = true
machine_type = "e2-medium"
disk_type ="pd-standard"
# Google recommends custom service accounts that have cloud-platform scope and permissions granted via IAM Roles.
service_account = google_service_account.default.email
oauth_scopes = [
"https://www.googleapis.com/auth/cloud-platform"
]
}
}
Agonesのデプロイ
現時点での最新版をデプロイする。
$ kubectl create namespace agones-system
$ kubectl apply --server-side -f https://raw.githubusercontent.com/googleforgames/agones/release-1.30.0/install/yaml/install.yaml
kubenetesデプロイメント
$kubectl get deployment --namespace agones-system
NAME READY UP-TO-DATE AVAILABLE AGE
agones-allocator 3/3 3 3 46s
agones-controller 1/1 1 1 46s
agones-ping 2/2 2 2 46s
役割(ざっくり)
deployment | 役割 |
---|---|
allocator | ゲームサーバーのプロビジョニング。 gRPCまたはRESTでリクエストを受ける。Mutal TLS(mTLS)によりクライアント・サーバー間で相互に正当性を確認するサーバーからもクライアントを検証することで、本来のサービスの提供先でない者からのゲームサーバーへの不正なアクセスを排除できる。(ブルートフォース攻撃対策) |
controller | ゲームサーバーの状態管理 |
ping | pingテスト用サービス |
サービス
$kubectl get service --namespace agones-system
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
agones-allocator LoadBalancer 10.103.254.202 35.189..***.*** 443:30029/TCP 10m
agones-allocator-metrics-service ClusterIP 10.103.246.40 <none> 8080/TCP 10m
agones-controller-service ClusterIP 10.103.241.84 <none> 443/TCP,8080/TCP 10m
agones-ping-http-service LoadBalancer 10.103.240.106 35.200.***.*** 80:32452/TCP 10m
agones-ping-udp-service LoadBalancer 10.103.241.252 34.146.***.*** 50000:32223/UDP 10m
Ingress
デフォルトのデプロイだとIngressは構成されない。クライアントはゲームサーバーのIPをallocatorを通じ入手する。
$kubectl get ingress --namespace agones-system
No resources found in agones-system namespace.
ping
# ping 35.200.***.***
PING 35.200.***.*** (35.200.***.***): 56 data bytes
64 bytes from 35.200.***.***: icmp_seq=0 ttl=105 time=6.474 ms
64 bytes from 35.200.***.***: icmp_seq=1 ttl=105 time=5.882 ms
64 bytes from 35.200.***.***: icmp_seq=2 ttl=105 time=6.201 ms
シークレット
オフィシャルリポジトリのinstall.yamlを使ったデプロイではyaml内のsecretリソースに埋め込まれた証明書がallocatorに適用される。
$kubectl get secret --namespace agones-system
NAME TYPE DATA AGE
agones-manual-cert Opaque 2 8m24s
allocator-client-ca Opaque 1 8m24s
allocator-tls kubernetes.io/tls 2 8m24s
allocator-tls-ca Opaque 1 8m24s
テストゲームサーバーのデプロイ
入力した文字をエコーするだけのシンプルなゲームサーバーをデプロイする。
kubectl create -f https://raw.githubusercontent.com/googleforgames/agones/release-1.30.0/examples/simple-game-server/gameserver.yaml
デプロイされたゲームサーバー。
$kubectl get pod
NAME READY STATUS RESTARTS AGE
simple-game-server-6dglq 2/2 Running 0 92s
カスタムリソース
gameserverはkubectlにカスタムリソースとしてkubectlにロードされていてkubectl上でgameserversオブジェクトとしてステータスを確認できる。
$kubectl get customresourcedefinitions |grep game
gameserverallocationpolicies.multicluster.agones.dev 2023-03-26T04:10:28Z
gameservers.agones.dev 2023-03-26T04:10:27Z
ほかにAgonesのカスタムリソースとしてはFleetがある。
ゲームサーバーのIP
ゲームサーバーにはGKEノードのIPが表示されている。
デフォルトのポートポリシーである"Dynamic"ではGKEノードで空いているポートが割り当てられる。
$kubectl get gameservers
NAME STATE ADDRESS PORT NODE AGE
simple-game-server-6dglq Ready 35.190.***.*** 7513 gke-agones-gke-clust-agones-node-pool-13a521cf-xcgr 2m58s
ゲームサーバーの状態遷移
kubectl describe gameserver
~
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal PortAllocation 26m gameserver-controller Port allocated
Normal Creating 26m gameserver-controller Pod simple-game-server-6dglq created
Normal Scheduled 26m gameserver-controller Address and port populated
Normal RequestReady 26m gameserver-sidecar SDK state change
Normal Ready 26m gameserver-controller SDK.Ready() complete
IPアドレスとポートが割り当てられたあとGameServerはReadyとなる。
ゲームサーバーのステータス遷移
GameServerのライフサイクルを通じ、以下のような経過を辿る。
- Ready
- Allocated
- Shutdown
ゲームサーバーはマッチごとに作成され、マッチが終わると破棄されるスクラップ&ビルドのイメージ。
ゲームサーバーのグローバルIP
Agonesは遅延最小化のためクライアントをゲームサーバーへ直接接続させるアーキテクチャーとなっている。
AllocatorがGKEノードのグローバルIPにクライアントを接続させるということ。GKEならノードのスケールアウトにより利用者が増えてノードのポート枯渇にも容易に対応できる。
サンプルゲームサーバーへの接続
Agonesではゲームサーバーに直接接続する仕組みのため、ノードが一台のミニマム構成の場合はPODに割り当てられたノードIPの公開ポートへUDPで接続するとゲームサーバーに接続できる。
# nc -u 35.190.***.*** 7513
hi
ACK: hi
Don't echo me.
ACK: Don't echo me.
次回
Fleetとマルチクラスタの動きを確認し、Agonesの拡張性について理解していく。