この記事はGoogle Cloud + Gaming Advent Calendar 2020の1日目のものです。
この記事では、KubernetesのGaming LibraryであるAgonesがKubernetesの拡張機能をどのように使って実現されているかを技術的に解説する記事です。
※ Kubernetesの基本知識を前提としています
Agonesとは?
AgonesはKubernetes上で動くGame Serverを制御するライブラリです。
Kubernetesの拡張機能であるAdmission Webhook, Custom Resource Definition, API Aggregationを使ってその機能を実現しています。
公式サイト: https://agones.dev/site/
Agonesのユースケース
AgonesはGame Serverを起動したりスケールさせたりするために使いますが、Gameの中でも特にリアルタイムマルチプレイゲーム(e.g. 協力プレイ, 対戦)用に使用します。
コンテナはベストプラクティスとして状態を持たない(ステートレス)ことが望ましいですが、リアルタイムマルチプレイではその名の通りリアルタイムで情報を処理するため、どうしても状態を持つ必要が出てきます。
Kubernetes上ではコンテナのスケジューリングを基本Kubernetesにお任せするので、コンテナがいつ起動するのか/いつ終了するのかを完全に制御することはできません。
普通のコンテナとしてリアルタイムマルチプレイの機能を持ったGame Serverを動かしていると、ユーザー同士が対戦・協力プレイなどのリアルタイム性の高いゲームをしている最中にコンテナが終了され、ユーザー体験が台無しにされてしまう可能性があります。
そこで出てくるのがAgonesです。 Agonesはコンテナ(正確にはPod)が勝手に終了しないように保護したり、グローバルな通信をServiceやIngressといったKubernetesの機能を介さずに通信を受け付けられるようにするなど、リアルタイムマルチプレイに必要な機能を提供してくれます。
本記事ではそのAgonesを支えるKubernetesの拡張機能部分を解説していきます。
Agonesのより詳しい説明については、素晴らしい記事があるのでこちらを紹介します。
参考記事: Agones 超入門
Agonesを支えるKubernetesの拡張機能
ここからはKubernetesの拡張機能についての話になってきます。
KubernetesはPlatform for Platformと呼ばれることが多くなってきたプロダクトですが、素晴らしいことにその機能をユーザー自身が拡張する仕組みを提供しています。
そのKubernetesが提供している拡張機能を使うことで、Agonesが実現しているような特殊な機能を実装することができます。
そのKubernetesが提供している拡張機能には3つの種類があります。
- Admission Webhook
- Custom Resource Definition(CRD)
- API Aggregation
それぞれ簡単に説明していきます。
1. Admission Webhook
Admission Webhookは、Resourceを作成・更新・削除などをした時に任意のWebhookを挟むことができる、という拡張機能です。
出典: https://kubernetes.io/blog/2019/03/21/a-guide-to-kubernetes-admission-controllers/
ユースケースとして、Podにresources.requests
やresources.limits
が付いていない時はデフォルト値を設定するようにしたいとします。
Admission Webhookには、Mutating Webhook
(デフォルト値を埋め込んだり変更したりできるHook)とValidating Webhook
(決めたルールに沿っているか検証するHook)の2種類があります。
上のユースケースだと、Mutating Webhookでresources.requests
やresources.limits
が空の場合はデフォルト値を埋めて、Validating Webhookで本当にresources.requests
やresources.limits
が埋まっているかを確認する処理を挟むことで実現できます。
あるResource(Pod, Deploymentなど)の操作に対して任意の処理(Webhook)を挟むことになるため、CRDやAPI Aggregationに比べると自由度は高くありません
2. Custom Resource Definition
CRDは、PodやDeployment, Serviceなど組み込みAPI Objectの他に、独自のAPI Objectを作成できる機能です。
下図のようにCustom Resource Definitionを定義し、Custom Resouceを監督するCustom Controllerを実装することで、独自のAPI Objectを管理できます。
ユースケースとしては〇〇 Operator
として使われることが多く、たとえばPrometheus OperatorやMySQL Operatorのように、ステートフルなソフトウェアをCustom Resourceとして構築・運用を自動化する目的で使われています。
Kubernetesの拡張機能としては主流の機能ですが、次のAPI Aggregationよりも柔軟性・拡張性には劣ります。
3. API Aggregation
API Aggregationは、拡張API Serverとして動くWebhook Serverを用意することでCRDよりもより柔軟なAPI Objectを作成できます。
Kubernetesで実際に使われる例としては、Metrics Serverが有名です。
ユースケースとしては、CRDよりもより複雑かつ柔軟性が求められるAPI Objectを作りたい時にAPI Aggregationを利用します。
たとえばCRDを作ると、Create/Update/Delete/Patchなどの基本的なAPIの操作方法が提供されますが、そこに独自のAPI Path(e.g. logs, execのような特殊なAPI)を加えたい時にはAPI Aggregationを選択します。
実際にAPI Aggregationを使って実装されているプロダクトは実は多くありません。というのもCRDを使えば大体のプロダクトは目的を達成できるからです。
Kubernetesの拡張機能とAgones
これまでKubernetsの3つの拡張機能の説明をしてきました。
Agonesはこれらの拡張機能を利用して実装されています。Agonesが利用している機能はなんと、この3つ全てです。
3つの機能のそれぞれの特性を活かして実装されており、Kubernetesの拡張機能を使って何かを実装する場合はとても綺麗なお手本になります。
では、これからAgonesが3つの拡張機能をどのように使っているのか確認していきたいと思います。
AgonesとAdmission Webhook
Admission Webhookを確認するにはkubectlを使います。Mutating WebhookとValidating Webhookの2種類に分かれているので注意してください。
まずはkubectlを使って、Mutatingから見ていきます。
$ kubectl get mutatingwebhookconfigurations
NAME CREATED AT
agones-mutation-webhook 2020-11-30T13:50:39Z
agones-mutation-webhook
がMutatingの設定名です。中身を見ると次のようになっています(一部省略)。
$ kubectl get mutatingwebhookconfigurations agones-mutation-webhook -o yaml
apiVersion: admissionregistration.k8s.io/v1
kind: MutatingWebhookConfiguration
metadata:
name: agones-mutation-webhook
...
webhooks:
- admissionReviewVersions:
- v1beta1
clientConfig:
service:
name: agones-controller-service
namespace: agones-system
path: /mutate
port: 443
rules:
- apiGroups:
- agones.dev
apiVersions:
- v1
operations:
- CREATE
resources:
- gameservers
- fleets
scope: '*'
注目するのはclientConfig.service
とclientConfig.rules
です。
rules
でなんのAPI Resourceがどの操作の時にWebhookが動くのかを設定しており、service
でWebhookの接続先を決めます。
この場合は、agones-system
namespaceのagones-controller-service
というServiceの後ろにいるController(Podで動いている)に問い合わせています。
続いてkubectlで、Validatingを確認します。
$ kubectl get validatingwebhookconfigurations
NAME CREATED AT
agones-validation-webhook 2020-11-30T13:50:39Z
こちらもMutatingと似た設定で、検証用のWebhookの設定を行なっていることが分かりました(YAMLの中身は省きます)。
Agonesの場合は、GameServer
かFleet
Resourceが作成(CREATE)されると、Mutatingとしてデフォルト値が埋め込まれ、Validatingでその検証が行われます。
AgonesとCRD
AgonesのメインのAPI Resourceには基本単位となるGameServer
と、複数のGameServer
を管理するFleet
、Fleet
のオートスケールを管理するFleetAutoscaler
があります。
これらはCRDで実現されています。これもkubectlから確認します。
$ kubectl get crd
NAME CREATED AT
fleetautoscalers.autoscaling.agones.dev 2020-11-30T13:50:38Z
fleets.agones.dev 2020-11-30T13:50:38Z
gameserverallocationpolicies.multicluster.agones.dev 2020-11-30T13:50:38Z
gameservers.agones.dev 2020-11-30T13:50:38Z
gameserversets.agones.dev 2020-11-30T13:50:38Z
ここで確認したCRDはあくまでもAPI Resourceの定義です。
これらのResouceをどのように管理し、どのように振る舞うのかを実現しているのがCustom Controllerです。
AgonesのCustom Controllerはデフォルトではagones-system
namespaceに存在しています。
$ kubectl get pods -n agones-system
NAME READY STATUS RESTARTS AGE
agones-controller-f8965d66d-2vhfm 1/1 Running 0 25m
このController Podは1つしかないため、もしなんらかの原因で一度落ちてしまうとその間はGameServer
やFleet
などが機能しなくなるため注意が必要です。
実装については細かく説明していく余裕はないので割愛しますが、ソースコードの場所だけここに残しておきます。
興味のある方はソースコードリーディングに挑戦してみてください。
※ Agonesのバージョンは1.10のコード
GameServer: https://github.com/googleforgames/agones/blob/v1.10.0/pkg/gameservers/controller.go
GameServerSet: https://github.com/googleforgames/agones/blob/v1.10.0/pkg/gameserversets/controller.go
Fleet: https://github.com/googleforgames/agones/blob/v1.10.0/pkg/fleets/controller.go
FleetAutoscaler: https://github.com/googleforgames/agones/blob/v1.10.0/pkg/fleetautoscalers/controller.go
AgonesとAPI Aggregation
AgonesにはGameServerAllocation
機能があります。
これはユーザーがGameServerに入室して使用している(Allocated)か使用していない(Ready)か、ステータスを識別するための機能です。
AgonesのGameServerAllocation
機能はAPI Aggregationによって実現されています。
kubectlでAPI Aggregationの設定を確認します。
$ kubectl get apiservice v1.allocation.agones.dev
NAME SERVICE AVAILABLE AGE
v1.allocation.agones.dev agones-system/agones-controller-service True 38m
v1.allocation.agones.dev
の設定を確認します。
apiVersion: apiregistration.k8s.io/v1
kind: APIService
metadata:
name: v1.allocation.agones.dev
...
spec:
group: allocation.agones.dev
groupPriorityMinimum: 1000
service:
name: agones-controller-service
namespace: agones-system
port: 443
version: v1
versionPriority: 15
ここでもspec.service
を確認すると、agones-system
のagones-controller-service
を向いています。 CRDで定義したCustom Resourceを管理していたのはagones-controller
Podでしたが、GameServerAllocation
も同じようにagones-controller
が管理していることが分かります。
参考: https://github.com/googleforgames/agones/blob/v1.10.0/pkg/gameserverallocations/controller.go
GameServerAllocation
は、CRDのようにAPI Objectを作ってそれを管理する...といったものではなく、存在しているGameServerのステータスをReady
からAllocated
に変更するためのResourceです。
そのためCRDではなく、柔軟な動作ができるAPI Aggregationが使われているのでないかと思われます。
最後に
以上がKubernetesの拡張機能とそれをAgonesがどう活用しているかの確認でした。
私もこの記事を書いて、あらためてagones-controller
が重要な役割を占めていることを再認識しました。
AgonesはKubernetesの拡張としてとても綺麗な作りをしているので、日本でもたくさん使われると知見が貯まってもっと面白くなりそうだなー、と思っています。
以上