Agones (от др.-греч. agōn — «соревнование») позволяет развернуть кластер игрового сервера используя Kubernetes с возможностью Auto-Scaling. Этот open-source проект был создан в 2018 году, уже набрал 2500 звезд, был на Google I/O 2019, и на Хабре, к великому удивлению, еще не был упомянут. В топике описан краткий экскурс в архитектуру и инструкция по запуску тестового сервера на локальной машине. Если интересно, добро пожаловать под кат, вперед!
Описание проекта
Agones представляет собой Custom Resource (расширение Kubernetes API).
Проект в действительности требует большего внимания, так как позволяет запускать единичный игровой сервер (GameServer) или же целый "флот" серверов (Fleets) посредством конфигурационных yaml файлов, через Agones API. В свою очередь, каждый сервер дает оповещения о его жизненном цикле (GameServer lifecycles), описывая текущий статус (health checking, connection information). Сервера в кластере имеют возможность автоматического масштабирования (Fleet Autoscaling), которые интегрированы с базовыми возможностями Kubernetes. В дополнение, есть вывод статистики на панели (dashboard) с помощью Prometheus, Grafana или Stackdriver, экспортируются метрики посредством OpenCensus, что позволяет добавить собственный экспортер. Пример dashboard'a в Stackdriver:
Архитектура, основные элементы
Сам по себе Agones берет на себя задачу запуска, автоматического расширения и хостинга игровых серверов используя в основе Kubernetes. Это позволяет сосредоточиться на разработке самого сервера многопользовательской игры, вместо разработки ее инфраструктуры и дальнейшей поддержки. Можно использовать любой игровой сервер, который может быть запущен на linux, причем он может быть написан на любом языке программирования.
Agones Kubernetes API делится на три основных пакета (packages), в каждом из которых находятся ресурсы: agones.dev (GameServer, GameServerSet, Fleet), allocation.agones.dev (GameServerAllocation), autoscaling.agones.dev (FleetAutoscaler). Как и в других ресурсах Kubernetes для их запуска используется yaml файлы.
Краткое описание каждого ресурса:
- GameServer — создает некий шаблон, который позволяет использовать обычные Pod параметры, с некоторыми дополнениями, такие как hostPort и containerPort для игрового сервера. Agones SDK предоставляет дополнительный контейнер "помощник" (sidecar), с которым GameServer в процессе будет постоянно общаться
- GameServerSet — структура данных для нескольких GameServer, очень схоже с отношением между Depoyment и ReplicaSet
- Fleet — создает несколько готовых GameServer, используется GameServerAllocation для распределения ресурсов
- GameServerAllocation — запрашивает GameServer из Fleet для использования и помечает, что он готов для использования игроками, благодаря этому GameServer не будет автоматически удален
- FleetAutoscaler — автоматически расширяет или, наоборот, уменьшает количество серверов во Fleet
Диаграмма (отсюда) показывает жизненный цикл GameServer ресурса:
Фиолетовыми стрелками отмечена работа Agones SDK, красным — API пользователя, синим — контроллер игрового сервера, желтым — контроллер приложения.
Установка
В данном и последующих разделах используются команды с инструкции на официальном сайте, с некоторыми дополнениями. Рекомендуется использовать Kubernetes версии 1.12 (протестировано разработчиками). Для теста на локальном компьютере можно использовать minikube, который потребует kubectl и гипервизор (Hyper-V или VirtualBox) поддерживаемый операционной системой.
Для установки кластера и Agones необходимо запустить следующие команды:
minikube profile agones #создадим профиль под названием agones
minikube start --kubernetes-version v1.12.10 --vm-driver hyperv #virtualbox
minikube status #статус кластера для созданного профиля
kubectl create namespace agones-system #создадим пространство имен для agones
kubectl apply -f https://raw.githubusercontent.com/googleforgames/agones/release-1.0.0/install/yaml/install.yaml
Последняя команда скачивает конфигурационный файл Agones создающий Custom Resource Definitions (CRD) через Kubernetes API.
Запуск GameServer
Теперь можно запустить в кластере UDP сервер используя готовый тестовый сервер из примеров, который будет просто отвечать на посланный к нему запрос:
#создание GameServer ресурса
kubectl create -f https://raw.githubusercontent.com/googleforgames/agones/release-1.0.0/examples/simple-udp/gameserver.yaml
kubectl get gameservers #список всех GameServer
minikube ip #адрес для подключения к серверу
kubectl describe gameserver #параметры и статус каждого GameServer
kubectl get gs #более удобная команда, список всех GameServer
Для подтверждения того, что сервер работает можно использовать NetCat, для linux программа обычно идет в поставке с системой, для windows её нужно скачать, к примеру здесь. NetCat нужно запустить с параметром -u
(UDP запрос), указывая адрес minikube (лучше скопировать адрес с команды minikube ip
) и активный порт GameServer:
echo "hello" | nc -u $(minikube ip) 7331
Если после запуска команды в консоли появится ответ "ACK: hello", то сервер работает, его можно выключить следующей командой, которая инициализирует :
echo "EXIT" | nc -u $(minikube ip) 7331
Статус сервера проверяется командой kubectl describe gameserver
, он должен поменяться на Shutdown.
Вносим изменения в GameServer
Используя предыдущий пример изменим ответ сервера. Для начала скопируем репозиторий проекта:
git clone git@github.com:googleforgames/agones.git
В файле agones/examples/simple-udp/main.go поменяем строку 159 на
respond(conn, sender, "ACKNOWLEDGED: "+txt+"\n")
Из корневой папки проекта запустим следующее, чтобы создать docker image и сохранить его в minikube. Для windows предварительно нужно запустить minikube docker-env | Invoke-Expression
, для linux eval $(minikube docker-env)
. Это позволит создавать docker images напрямую в minikube.
Создадим docker image:
docker build -t agones-go:modified -f .\examples\simple-udp\Dockerfile .
Эта команда может занять некоторое время, так как весь репозиторий проекта будет копироваться в image. Этого можно избежать, если в директории оставить только папку sdks, файл main.go и Dockerfile.
Далее в examples\simple-udp\gameserver.yaml изменим строку 28 на image: agones-go:modified
и создадим новый GameServer:
kubectl create -f .\examples\simple-udp\gameserver.yaml
Проверим изменения и выключим сервер:
echo "hello" | nc -u 172.17.113.72 7331
echo "EXIT" | nc -u 172.17.113.72 7331
Если после запуска команд в консоли появится ответ "ACKNOWLEDGED: hello", то внесенные изменения прошли успешно.
Запускаем сервер локально
Итерировать изменения для удобной разработки можно и без Kubernetes, используя только Agones SDK. Во время работы игрового сервера SDK общается через TCP с маленьким gRPC сервером, который Agones запускает в контейнере под тем же namespace. Такой контейнер в Kubernetes называется sidecar. Поэтому, для локальной разработки необходимо запустить процесс SDK. Для этого потребуется запустить его исходный файл с параметром -local
, который включает режим 'local mode'. Этот режим говорит процессу быть в пассивном режиме и никуда не подсоединяться, только лишь выводить логи в консоль, чтобы можно было видеть, что делает SDK во время работы игрового сервера.
Скачать последний agonessdk-server можно в релизах официального репозитория проекта. По умолчанию, после запуска SDK сервера создается болванка конфигурации GameServer, которая используется для GameServer() и WatchGameServer() SDK запросов. При запуске можно указать и собственный конфигурационный файл в формате yaml или json, для этого потребуется параметр -file
или его сокращенная версия -f
вместе с параметром -local
.
.\sdk-server --local -f .\examples\simple-udp\gameserver.yaml
sdk-server : {"ctlConf":{"Address":"localhost","IsLocal":true,"LocalFile":".\\examples\\simple-udp\\gameserver.yaml","Timeout":0,"Test":""},"grpcPor
t":59357,"httpPort":59358,"message":"Starting sdk sidecar","severity":"info","source":"main","time":"2019-09-29T12:45:59.8379817+02:00","version":"1.0.0"}
{"filePath":"C:\\agones-release-1.0.0\\examples\\simple-udp\\gameserver.yaml","message":"Reading GameServer
configuration","severity":"info","time":"2019-09-29T12:45:59.8479789+02:00"}
{"message":"Starting SDKServer grpc service...","severity":"info","source":"main","time":"2019-09-29T12:45:59.8529791+02:00"}
{"message":"Starting SDKServer grpc-gateway...","severity":"info","source":"main","time":"2019-09-29T12:46:00.1555756+02:00"}
Продолжение следует...