Skip to content

Commit

Permalink
more docs work
Browse files Browse the repository at this point in the history
  • Loading branch information
dgkanatsios committed Jul 22, 2022
1 parent 52e2e22 commit d5d076a
Show file tree
Hide file tree
Showing 13 changed files with 88 additions and 41 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Thundernetes makes it easy to run your game servers on Kubernetes.

## ℹ️ Description

Thundernetes is a project originating from the [Azure PlayFab Multiplayer Servers (MPS)](https://docs.microsoft.com/gaming/playfab/features/multiplayer/servers/) team and other teams in Azure/XBOX that enables you to run both Windows and Linux game servers on your Kubernetes cluster. Thundernetes can be useful in the following scenarios:
Thundernetes is a project originating from the [Azure PlayFab Multiplayer Servers (MPS)](https://docs.microsoft.com/gaming/playfab/features/multiplayer/servers/) team and other teams in Azure/XBOX that enables you to run Windows and Linux game servers on your Kubernetes cluster. Thundernetes can be useful in the following scenarios:

- host your game servers on a Kubernetes cluster, either on a public cloud provider or on-premise and allow your users to connect from everywhere
- pre-warm game servers so that they are ready to accept players within seconds, when the game is about to start
Expand Down
24 changes: 23 additions & 1 deletion docs/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,10 +8,27 @@ permalink: /

# Thundernetes

Welcome to Thundernetes, an open source project from Azure/XBOX teams that enables you to run Windows and Linux game servers on your Kubernetes cluster!
Welcome to Thundernetes, an open source project that allows you to run your game servers on a Kubernetes cluster!

:exclamation: Latest release: [![GitHub release](https://img.shields.io/github/release/playfab/thundernetes.svg)](https://github.com/playfab/thundernetes/releases)

## Description

Thundernetes is a project originating from the [Azure PlayFab Multiplayer Servers](https://docs.microsoft.com/gaming/playfab/features/multiplayer/servers/) team and other teams in Azure/XBOX that enables you to run both Windows and Linux game servers on your Kubernetes cluster. Thundernetes can be useful in the following scenarios:

- host your game servers on a Kubernetes cluster, either on a public cloud provider or on-premise and allow your users to connect from everywhere
- pre-warm game servers so that they are ready to accept players within seconds, when the game is about to start
- as part of your iterative development process, you can use Thundernetes locally to test your game server code

Thundernetes offers:

- game server auto-scaling enabled by default, based on [requested standingBy levels](./gameserverbuild.md)
- a [latency server](./howtos/latencyserver.md) to test client connection to multiple Kubernetes cluster and determine the best cluster to connect to
- a [Game Server SDK](./gsdk/README.md) in multiple languages/environments (Unity, Unreal, C#, C++, Java, Go) and a [local utility](./gsdk/runlocalmultiplayeragent.md) to test your game server integration locally
- a [web-based User Interface](./thundernetesui/README.md) to manage Thundernetes deployments in multiple clusters. This component utilizes a [REST API](./gameserverapi/README.md) which you can use to manage your game servers
- an experimental [intelligent standingBy server count forecaster](./howtos/intelligentscaling.md) that utilizes various algorithms to predict the number of game servers that will be needed
- [game server related Prometheus metrics and Grafana charts](./howtos/monitoring.md)

## Prerequisite knowledge

New to Kubernetes or containers? Check our [prerequisites](prerequisites.md) document that has resources that will fill the knowledge gaps when working with technologies within Thundernetes.
Expand All @@ -35,6 +52,11 @@ Check the following image to see how easy it is to install and use Thundernetes:

[![asciicast](https://asciinema.org/a/438455.svg)](https://asciinema.org/a/438455)

For a video presentation, check:

[![What is Project Thundernetes? How Kubernetes Helps Games Scale](https://img.youtube.com/vi/zwnUfq1ygic/0.jpg)](https://www.youtube.com/watch?v=zwnUfq1ygic)


## Contributing

If you are interested in contributing to Thundernetes, please read our [Contributing Guide](contributing.md) and open a PR. We'd be more than happy to help you out!
38 changes: 17 additions & 21 deletions docs/gameserverbuild.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,9 +6,20 @@ nav_order: 7

# GameServerBuild definition

GameServerBuild defines the specification and auto-scaling configuration of the GameServers that you want to run in the cluster. Each version of your game server should have its own GameServerBuild.
GameServerBuild defines the specification and auto-scaling configuration of a specific version of your GameServers that you want to run in the cluster. Each version of your game server should have its own GameServerBuild.

Here you can see the YAML that can be used to create a GameServerBuild in Thundernetes. The only fields that you should change after the GameServerBuild is created are the *standingBy* and the *max* ones. The other fields should be considered immutable.
You need to specify these properties in your GameServerBuild YAML file:

- `titleID`: this is a unique string for your game, in case you want to host multiple games in the same cluster
- `buildID`: this is a unique identifier (GUID) for the specific version of your game server
- `standingBy`: this is a key property for the auto-scaling feature. A server in the `standingBy` state is a server that has loaded all the necessary assets and configuration and is ready to accept players. Thundernetes will always try to keep this number of servers in the `standingBy` state, always respecting the `max` threshold (see below). For more information on the game server states, check the [Game Server lifecycle](./gsdk/gameserverlifecycle.md) document.
- `max`: this is the maximum number of servers in all states. The sum of game servers in `initializing` + `standingBy` + `active` states will never be beyong the `max`, for each GameServerBuild.
- `buildMetadata`: an optional array of key/value pair strings that you can access from your game server process using the [Game Server SDK](./gsdk/README.md)
- `portsToExpose`: in this field you define which ports of your Pod will be exposed outside the cluster. Read on for more details.
- `crashesToMarkUnhealthy`: **optional but highly recommended**, this is the threshold for the number of crashes that will trigger your GameServerBuild to become `Unhealthy`. Read on for more details.
- `template`: this is the specification of [your game server pod](https://kubernetes.io/docs/concepts/workloads/pods/). You should include here whatever is needed for your game server to run (environment variables, storage, etc).

Here you can see a sample YAML file:

```yaml
apiVersion: mps.playfab.com/v1alpha1
Expand All @@ -19,7 +30,7 @@ spec:
titleID: "1E03" # required, corresponds to a unique ID for your game. Can be an arbitrary string
buildID: "85ffe8da-c82f-4035-86c5-9d2b5f42d6f5" # required, build ID of your game, must be GUID. Will be used for allocations, must be unique for each Build/version of your game server
standingBy: 2 # required, number of standing by servers to create
max: 4 # required, max number of servers to create. Sum of active+standingBy servers will never be larger than max
max: 4 # required, max number of servers to create. Sum of active+standingBy+initializing servers will never be larger than max
crashesToMarkUnhealthy: 5 # optional. It is the number of crashes needed to mark the GameServerBuild unhealthy. Once this happens, no other operation will take place. If it is not set, Thundernetes will keep creating new GameServers as the old ones crash
buildMetadata: # optional. Retrievable via GSDK, used to customize your game server
- key: "buildMetadataKey1"
Expand All @@ -38,7 +49,7 @@ spec:
name: gameport # name of the port that you want to expose.
```
The template.spec contains the definition for a [Kubernetes Pod](https://kubernetes.io/docs/concepts/workloads/pods/). As a result, you should include here whatever is needed for your game server to run (environment variables, storage, etc).
In general, the only fields that you should change after the GameServerBuild is created are the standingBy and the max ones. The other fields should be considered immutable.
## PortsToExpose
Expand All @@ -56,24 +67,9 @@ CrashesToMarkUnhealthy (integer) is the number of crashes that will transition t

Be very careful if you decided to remove the CrashesToMarkUnhealthy field. If you remove it, the GameServerBuild will never be marked as Unhealthy, no matter how many crashes it has. This might have the negative impact on Thundernetes constantly creating GameServers to replace the ones that have crashed. For this reason, we always recommend to set the CrashesToMarkUnhealthy field using a value that makes sense for your game/environment.

## Using host networking

Thundernetes supports running your GameServer Pods with host networking. To do that, you need to provide a GameServerBuild YAML like [this](https://github.com/playfab/thundernetes/tree/main/samples/netcore/sample-hostnetwork.yaml), setting the `hostNetwork` value to true on PodSpec template. During Pod creation, Thundernetes controllers will **override** the containerPort with the same value that will be assigned in the hostPort.

You **have to** use the generated port when you instantiate your game server process. To grab the port number, you should use the [GSDK](gsdk/README.md) `GetGameServerConnectionInfo` method.

```csharp
string ListeningPortKey = "gameport";
var gameServerConnectionInfo = GameserverSDK.GetGameServerConnectionInfo();
var portInfo = gameServerConnectionInfo.GamePortsConfiguration.Where(x=>x.Name == ListeningPortKey);
if(portInfo.Count() == 0)
{
throw new Exception("No port info found for " + ListeningPortKey);
}
var port = portInfo.Single().ServerListeningPort;
```
## Host Networking

> _**NOTE**_: It is necessary to provide a `containerPort` value in the GameServerBuild YAML, since it is required for GameServerBuild validation (specifically, the way the PodTemplate is validated from Kubernetes). However, as mentioned, this provided value is not used since it's overwritten by the `hostPort` value.
Thundernetes supports Kubernetes host networking (i.e. using the Node's network namespace), check the [host networking document](./howtos/hostnetworking.md) for more information.

## Game server image upgrades

Expand Down
2 changes: 1 addition & 1 deletion docs/gsdk/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ To integrate with GSDK, follow the guide for the programming language/environmen
- [Unreal GSDK](unreal.md)
- [C#/C++/Java GSDK](csharpcppjava.md)

> **_NOTE_**: For experimenting with Thundernetes, you can use our [wrapper sample](../howtos/usingwrapper.md). This sample takes care of calling the GSDK for you and launching your game server as a separate process.
> **_NOTE_**: For experimenting with Thundernetes, you can use our [wrapper sample](../howtos/usingwrapper.md). This sample takes care of calling the GSDK for you and launching your game server as a separate process. Generally, not recommended for production workloads.
## Run your game server on Thundernetes

Expand Down
4 changes: 1 addition & 3 deletions docs/gsdk/csharpcppjava.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,4 @@ You can find the GSDK libraries for each language here:

In all these programming languages, you need to include the GSDK libraries in your project and call the `Start()` and `ReadyForPlayers()` methods. `Start` will signal to Thundernetes that the game server is initializing whereas `ReadyForPlayers` will signal that the game server is ready for players to connect.

#### Testing with LocalMultiplayerAgent

You can use [LocalMultiplayerAgent](runlocalmultiplayeragent.md) to test your GSDK integration of your game server before uploading to Thundernetes.
{% include_relative gsdkfooter.md %}
12 changes: 12 additions & 0 deletions docs/gsdk/gsdkfooter.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
### Other GSDK methods and callbacks

There are some other GSDK methods you can use from your game server process:

- `GetGameServerConnectionInfo`: Returns the connection information for the GameServer. Usually, it should be the port that you have already defined in your Pod specification. It is **required** use this method if you want to use the [hostNetwork](../howtos/hostnetworking.md) option.
- `GetInitialPlayers`: Returns the IDs of the players that are expected to connect to the GameServer when it starts. It is set during the call to [the allocation service API](../quickstart/allocation-scaling.md).
- `UpdateConnectedPlayers`: It updates the currently connected players to the GameServer. On the backend, Thundernetes updates the `GameServerDetail` Custom Resource with the new number and IDs of connected players.
- `GetConfigSettings`: Returns the current configuration settings for the GameServer. You can retrieve the [associated GameServerBuild metadata](../gameserverbuild.md) with this method.

### Testing with LocalMultiplayerAgent

You can use [LocalMultiplayerAgent](runlocalmultiplayeragent.md) to test your GSDK integration of your game server before uploading to Thundernetes.
4 changes: 1 addition & 3 deletions docs/gsdk/unity.md
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,4 @@ CMD ["/game/UnityServer.x86_64", "-nographics", "-batchmode", "-logfile"]

For a more robust sample integrating Unity with the popular [Mirror](https://mirror-networking.com/) networking library, check the `MpsSamples` repository [here](https://github.com/PlayFab/MpsSamples/tree/main/UnityMirror).

#### Testing with LocalMultiplayerAgent

You can use [LocalMultiplayerAgent](runlocalmultiplayeragent.md) to test your GSDK integration of your game server before uploading to Thundernetes.
{% include_relative gsdkfooter.md %}
4 changes: 1 addition & 3 deletions docs/gsdk/unreal.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,4 @@ CMD su ue -c ./ShooterServer.sh

Check [this guide](https://github.com/PlayFab/MpsSamples/tree/main/UnrealThirdPersonMP) on how to integrate the [Unreal Third Person template](https://docs.unrealengine.com/4.27/en-US/Resources/Templates/ThirdPerson/) with the Unreal GSDK.

#### Testing with LocalMultiplayerAgent

You can use [LocalMultiplayerAgent](runlocalmultiplayeragent.md) to test your GSDK integration of your game server before uploading to Thundernetes.
{% include_relative gsdkfooter.md %}
25 changes: 25 additions & 0 deletions docs/howtos/hostnetworking.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
---
layout: default
title: Host Networking
parent: How to's
nav_order: 6
---

# Host Networking

Thundernetes supports running your GameServer Pods with host networking. To do that, you need to provide a GameServerBuild YAML like [this](https://github.com/playfab/thundernetes/tree/main/samples/netcore/sample-hostnetwork.yaml), setting the `hostNetwork` value to true on PodSpec template. During Pod creation, Thundernetes controllers will **override** the containerPort with the same value that will be assigned in the hostPort.

You **have to** use the generated port when you instantiate your game server process. To grab the port number, you should use the [GSDK](gsdk/README.md) `GetGameServerConnectionInfo` method.

```csharp
string ListeningPortKey = "gameport";
var gameServerConnectionInfo = GameserverSDK.GetGameServerConnectionInfo();
var portInfo = gameServerConnectionInfo.GamePortsConfiguration.Where(x=>x.Name == ListeningPortKey);
if(portInfo.Count() == 0)
{
throw new Exception("No port info found for " + ListeningPortKey);
}
var port = portInfo.Single().ServerListeningPort;
```

> _**NOTE**_: It is necessary to provide a `containerPort` value in the GameServerBuild YAML, since it is required for GameServerBuild validation (specifically, the way the PodTemplate is validated from Kubernetes). However, as mentioned, this provided value is not used since it's overwritten by the `hostPort` value.
2 changes: 0 additions & 2 deletions docs/prerequisites.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,6 @@ Kubernetes is built on top of Docker to run containers at scale across many mach

## Game Servers 👾

Thundernetes is a preview project from teams from Azure and Xbox that enables you to run Linux game servers that use the open source Azure PlayFab Game Server SDK (GSDK) on your Kubernetes cluster.

- [Integrating Game Servers with Game Server SDK (GSDK)](https://docs.microsoft.com/gaming/playfab/features/multiplayer/servers/integrating-game-servers-with-gsdk)
- [Azure PlayFab Game Server SDK](https://github.com/PlayFab/gsdk)

Expand Down
4 changes: 2 additions & 2 deletions docs/troubleshooting/controllernodeagent.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
---
layout: default
title: Controller/NodeAgent status
title: Controller/NodeAgent logs
parent: Troubleshooting
nav_order: 4
---

# How can I get access to the controller and the NodeAgent status and logs?
# How can I get access to the controller and the NodeAgent logs and status?

Thundernetes controller Pod and NodeAgent Pods are installed in the `thundernetes-system` namespace by default.

Expand Down
2 changes: 1 addition & 1 deletion docs/troubleshooting/stuckgameserver.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ nav_order: 2

# What should we do if a GameServer gets stuck?

Sometimes the GameServer process might not responding, due to a programming bug or a misconfiguration. You can check the logs by using the command ```kubectl logs <Name>``` and running a command shell into the Pod with ```kubectl exec -it <Name> -- sh```. It might be useful to also check the NodeAgent logs for the Node that this Pod is running on, check [here](controllernodeagent.md) for more information.
Sometimes the GameServer process might not responding, due to a programming bug or a misconfiguration. You can check the logs by using the command ```kubectl logs <Name>``` and running a command shell into the Pod with ```kubectl exec -it <Name> -- sh```. It might be useful to also check the NodeAgent logs for the Node that this Pod is running on, to see potential issues on GameServer and NodeAgent communication. You can check [our guide on how to get access to the NodeAgent logs](controllernodeagent.md) for more information.

If you want to delete the Pod, you can use the kubectl command ```kubectl delete gs <Name>``` since this will take down both the GameServer instance, the corresponding Pod as well as the GameServerDetail CR instance (in case the game server was allocated).

Expand Down
6 changes: 3 additions & 3 deletions docs/troubleshooting/stuckinitializing.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,12 @@ nav_order: 3

# My GameServer state stays in empty or Initializing state and does not transition into StandingBy

> Check [here](../gameserverlifecycle.md) for more information on GameServer lifecycle.
Check [here](../gameserverlifecycle.md) for more information on GameServer lifecycle.

> You can check for the state of your GameServer by typing `kubectl get gs`
You can check for the state of your GameServer by typing `kubectl get gs <gsName>` or `kubectl describe gs <gsName>`

You might see your GameServer stuck in the `Initializing` state (or in the empty state) and not transitioning to `StandingBy`. This can be a problem since eventually this GameServer cannot be allocated (converted to Active). Thundernetes only looks for `StandingBy` servers when looking for a GameServer to allocate.

If the GameServer state is empty, tou should check if a corresponding Pod has been created for this GameServer. Pods have the same name and are created in the same namespace as their corresponding GameServer so they are easy to locate. Try `kubectl get gs` to see the GameServer name, then use `kubectl get pod` to see if there is a Pod with same name as the GameServer. You can use `kubectl get pod` to see the high-level status of the Pod. Try running `kubectl logs <podName>` to see logs from your game server process. Also, try running `kubectl describe pod` to see the status of the Pod. Check there for some obvious failures, like failure to access the container registry, Pod creation failure because of resource constraints, etc. You can also try `kubectl exec -it <podName> -- sh` to open a shell in the game server Pod and investigate.

If everything looks OK, then probably there is an issue with the GSDK integration of your GameServer. You should take a look at [LocalMultiplayerAgent](../howtos/runlocalmultiplayeragent.md) to see how to run/test your GameServer locally and test its GSDK integration.
If everything looks OK, then probably there is an issue with the GSDK integration of your GameServer. You should take a look at [LocalMultiplayerAgent](../gsdk/runlocalmultiplayeragent.md) to see how to run/test your GameServer locally and test its GSDK integration.

0 comments on commit d5d076a

Please sign in to comment.