Contents

Getting started with AKS the fun way.


Learning about Kubernetes/AKS the fun way.

1 Introduction:

Getting started with Kubernetes can be a little bit overwhelming and specially if you want to start deploying something that makes use of multiple features and services at the same time. To change things up a bit and instead of deploying a basic Hello World app which you can find many under Azure’s documentation, I’ll be guiding you on how to set up something a bit more… fun, a Minecraft Server running on Azure Kubernetes Service (AKS) as well as using a File Share to keep your files handy for quick and easy access.

You can find different guides on how to set up a Minecraft Server online, as well as steps on how to run this on many different platforms. In case you haven’t noticed, this guide is a bit long but it’s because I have tried to explain everything in detail for beginners, after all the purpose of this guide is to help you learn along the way and have some additional fun afterwards. If you are already experienced with AKS and are just looking for my configuration script and the deployment yaml head over to https://github.com/pecrow/minecraft-container-scripts .

I’ve been running a Minecraft server for about 6 months that I share with a few of my friends. Doing so does required constant maintenance to update the server when a new version gets released and it would get in the way of play sessions, so I’ve automated this task and decided to share my Minecraft scripts as well as share some basic Kubernetes knowledge.

I had fun setting this up and writing this guide and I hope you enjoy too. Let’s get started.

2 This guide will show you how to

  • Create an AKS Cluster (as well as a more cost effective one.)
  • Create a Storage Account and a File Share to be mounted by your Container.
  • Prepare a deployment yaml file with all the configurations required.
  • Additional tips and basic information on Azure and the features we are going to use.
Note
This guide will not show you how to use docker to pull/modify/tag/push container images simply due to the nature of the setup and my scripts. A default Ubuntu image from docker hub will be used in this guide meaning that you can choose between different (Debian based) release versions if needed as most should work. Stay tunned for upcoming guides with Docker, Azure Container Instances, and Azure Container Registries.

3 Requirements

  • This will all be running on Azure so if you don’t have an account or subscription, you can set up a free trial here https://azure.microsoft.com/en-us/free/ which includes $200 limit for 30 days.

  • We will be using Cloud Shell for our deployments; you can set it up by reviewing the steps below (quick): https://docs.microsoft.com/en-us/azure/cloud-shell/quickstart

  • Before you can create an AKS cluster, you need to register the AKS Resource Provider under your subscription. Run the command below via Cloud Shell before you continue as this will take some time to register (around 15-20 minutes). It should give you enough time to read over the entire document the first time before starting to copy and paste commands, just like any good engineer would do… right?

1
az provider register --namespace 'Microsoft.ContainerService'

4 Creating an AKS cluster

The first thing we are going to do is create the Resource Group for our cluster and specify an Azure Region. In this example I’ll be using the ‘EastUS’ region mainly because the VM SKU that we’ll be using in this guide is Standard_B2s, which might not be available on other regions during the Trial period. Open Cloud Shell and use below command to create the resource group:

1
az group create --name MyResourceGroup --location eastus

The result should look something like this:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
alfredo@Azure:~$ az group create --name MyResourceGroup --location eastus
{
  "id": "/subscriptions/4e1xxxxxxx-xxxx-xxxx-xxxxxxx9b7061/resourceGroups/MyResourceGroup",
  "location": " eastus ",
  "managedBy": null,
  "name": "MyResourceGroup",
  "properties": {
    "provisioningState": "Succeeded"
  },
  "tags": null,
  "type": "Microsoft.Resources/resourceGroups"
}
alfredo@Azure:~$

If you are not looking to reduce costs and just want to deploy the AKS cluster simply run below command via cloud shell and move to the next step which guides to you create a Storage Account. Feel free to modify the cluster/resource group names below. Resource group must match the one you created above. If you did not already enable the Resource Provider under the Requirements section, please do so before running this command.

1
az aks create -n MyAKS -g MyResourceGroup --node-count 1 --node-vm-size Standard_B2s --generate-ssh-keys 

4.1 Low cost AKS cluster (This step is out of date)

Update

Azure has updated the AKS creation process allowing you to choose a low cost option. This section is no longer recommended.

