Skip to main content

Deploy Gameservers

“Hello World” of OKG

You can use GameServerSet to deploy game servers. A simple deployment case is as follows:

cat <<EOF | kubectl apply -f -
apiVersion: game.kruise.io/v1alpha1
kind: GameServerSet
metadata:
name: minecraft
namespace: default
spec:
replicas: 3
updateStrategy:
rollingUpdate:
podUpdatePolicy: InPlaceIfPossible
gameServerTemplate:
spec:
containers:
- image: registry.cn-hangzhou.aliyuncs.com/acs/minecraft-demo:1.12.2
name: minecraft
EOF

After the GameServerSet is created, three game servers and three corresponding pods appear in the cluster, because the specified number of replicas is 3.

kubectl get gss
NAME AGE
minecraft 9s

kubectl get gs
NAME STATE OPSSTATE DP UP AGE
minecraft-0 Ready None 0 0 10s
minecraft-1 Ready None 0 0 10s
minecraft-2 Ready None 0 0 10s

kubectl get pod
NAME READY STATUS RESTARTS AGE
minecraft-0 1/1 Running 0 10s
minecraft-1 1/1 Running 0 10s
minecraft-2 1/1 Running 0 10s

ID awareness

Due to the stateful nature of game servers, they usually need unique identifiers to distinguish each other. This is why the name of the GameServer managed by GameServerSet ends with an ID number.

In some cases, the game server business itself needs to be aware of its own ID, which can be used as a regional server attribute mark or a basis for configuration management. At this time, the corresponding identification ID can be sunk into the container through DownwardAPI. Here's an example:

Deploy a GameServerSet, and the environment variable GS_NAME in the generated game server container will have the corresponding name as its value:

apiVersion: game.kruise.io/v1alpha1
kind: GameServerSet
metadata:
name: minecraft
namespace: default
spec:
replicas: 3
updateStrategy:
rollingUpdate:
podUpdatePolicy: InPlaceIfPossible
gameServerTemplate:
spec:
containers:
- image: registry.cn-hangzhou.aliyuncs.com/acs/minecraft-demo:1.12.2
name: minecraft
env:
- name: GS_NAME
valueFrom:
fieldRef:
fieldPath: metadata.name

3 game servers will be generated:

kubectl get gs
NAME STATE OPSSTATE DP UP AGE
minecraft-0 Ready None 0 0 31s
minecraft-1 Ready None 0 0 31s
minecraft-2 Ready None 0 0 31s

Check the GS_NAME environment variables of these three game servers separately and find that the GS_NAME of the three game servers corresponds to their own names.

kubectl exec  minecraft-0 -- env | grep GS_NAME
GS_NAME=minecraft-0

kubectl exec minecraft-1 -- env | grep GS_NAME
GS_NAME=minecraft-1

kubectl exec minecraft-2 -- env | grep GS_NAME
GS_NAME=minecraft-2

In this way, the game program can perform configuration management and other operations by parsing the GS_NAME environment variable when it is started.

Service discovery of game server stateful instances

Due to the stateful nature of game servers, access often requires specific pod instances, and the load balancing features of traditional k8s services cannot be used. OKG supports the DNS mechanism of stateful services to achieve interactive access between game servers within the cluster.

The following example will involve two services, the minecraft game server and the accessor. Minecraft is called by the accessor.

Service registration

Normally, when a game server needs to be accessed internally, it needs to register its own information with the corresponding service so that the accessor can know which pods are accessible; correspondingly, when the game server exits, it also needs corresponding structural actions, such as deregistration. The accessor knows that the pod no longer provides services.

As mentioned earlier, the only identifier of the game server is its ID (or name). Use the DownwardAPI mentioned above to sink GS_NAME into the container, and then register it with the corresponding service when the container starts.

After the Yaml deployment is completed according to the previous article, there are 3 minecraft pods in the cluster:

kubectl get po -owide
...
minecraft-0 1/1 Running 0 10s 172.16.0.64 xxx <none> 2/2
minecraft-1 1/1 Running 0 10s 172.16.0.6 xxx <none> 2/2
minecraft-2 1/1 Running 0 10s 172.16.0.12 xxx <none> 2/2

DNS

In order to enable the pod of the game server to be accessed individually, in addition to deploying GameServerSet, it is also necessary to deploy a headless service with the same name as GameServerSet. In this example, its Yaml is as follows:

apiVersion: v1
kind: Service
metadata:
name: minecraft
spec:
clusterIP: None
selector:
game.kruise.io/owner-gss: minecraft # Fill in the name of GameServerSet

Deploy a simple accessor Yaml to access the corresponding minecraft pod within the container

apiVersion: game.kruise.io/v1alpha1
kind: GameServerSet
metadata:
name: accessor
namespace: default
spec:
replicas: 1
gameServerTemplate:
spec:
containers:
- image: busybox
name: accessor
args:
- sleep
- "3600"
command: ["/bin/sh", "-c", "sleep 3600"]

Enter the accessor container and ping the corresponding minecraft pod (this step simulates the access logic in the real environment. Of course, choosing which pod to access requires certain filtering rules):

kubectl exec -it accessor-0 /bin/sh
/ #
/ # ping minecraft-2.minecraft.default.svc.cluster.local
PING minecraft-2.minecraft.default.svc.cluster.local (172.16.0.12): 56 data bytes
64 bytes from 172.16.0.12: seq=0 ttl=63 time=0.082 ms
64 bytes from 172.16.0.12: seq=1 ttl=63 time=0.061 ms
64 bytes from 172.16.0.12: seq=2 ttl=63 time=0.072 ms

It can be found that the accessor successfully accessed minecraft-2, and the DNS successfully resolved to the corresponding intranet IP address. The DNS rules here are as follows: {pod-name}.{gss-name}.{namespace-name}.svc.cluster.local