Your First Cluster
In this chapter, you'll create your first Minecraft Cluster. It is based on the "Getting Started" example available on GitHub.
Creating your tutorial environment
For you to clean the resources created during this tutorial, we will first create a Kubernetes namespace to hold our resources:
$ kubectl create ns shulker-tutorial
At the end of this tutorial, the cleaning will be as simple as deleting the namespace.
A spoon of MinecraftCluster
Everything starts by creating a MinecraftCluster
. As described in the Architecture chapter, it is the most important entity because it is referenced in many other resources.
Create a cluster.yaml
file containing the following:
apiVersion: shulkermc.io/v1alpha1
kind: MinecraftCluster
metadata:
name: getting-started
spec: {}
And then apply this file:
$ kubectl apply -f cluster.yaml -n shulker-tutorial
After this, the Shulker Operator should have started some work but nothing really visible: no Pods are created yet. However, we are now ready for the main course.
A drizzle of Proxy
For the players to be able to connect to our Minecraft Cluster, we need at least one Proxy. So let's create a ProxyFleet
. It will handle replication among other things, but more importantly, it will create and bind a Kubernetes Service for us, with the LoadBalancer
type by default.
INFO
Each ProxyDeployment has its own, dedicated Service. This allows you to have a bunch of "public" proxies for your players while having a separate entrypoint for privileged players (like a staff, etc...).
Create a proxy.yaml
file containing the following:
apiVersion: shulkermc.io/v1alpha1
kind: ProxyFleet
metadata:
name: public
spec:
clusterRef:
name: getting-started
replicas: 1
service:
type: LoadBalancer
externalTrafficPolicy: Local
template:
spec:
version:
channel: Velocity
name: latest
config: {}
And then apply this file:
$ kubectl apply -f proxy.yaml -n shulker-tutorial
You'll soon start to see a public-xxx-xxx
Pod being scheduled. Wait a little bit for it to be ready. If you look at the logs of this Pod, you'll probably see some lines like this:
[io.shulkermc.serveragent.BootstrapPlugin]: Identified Shulker proxy: shulker-tutorial/public-xxx-xxx
[io.fabric8.kubernetes.client.dsl.internal.VersionUsageUtils]: The client is using resource type 'proxies' with unstable version 'v1alpha1'
[io.shulkermc.serveragent.BootstrapPlugin]: Proxy will be force stopped in 86400 seconds
[io.fabric8.kubernetes.client.dsl.internal.VersionUsageUtils]: The client is using resource type 'minecraftservers' with unstable version 'v1alpha1'
This is due to Shulker injecting automatically an agent plugin to handle some work that cannot be only done from the infrastructure.
INFO
You probably question yourself about the log line indicating that the proxy will be force stopped after some time. Due to players being constantly connected to the proxies, updating them is hard because the only way of doing it is by rebooting it, causing players to disconnect without any way to recover them (at least on Minecraft: Java Edition).
After a fixed amount of time, a proxy will enter the Drain mode, meaning that Kubernetes will exclude this proxy from the Service. This will prevent any new player from connecting to this proxy allowing it to be drained step by step (considering the players will deconnect after some play time).
The proxy will check that it is empty every 30 seconds, if there is no player, it will shutdown itself, otherwise it will wait.
It is important to note that a new Proxy is automatically created when one enters the Drain mode, to ensure the availability of the ProxyFleet.
While you read the block above, your Kubernetes Cluster should already have created a LoadBalancer
Service. If you add the IP to the game's server list, you should see an output similar to the following:
However, if you try to connect, you'll be kicked out with the following error:
By default, the Shulker Agent will try to connect the player to the first server with the lobby
tag. If none are found the agent will try to fallback on a server with the limbo
tag. Because there is no server currently running in the cluster, there is no other choice than kicking the player.
A pinch of MinecraftServer
The concept is more or less the same as for a Proxy, except that no Kubernetes Service is created because the only entrypoints are the Proxies.
Create a minecraftserver.yaml
file containing the following:
apiVersion: shulkermc.io/v1alpha1
kind: MinecraftServerFleet
metadata:
name: lobby
spec:
clusterRef:
name: getting-started
replicas: 1
template:
spec:
clusterRef:
name: getting-started
tags:
- lobby
version:
channel: Paper
name: '1.20.2'
config: {}
And then apply this file:
$ kubectl apply -f minecraftserver.yaml -n shulker-tutorial
A new Pod representing the MinecraftServer will be created. After a short period, the Pod will be marked as healthy. If you look back to the Proxy's logs, you'll see that the Shulker Agent registered automatically the server into its server list:
[io.shulkermc.serveragent.BootstrapPlugin]: Registering server 'limbo-xxx-xxx' to directory
Finally, without any surprise, if you retry to connect to the proxy, you'll arrive on the server you just created:
TIP
Pay attention to the tags
field of the MinecraftServer resource you just created. The Shulker Agent will connect the player to the first server it finds with the lobby
tag. If none, it will try to fallback on one with the limbo
tag. It is optional to provide tags to servers. They could, however, be retrieved using Shulker's Proxy API.
Congratulations! You have successfully created your first Minecraft Cluster using Shulker!
Cleaning everything up
Deleting the three resources you created will destroy all the resources created by Shulker under the hood:
$ kubectl delete -f minecraftserver.yaml
$ kubectl delete -f proxy.yaml
$ kubectl delete -f cluster.yaml
If you created a namespace dedicated to this tutorial, you can simply delete it without bothering deleting the resources one-by-one:
$ kubectl delete ns shulker-tutorial
TIP
The command could block some seconds/minutes during the deletion of all the resources contained in the namespace.