Azure has added a cost based option menu when creating a new AKS cluster. This allows you to deploy one with use and cost in mind. Below is an example image of how it looks.

/aks-minecraft-server/aks-cost.png
New Cost Options

This next section describes how to create a low cost AKS cluster. I’ve added this in this guide simply because I did not find anything similar when I was searching for tips on creating a cheap AKS cluster.

Here are a few examples on what resources are going to be modified to reduce costs, followed by the command to deploy the AKS cluster.

When you create a default AKS cluster, via the portal or CLI, you will find yourself using higher end ($) resources that can be lowered to more basic components to save some extra cash;hey! You might want to try out other services within the trial’s $200 limit. Tread lightly if you are looking to run this in Production.

Info

By default, a Standard Load Balancer is used which has a higher cost than say a Basic Load Balancer though with some limits, for example with a Basic Load Balancer you cannot have multiple Node Pools when used in AKS, you can only use Basic IP addresses, etc. The complete list of differences can be found here: https://docs.microsoft.com/en-us/azure/load-balancer/skus

The same would go for the AKS Node’s OS disk size. Unless you are using this in Production, deploying large amounts of containers, or large container images, you won’t necessarily need the default 128GB Premium SSD nor the performance that comes with it. You might want to lower it to 64GB or even 32GB in size. If you are planning on running a lot of servers you might want to go with higher SKUs for the extra disk performance. Complete disk SKU and performance details can be found here: https://docs.microsoft.com/en-us/azure/virtual-machines/disks-types#premium-ssd-size

The AKS node which runs the containers will be created as part of a Virtual Machine Scale Set (VMSS) and the size of the VM will also include costs. We’ll go with a simple one, a General purpose B2s, it has 2 vCPU and 4GB of RAM, for a cost of around $30 a month depending on the region. More VM Sizes/SKUs can be found here: https://docs.microsoft.com/en-us/azure/virtual-machines/sizes

In summary, for the cheap AKS cluster, we will be using a Basic LB, this will also use Basic IPs for our resources, a small VM SKU, and a 32GB OS Disk size for our AKS node.

Note - Updated

Basic Load Balancers will be removed in 2025.

Since we are using a ‘Basic’ LB, multiple nodepools cannot be created on the same AKS cluster. This means that if you later want to change the VM/OS disk sizes you will need to re-deploy your AKS cluster.
With a ‘Standard’ LB you can add multiple system/user nodepools at the same time with different VM/OS disk sizes and delete the older nodepools. If you want to use a Standard LB simply change ‘basic’ to ‘standard’ below. Standard is the default option if it’s not specified

  • If you did not already enable the Resource Provider under the Requirements section, please do so before you continue.

Use this command to create your “cheap” AKS cluster. Modify the cluster/resource group names in the command below:

1
az aks create -n MyAKS -g  MyResourceGroup  --node-count 1 --node-vm-size Standard_B2s --node-osdisk-size 32 --load-balancer-sku  basic  --generate-ssh-keys 

The command should display “running” for a few minutes and finally a long text showing the cluster properties when it completes.

Run below command to get your cluster credentials on Cloud Shell and check that the nodes are running.

1
2
3
az aks get-credentials --resource-group  MyResourceGroup  --name  MyAKS  

kubectl get nodes

It should look something like this:

1
2
3
4
5
6
7
alfredo@Azure:~$ az aks get-credentials --resource-group MyResourceGroup --name MyAKS
Merged "MyAKS" as current context in /home/alfredo/.kube/config

alfredo@Azure:~$ kubectl get nodes
NAME                                STATUS   ROLES   AGE     VERSION
aks-nodepool1-45778428-vmss000000   Ready    agent   7m15s   v1.21.7
alfredo@Azure:~$

5 Creating a Storage Account

The purpose of this storage account is that we’ll be creating the File Share on it where our Minecraft server files will be stored for quick and easy access by both the container as well as us via any Windows or Linux PC. This will also allow a container to be restarted/deleted without losing our Minecraft files/worlds, etc. You can also mount the file shares on Windows or Linux systems and drag/drop files as needed, which will allow for configuration changes and uploading worlds much easier. Alternate options are available for storing persistent data on virtual disks, but I prefer this method due to the nature of the application and that we will be accessing the data frequently to move files around manually.

The name of the Storage Account must be unique. Only lowercase letters and numbers. Between 3-24 characters long. You will receive a message if the account name is already taken in red letters. I’ve chosen a very creative name, ‘mystorageaccount4567’ , you will need to replace it. We can use the same resource group where we are going to keep the AKS cluster in.

1
az storage account create --name mystorageaccount4567 --resource-group MyResourceGroup

Now we are going to create the file share. We need to specify the RG and Name of the Storage account we have just created, following by the name of the file share, I’ll be using ‘sharename’ (lowercase). I’ve also selected to use the ‘TransactionOptimized’ tier which would be the best cost effective for our Minecraft Server due to the low space used and high transactions generated by Minecraft. The quota would be the quota limit in GB, 2gb is more than enough. Quotas can also be modified after creation so no need to worry too much about this value.

There are multiple Tiers that can be used for storage, but you need to consider how much data is going to be stored, if you’re going to need high performance, or even if the data is going to be accessed frequently. If you would like to see an example of the different Tiers I’ve included the image below as you can compare the cost per feature for each tier.

/aks-minecraft-server/tier.png
Image Credit: Microsoft Ignite 2019

5.1 Creating a File Share

Now to create the File Share the command is below, make sure you replace the items in Bold:

1
az storage share-rm create --resource-group MyResourceGroup --storage-account mystorageaccount4567  --name sharename  --access-tier "TransactionOptimized" --quota 2

For the container to Mount this file share we will need the Storage Account access keys. You can get these by running the following command:

1
az storage account keys list --account-name mystorageaccount4567

It should look like below. It will display two keys, you will only need one so save this output for later use.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
alfredo@Azure:~$ az storage account keys list --account-name mystorageaccount4567
[
  {
    "creationTime": "2022-01-22T19:17:34.392459+00:00",
    "keyName": "key1",
    "permissions": "FULL",
    "value": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=="
  },
  {
    "creationTime": "2022-01-22T19:17:34.392459+00:00",
    "keyName": "key2",
    "permissions": "FULL",
    "value": " xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx=="
  }
]
alfredo@Azure:~$

5.2 Uploading files to your File Share

The last change you need to do in the File Share is to upload the script file below. This script will be called by the yaml file on container deployment as this will configure the Minecraft server for the first time and/or update the Minecraft installation if it’s out of date. If the container is restarted it will check if you are on the latest version and update the files if needed.

https://github.com/pecrow/minecraft-container-scripts/blob/main/main-script.sh

Note
This script bypasses the “I Agree” checkbox for Minecraft’s End User License Agreement and Privacy Policy which is a mandatory check under https://www.minecraft.net/en-us/download/server/bedrock to download these files. By using this script you agree with both.

You can download it on your computer and upload it to the File Share as shown below.

Access your storage account, click on File Share, click on your Share Name, and select the Upload Button. Select the main-script.sh file and upload it.

/aks-minecraft-server/fileshare.png
File Share

Another way to Upload files would be to use the “Connect” button seen in the center of the image above, this will include steps for you to “Mount” the share on your local computer as a Network Drive, allowing you to drag-drop files/worlds in without any hassle or container image creation.

Under Windows for example, it would show under My Computer as a Network Drive.

/aks-minecraft-server/netdrive.png
Network Drive

Note

As noted at the start of the guide we will not be using docker in this guide, but a third method of adding files to your container without uploading them to a File Share would be to:

  • Pull an Ubuntu Image using docker.
  • Copy this script into the docker image and change the permissions to allow execution.
  • Commit, tag, and upload the image to a container registry, like ACR, and use this image for your container.
  • Modify the route of the script file on the yaml file to be executed on start.

The downside to this would be that every time you update the script and make changes to it, you need to modify the image, commit/tag, and upload to your Registry. Which is a bit more work than just having it in the share to be used by the container and never have to update the container image.

6 Configuring your deployment YAML

A YAML file is a text format used to specify data related to configuration, though it requires very specific formatting it can be used to deploy any resource under an AKS cluster. Alternate tools are also available, but this guide will only cover YAML as it’s the most basic method with out needing third party utilities.

I will guide you on creating a single YAML file which will include all the configurations needed to get our container deployed and our Minecraft server running. You could also create multiple files for every section, but by adding “- - -” (3 dashes) between the configurations we can add them all in one file as they will be seen as separate deployments. I will also use the ‘default’ namespace for this deployment, you can change it if needed, but make sure all resources are under the same namespace.

The complete file will be available here https://github.com/pecrow/minecraft-container-scripts/blob/main/minecraft.yaml , but I will describe each section below so that you can understand what each one does and what options need to be modified.

Let’s open Notepad and get started.

6.1 Base64 - Storage Key Secret

Remember the storage account keys that we saved for later use? It was for this step. We need to create a ‘Secret’ with our storage account name and key. This ‘Secret’ is the ‘key’ that will allow our container to access the storage account and mount the file share inside of the container. With out this key, the container might run, but it will not have access to the file share nor any of it’s files.

Now that we understand what a ‘Secret’ is used for, the yaml configuration and deployment won’t allow us to just copy and paste the storage account name and key in plain text. Anyone who has access to the code can just… read it and use it for any means. We will need to ‘hide’ the information and encode it as base64 as this is expected by default.

For example, below command gives us the encoded output of our storage account name and our Storage Key: (I’ve modified mine with ‘xxxxx’ In the example.)

1
2
3
echo -n 'mystorageaccount4567' | base64 

echo -n 'xxxxxxxxxxxxxxxxxxxxxxxx-Key-Goes-Here-xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' | base64 

Executing the commands above on cloud shell will look something like this:

1
2
3
4
5
6
7
alfredo@Azure:~$ echo -n 'mystorageaccount4567' | base64
xxxxxxxxxxxxxxxxxxxxxxxxx
alfredo@Azure:~$

alfredo@Azure:~$ echo -n 'xxxxxxxxxxxxxxxxxxxxxxxxxx-Key-Goes-Herexxxxxxxxxxxxxxxxxxxxxxxxxx==' | base64
xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx==
alfredo@Azure:~$

When you have the name/key encoded in base 64 we can continue.

I know what you might be thinking, well, can’t someone just decode the keys from base64, how secure is that exactly? Well… It’s not. If you are going to be publishing your code somewhere public, you will want to use an alternate method like an Azure Keyvault, or similar service, to pull your secrets from. Not something that will be covered here though.

The yaml configuration for the Secret is this one below. Modify the Storage Account name/key with your Base64 outputs of each value. Take note of the “name” that we give our Secret, as we will need this for the next configurations.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
apiVersion: v1
kind: Secret
metadata:
  name: storage-secret
  namespace: default
type: Opaque
data:
  azurestorageaccountname: xxxxxxxxxxxxxxxxxxxx==
  azurestorageaccountkey: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx==
---

6.2 Persistent Volume

Now comes the PersistentVolume configuration. This will include the details of the File Share that we are going to be using, and any special permissions that we might want for the File Share.

I’ve highlighted in bold the items we need to take note of and change:

name” This would be the name that we want to give to the PersistentVolume we are creating. “storageClassName” This is just the name of the storage class we will use for this PV, both sections need to match. “storage” Would be the capacity that we are giving to the share. You can set this the same as 2GB your quota. “secretName” This needs to match the secret name we created on the first section. “shareName” Is the name of the File Share that you created inside your Storage Account.

We also have the mountOptions section, but this will remain as I’ve left them. These are the permissions that the Mount Point will use, and I’ve configured them to use the Minecraft User ID (UID/GID)) that will get created later as well as 750 folder and file permissions.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
apiVersion: v1
kind: PersistentVolume
metadata:
  name: pvname
spec:
  storageClassName: "scname"
  capacity:
    storage: 2Gi
  accessModes:
  - ReadWriteMany
  storageClassName: scname
  mountOptions:
  - dir_mode=0750
  - file_mode=0750
  - uid=1001
  - gid=1001
  azureFile:
    secretName: storage-secret
    secretNamespace: default
    shareName: sharename
    readOnly: false
---

6.3 Persistent Volume Claim

Now we have the Persistent Volume Claim. This one will be used by our application/pod to “request” the PV and it has just a few sections that we need to look at.

name” is the name we are giving this PVC. “storageClassName” must match the same name we created above. “storage” again the 2GB limit.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: pvclaim
spec:
  accessModes:
    - ReadWriteMany
  storageClassName: "scname"
  resources:
    requests:
      storage: 2Gi
---

6.4 Minecraft Deployment

Now we have the actual application deployment; This is the Minecraft server itself.

There are multiple ‘name’ sections, for the Metadata/Labels, and ‘app’ for the labels/containers sections that all need to match. These are just for the name and labels of the deployment/pod. You can modify the name as needed, just validate that they match.

Then the sections that we need to modify are under the ‘VolumeMounts’ and ‘Volumes’. These must match the name of the File Share and the Persistent Volume Claim we had created in previous steps. The POD will use all the previous items created to complete the mount, from the Secret to the PV/PVC, etc.

There are a few other sections here that are already filled in that need to remain the same. These would be the Ubuntu image we are using provided by Docker Hub. With the configurations that we have in place both in this yaml, and the main-script.sh file, all required changes to the OS will be made to allow the Minecraft server to get deployed without us having to create a custom container image and pulling it from a Container Registry.

The commands (args) that will be executed when the container is being created. I have two commands in place. The first one is to create the user Minecraft as well as the command to execute our main-script.sh which will take care of the rest. Then we also have the ports required by Minecraft over which we are going to connect. And finally, the Mount path for the File Share that we created; this will mount our File Share under /home/Minecraft.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
apiVersion: apps/v1
kind: Deployment
metadata:
  name: minecraft-server
  labels:
    app: minecraft-server
spec:
  replicas: 1
  selector:
    matchLabels:
      app: minecraft-server
  template:
    metadata:
      labels:
        app: minecraft-server
    spec:
      containers:
      - name: minecraft-server
        image: docker.io/library/ubuntu:20.04
        command: ["/bin/sh"]
        args: ["-c", "useradd -u 1001 -m Minecraft ; sh /home/Minecraft/main-script.sh"]
        ports:
        - containerPort: 19132
        - containerPort: 19133
        volumeMounts:
        - name: sharename
          mountPath: /home/Minecraft
      volumes:
      - name: sharename
        persistentVolumeClaim:
          claimName: pvclaim
---

6.5 Load Balancer

The last one is the Load Balancer. This one will handle the Public IP that we are going to use to connect to our Minecraft server as well as route our traffic to/from the Minecraft container.

“name” would be the name for the LB service. “app” is the name of the Pod/Deployment. In this case the name given above. “loadBalancerIP” This is the Public IP that we will use to connect to Minecraft.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
apiVersion: v1
kind: Service
metadata:
  name: mine-loadbalancer
spec:
  type: LoadBalancer
  ports:
  - port: 19132
    protocol: UDP
    name: udp-19132
  - port: 19133
    protocol: UDP
    name: udp-19133
  selector:
    app: minecraft-server
  loadBalancerIP:   000.000.000.000

Since we don’t have a Public IP yet let me show you how to create a static public IP with a basic SKU (since we are using a Basic LB the IP SKU must match). The IP must be created in the same resource group as the rest of our cluster resources. In the case of AKS, the resource group of the AKS is different than the resource group created to contain all the AKS resources (VMSS, vnet, Ips, etc). You can check for the MC_ resource group name by accessing your AKS cluster and clicking on ‘Properties’:

/aks-minecraft-server/properties.png
Properties

The command to create our Public IP is below:

1
az network public-ip create --name minecraft-basic-ip --resource-group MC_MyResourceGroup_MyAKS_eastus --allocation-method Static  --sku Basic

When this completes you will receive a large output, near the top you will see the Public IP address that you will be using for your load balancer.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
alfredo@Azure:~$ az network public-ip create --name minecraft-basic-ip --resource-group MC_MyResourceGroup_MyAKS_eastus --allocation-method Static  --sku Basic
{
  "publicIp": {
    "ddosSettings": null,
    "deleteOption": null,
    "dnsSettings": null,
    "etag": "W/\"xxxxxxx-xxxxx--xxxxxxxxxxx\"",
    "extendedLocation": null,
    "id": "/subscriptions/xxxxxxxxxxxxxxxxxxxx/resourceGroups/MC_MyResourceGroup_MyAKS_eastus/providers/Microsoft.Network/publicIPAddresses/mine-basic-ip",
    "idleTimeoutInMinutes": 4,
    "ipAddress": "000.000.000.000",
    "ipConfiguration": null,

6.5 Deploy Your YAML

Now that we have all the configurations that we need, head over to Cloud Shell and create a file with this configuration. You can use nano or vi to create a file, let’s say it’s named “minecraft.yaml” and simply copy/paste the configurations that we have into the file and save it.

If you want to compare that your file looks similar, you can check the complete file I’ve created here to be used as reference: https://github.com/pecrow/minecraft-container-scripts/blob/main/minecraft.yaml

To deploy the file on your AKS cluster you simply need to run the following:

1
Kubectl apply -f minecraft.yaml

If everything goes well it should look like below:

1
2
3
4
5
6
7
alfredo@Azure:~$ kubectl apply -f minecraft.yaml
secret/storage-secret created
persistentvolume/pvname created
persistentvolumeclaim/pvclaim created
deployment.apps/minecraft-server created
service/mine-loadbalancer created
alfredo@Azure:~$

If you would like to delete the deployment and all of the services we created you can simply run below command:

1
Kubectl delete -f minecraft.yaml

What happens if you received an error when deploying?

If any typos or incorrect values are typed in the yaml file it will cause some of the deployments to fail. To find out where the error is my recommendation is to copy one section at a time to your Minecraft.yaml file and run the deployment. If it gets created with out an issue, add the second section and re-deploy. Do this for all of them until you find the one that errors out and check that you have typed everything in correctly.

6.6 View Status and Logs

If everything gets created, you can check that your pod is running and even view the logs:

Run below to list all the running pods. If you used a different namespace than Default, you need to add ‘-n namespace’ to the command otherwise it should show everything in the default namespace automatically.

1
Kubectl get pods -n namespace

Example output

1
2
3
alfredo@Azure:~$ kubectl get pods -n default
NAME                                READY   STATUS    RESTARTS   AGE
minecraft-server-777f9c8b85-jgmjz   1/1     Running   0          15h

Copy the complete name of the pod and you can check the logs by running.

1
kubectl logs <pod-name> -n <namespace>

You should see the logs of each step and at the end the Minecraft server will be started.

When you run this for the first time or if an upgrade is required, a zip file will be downloaded directly from https://www.minecraft.net/en-us/download/server/bedrock and unzipped with in your container and thus your File Share. This can take up to 20 minutes so be patient. If no updates are required, the start of the server will be around 2 minutes.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
kubectl logs minecraft-server-777f9c8b85-jgmjz
----------
Script created by https://github.com/pecrow
Complete beginners guide on AKS to be posted on https://ramirez.cr including the use of this script
You may modify/use this as needed. For Free use only, not be sold in any way. If modifying/posting elsewhere, give credit.
----------
Sun Jan 23 01:11:00 UTC 2022 - Creating required directories and files.
Sun Jan 23 01:11:00 UTC 2022 - Installing wget and unzip packages
…
… Most logs were removed from this example output.
…
[2022-01-23 01:11:13:157 INFO] Starting Server
[2022-01-23 01:11:13:157 INFO] Version 1.18.2.03
[2022-01-23 01:11:13:157 INFO] Session ID 3837e364-8ded-4441-a6c5-c5xxxxxxxx0
[2022-01-23 01:11:13:171 INFO] Level Name: Bedrock level
[2022-01-23 01:11:13:206 INFO] Game mode: 0 Survival
[2022-01-23 01:11:13:206 INFO] Difficulty: 1 EASY
[2022-01-23 01:11:22:526 INFO] opening worlds/Bedrock level/db
[2022-01-23 01:12:09:033 INFO] IPv4 supported, port: 19132
[2022-01-23 01:12:09:033 INFO] IPv6 supported, port: 19133
[2022-01-23 01:12:11:492 INFO] Server started.

You can connect to your Minecraft server via the IP address assigned to the load balancer and start playing. A default world is created and anyone can connect and play with the IP address. If you would like to upload your custom worlds, edit the server properties, permissions, white listings, check the FileShare section that will show you how to access the File Share as a Network Drive to drag and drop files as needed.

After you have updated and uploaded any desired Minecraft world/files simple restart the container to have it get re-created and running with the new configurations. To do this you can run below commands.

1
2
Kubectl get pods -n <namespace>
Kubectl delete pod <pod-name> -n <namespace>

Below are a few examples and you can also see that when one container get’s deleted a new one will automatically re-deploy. Take note of the pod name after deployment if you would like to check logs or run any other commands as these will change.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
alfredo@Azure:~$ kubectl get pods -n default
NAME                                READY   STATUS    RESTARTS   AGE
minecraft-server-777f9c8b85-jgmjz   1/1     Running   0          15h

alfredo@Azure:~$ kubectl delete pod minecraft-server-777f9c8b85-jgmjz -n default
pod "minecraft-server-777f9c8b85-jgmjz" deleted

alfredo@Azure:~$ kubectl get pods
NAME                                READY   STATUS        RESTARTS   AGE
minecraft-server-777f9c8b85-jgmjz   1/1     Terminating   0          15h
minecraft-server-777f9c8b85-sfhd2   1/1     Running       0          6s
alfredo@Azure:~$

7 CrobJobs – Minecraft Restart and Updates

There are multiple ways, and way easier, to go about frequent checks to see if there is a new Minecraft version. One quick option is to simply modify the sleep at the end of the main-script.sh file if you don’t want to set up Cronjobs, when the sleep ends the container will complete and restart; and the version check will be performed at start, but since we are learning about AKS why not learn about Crobjobs?

The main-script.sh file has been created in a way that every time the container starts, it checks if a new Minecraft version has been released, if it does not find a new version it will simply start the server as is, but if it does detect that a new version has been released under https://www.minecraft.net/en-us/download/server/bedrock it will download it, backs up your whitelist - -properties – permissions - and world files, replace the Minecraft installation, and then restore your configurations. So, the idea here is to simply re-execute the script and restarting the container one way.

A cronjob is a ‘job’ that gets executed and performs a desired task at specific times or intervals. You really could go a dozen different ways with this, but I’ll just go a simple route which is to just delete the container that is running our Minecraft Server which will automatically re-create it and re-run the script, thus updating it if an update is present or just starting the Minecraft process back up if no updates are found. You can specify the exact time and day of when to execute the job. Thinking of a time that doesn’t disrupt gameplay, maybe 5am every Thursday sounds about right for this guide.

Cronjobs are very useful and a great addition to an AKS cluster, you can use it for so many different tasks, if you run a web server for example you can set it up to rotate your ssl certificates without going a longer route; Your imagination is the limit.

Create a new file and let’s create our new yaml file.

7.1 Service Account

RBAC is enabled by default on the AKS cluster, so the first part of the Yaml file will be for us to create a Service Account. This will be the account that is given permissions to execute the container deletion. Without this the cronjob will simply not have access to delete the container. You can change the service account name below and the namespace if you did not use the default for this guide.

1
2
3
4
5
6
kind: ServiceAccount
apiVersion: v1
metadata:
  name: myserviceaccount
  namespace: default
---

7.2 Roles

The next section is to create the roles that we will need to delete the pod. The access given below is limited to this action. You can look into the Kubernetes.io’s RBAC Authorization for more examples and features here https://kubernetes.io/docs/reference/access-authn-authz/rbac/

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
  name: myroles
  namespace: default
rules:
- apiGroups: [""]
  resources:
  - namespaces
  - pods
  - cronjobs
  verbs: ["get", “list”, "delete"]
---

7.3 Role Bindings

Okay, so we have created a service account and a list of roles and to link them we create a RoleBinding, which I’ve named myrolebinding. This will assign the roles to the service account. Here we will need to add the names of the role binding and the roles that you created above, so just add them in as follows.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: myrolebinding
  namespace: default
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: myroles
subjects:
  - kind: ServiceAccount
    name: myserviceaccount
---

7.4 Cron Job

What we have created above is just the access for your cronjob, below is the cronjob itself. Here are the details for each section:

“name” specifies the name of your cronjob. “schedule” is when and how often your cronjob will execute. Azure uses UTC so make sure to take this into account. Head over to https://crontab.guru/ for more cronjob examples. “serviceAccountName” would be the name you used for the Service Account. “args” here is where we add the commands we want to execute. Since a pod’s complete name differs, we need to first get the current container name and we just need the deployment then to get this done, after this we can delete the pod. If you specified another name for your Minecraft container, replace “minecraft-server” with your deployment name.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
apiVersion: batch/v1
kind: CronJob
metadata:
  name: myrestartcronjob
  namespace: default
spec:
  concurrencyPolicy: Forbid
  schedule: "0 11 * * 4" #Every Thursday at 5AM UTC-6.
  successfulJobsHistoryLimit: 1
  failedJobsHistoryLimit: 1
  jobTemplate:
    spec:
      backoffLimit: 1
      activeDeadlineSeconds: 600
      template:
        spec:
          serviceAccountName: myserviceaccount
          restartPolicy: Never
          containers:
            - name: kubectl
              image: bitnami/kubectl
              command: [ "/bin/sh", "-c" ]
              args:
                - 'kubectl delete pod $(kubectl get pod -l app=minecraft-server  -o jsonpath="{.items[0].metadata.name}")'

7.5 Deploying Cronjob

Now save your changes and deploy the cronjob, the four resources configured will be created.

1
kubectl apply -f cronjob.yaml

It should look as follows:

1
2
3
4
5
6
alfredo@Azure:~$ kubectl apply -f cronjob.yaml
serviceaccount/myserviceaccount created
role.rbac.authorization.k8s.io/myroles created
rolebinding.rbac.authorization.k8s.io/myrolebinding created
cronjob.batch/myrestartcronjob created
alfredo@Azure:~$

You can check the cronjob with the command below.

1
kubectl get cronjobs

Example:

1
2
3
4
alfredo@Azure:~$ kubectl get cronjobs
NAME               SCHEDULE      SUSPEND   ACTIVE   LAST SCHEDULE   AGE
myrestartcronjob   0 11 * * 4 False     0        <none>          30s
alfredo@Azure:~$ 

When the cronjob runs, you will see the cronjob in a running state, the Minecraft server terminating while the new one gets executed a second later. When it completes it will remain in the pod lists as completed and you can check the logs at any time. This is due to the configuration for the Cronjob under the ‘HistoryLimits’ values.

1
2
3
4
5
alfredo@Azure:~$ kubectl get pods
NAME                                READY   STATUS        RESTARTS   AGE
minecraft-server-777f9c8b85-kslr2   1/1     Running       0          11s
minecraft-server-777f9c8b85-sfhd2   1/1     Terminating   0          10h
myrestartcronjob-27383275-f8c9f     1/1     Running       0          12s

If you check the logs for the cronjob you will see the confirmation that the Minecraft-server pod was deleted. If the job failed you will find the error logs here.

Example

1
2
3
alfredo@Azure:~$ kubectl logs myrestartcronjob-27383275-f8c9f
pod "minecraft-server-777f9c8b85-sfhd2" deleted
alfredo@Azure:~$

8 Conclusion

You’ve successfully created a Minecraft Server in an AKS cluster using a File Share and a Cron Job to restart the container weekly for auto-updates if one is available. Congratulations! Hope you have learned a lot from this guide and stay tuned for more upcoming guides in the future where we’ll look into Azure Container Registries, building images with Docker, and even Azure Container instance deployments.