Red Hat Summit: Achieving IT service continuity through ecosystem-powered AIOps & event-driven automation

Disaster Recovery of Minecraft Server from ROSA to ARO | Trilio

Author

Table of Contents

Red Hat OpenShift Cloud Services and Trilio for OpenShift

Red Hat OpenShift cloud services help you automate the deployment and management of Red Hat OpenShift clusters so that you can build, deliver and maintain applications across every major public cloud environment—in less time. Red Hat OpenShift Service on AWS (ROSA) and Microsoft Azure Red Hat OpenShift (ARO ) are two services that Red Hat co-manages with AWS and Microsoft.

Application data protection on ARO/AWS is critical for businesses. Though Open Source Tools such as Velero provides Kubernetes backup and restore functionality, Trilio provides enterprise-level features such as 24x7x365 support, scalable performance, hooks, operation visualization, and so on.

In this blog, we will demonstrate seamless disaster recovery by backing up a Minecraft server in ROSA and restoring it in ARO.

Backing Up Application on ROSA

By leveraging an Ansible playbook, we can back up the data to an AWS S3 bucket.

  • Create demo-Minecraft namespace
  • Create a secret that holds the S3 bucket credentials
  • Create a backup target that stores the backups
  • Create a backup plan, which holds the instruction on what to backup to protect the Minecraft server data and metadata (we don’t launch a backup yet, as we still have to deploy the Minecraft server and play a little):
[st@rtrek ansibledr]$ ansible-playbook backupsite.yaml

PLAY [Preparing backup strategy] 
***************************************************************************

TASK [create the namespace "demo-minecraft"] 
***************************************************************************
changed: [localhost]

TASK [Copy the secret yaml file] 
***************************************************************************
ok: [localhost]

TASK [Ensure the secret is created] 
***************************************************************************
changed: [localhost]

TASK [Copy target yaml file] 
***************************************************************************
ok: [localhost]

TASK [Ensure target is available in "demo-minecraft"] 
***************************************************************************
changed: [localhost]

TASK [Copy the backup plan yaml file] 
***************************************************************************
ok: [localhost]

TASK [Ensure the backup plan is available] 
***************************************************************************
changed: [localhost]

In this step, we start using the demo-Minecraft namespace, go into the Minecraft directory, and execute the run.sh script. This is the script that basically creates the server, using a Helm chart. We can “oc logs” that Minecraft pod, and see when it finishes creating the world:

[st@rtrek ansibledr]$ oc project demo-minecraft
Now using project "demo-minecraft" on server 
"https://api.trilio.cjlx.p1.openshiftapps.com:6443".
[st@rtrek ansibledr]$ oc get all
NAME READY STATUS RESTARTS AGE
pod/aws-sa-demo4-target-validator-ep9zzt-sqrkb   1/1 Running   0 12s

NAME COMPLETIONS DURATION AGE
job.batch/aws-sa-demo4-target-validator-ep9zzt   0/1 13s 13s

[st@rtrek ansibledr]$ cd Minecraft/
[st@rtrek Minecraft]$ ./run.sh
clusterrole.rbac.authorization.k8s.io/system:openshift:scc:anyuid added: "default"
Release "minecraft" does not exist. Installing it now.
NAME: minecraft
LAST DEPLOYED: Mon Jan  9 18:59:51 2023
NAMESPACE: demo-minecraft
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
Get the IP address of your Minecraft server by running these commands in the
same shell:

!! NOTE: It may take a few minutes for the LoadBalancer IP to be available. !!

You can watch for EXTERNAL-IP to populate by running:
kubectl get svc --namespace demo-minecraft -w minecraft-minecraft

[st@rtrek Minecraft]$ oc logs minecraft-minecraft-696c6f8d94-v7t44 -f
[18:01:30] [Worker-Main-3/INFO]: Preparing spawn area: 93%
[18:01:31] [Worker-Main-1/INFO]: Preparing spawn area: 94%
[18:01:31] [Worker-Main-1/INFO]: Preparing spawn area: 96%
[18:01:32] [Worker-Main-3/INFO]: Preparing spawn area: 98%
[18:01:32] [Server thread/INFO]: Time elapsed: 49400 ms
[18:01:32] [Server thread/INFO]: Done (58.346s)! For help, type "help"
^C
[st@rtrek Minecraft]$ oc get all
NAME READY STATUS RESTARTS AGE
pod/minecraft-minecraft-696c6f8d94-v7t44   1/1 Running   0  6m1s

NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/minecraft-minecraft   LoadBalancer   172.30.11.145   
af096cae3f32f4bebbfe04e63e196ff7-650369600.us-east-2.elb.amazonaws.com   
25565:30331/TCP 6m1s

NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/minecraft-minecraft   1/1 1 1 6m2s

NAME DESIRED CURRENT READY AGE
replicaset.apps/minecraft-minecraft-696c6f8d94   1 1 1 6m2s

With the next command, we see the LoadBalancer IP that we will use later on the Minecraft client to connect to the server:

[st@rtrek ansibledr]$ oc get all | grep LoadBalancer
service/minecraft-minecraft   LoadBalancer   172.30.11.145   
af096cae3f32f4bebbfe04e63e196ff7-650369600.us-east-2.elb.amazonaws.com
25565:30331/TCP   51m

At this point, we have an address for the ELB → af096cae3f32f4bebbfe04e63e196ff7-650369600.us-east-2.elb.amazonaws.com

We use that in the Minecraft client:

Now we play a little, and then take a backup:

[st@rtrek ansibledr]$ ansible-playbook createbackup.yaml
 
PLAY [Launch a backup]
***************************************************************************
 
TASK [Copy the backup plan yaml file] 
***************************************************************************
ok: [localhost]
 
TASK [Ensure the backup runs] 
***************************************************************************
changed: [localhost]
  
[st@rtrek ansibledr]$ oc get backup
NAME BACKUPPLAN BACKUP TYPE STATUS DATA SIZE CREATION TIME START TIME END TIME PERCENTAGE COMPLETED BACKUP SCOPE DURATION
minecraft-backup   minecraft-demo-backup-plan Full InProgress 0 2023-01-09T18:22:24Z 2023-01-09T18:22:24Z Namespace   
[st@rtrek ansibledr]$ oc get backup
NAME BACKUPPLAN BACKUP TYPE STATUS DATA SIZE CREATION TIME START TIME END TIME PERCENTAGE COMPLETED BACKUP SCOPE DURATION
minecraft-backup   minecraft-demo-backup-plan   Full       Available   394395648   2023-01-09T18:22:24Z   2023-01-09T18:22:24Z   2023-01-09T18:27:39Z   100                 Namespace   5m15.39490617s

Now that the backup is ready, we can restore the same in ARO, using the Trilio UI, or using an Ansible playbook to do it automatically.

Restore using Ansible Playbook:

We will run the playbook restoresite.yaml and this will do the whole process:

[st@rtrek ansibledr]$ ansible-playbook restorearo.yaml
PLAY [Preparing restore strategy] 
***************************************************************************
TASK [create the namespace "demo-minecraft-restore"] 
***************************************************************************
changed: [localhost]
TASK [Copy the secret yaml file] 
***************************************************************************
ok: [localhost]
TASK [Ensure the secret is created] 
***************************************************************************
changed: [localhost]
TASK [Copy target yaml file]
***************************************************************************
ok: [localhost]
TASK [Ensure target is available in "demo-minecraft-restore"] 
***************************************************************************
changed: [localhost]
TASK [Copy the restore plan yaml file]
***************************************************************************
changed: [localhost]
TASK [Ensure the restore runs]
***************************************************************************
changed: [localhost]

This playbook will create an empty namespace “demo-Minecraft-restore”, a secret for the target, a target (it holds the S3 bucket credentials), and run the restore.

After a few minutes, everything will be restored in that namespace, and ARO would have created a LoadBalancer which we will grab to use it in the Minecraft client:

[st@rtrek ansibledr]$ oc get all
NAME READY STATUS RESTARTS AGE
pod/aws-sa-demo4-target-browser-l7ztek-6b5575db7-g5sl6 1/1 Running 0 6m49s
pod/minecfqnu-minecraft-6447d44cb5-v7qhh 0/1 Running 0 27s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/minecfqnu-minecraft LoadBalancer 172.30.184.128 20.102.37.28 25565:31879/TCP 28s
service/tb-aws-sa-demo4-target-browser-l7ztek ClusterIP 172.30.154.178 <none> 80/TCP 6m50s

NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/aws-sa-demo4-target-browser-l7ztek 1/1 1 1 6m50s
deployment.apps/minecfqnu-minecraft 0/1 1 0 28s

NAME DESIRED CURRENT READY AGE
replicaset.apps/aws-sa-demo4-target-browser-l7ztek-6b5575db7 1 1 1 6m50s
replicaset.apps/minecfqnu-minecraft-6447d44cb5 1 1 0 28s

NAME HOST/PORT PATH SERVICES PORT TERMINATION WILDCARD
route.route.openshift.io/tb-aws-sa-demo4-target-browser-l7ztek-f2zzf trilio-system.apps.nvsgu1at.eastus.aroapp.io /aws-sa-demo4-target.demo-minecraft-restore tb-aws-sa-demo4-target-browser-l7ztek http edge/Redirect None

In this case, is the IP 20.102.37.28:

And then we will be able to connect to the Minecraft Server running in ARO:

Restore using Trilio UI:

In this way of restoring the Minecraft server to ARO, what we do is access the Trilio UI (which is running inside ARO and exposed with a route.

Don’t be surprised if the IPs or Minecraft screenshots look different, as I recorded different videos, and different restores for this blog post.

We see in the screenshot that the Trilio UI is a multi-cluster UI, so we took the backup in the Rosa instance, and now we are going to access the backup target from the ARO instance and start restoring from there. The source cluster could be down or inaccessible, and that would not prevent us from being able to restore it anyway:

We go to targets, and select the aws-sa-demo4-target, where the backup was saved from Rosa:

We could select any backup on that backup target, but we choose the one we know the backup is:

And then the backup we want to restore, in this case we only have one backup, but we could have one full and several increments, and we could choose any of those:

Then we enter a name for the restore and the namespace where we want to restore. If the namespace where we want to restore does not exist, we can create it here:

The restoration will start at this point.

We can then go to ARO, and check that everything is being restored, like the Persistent Volume where the data is stored:

Here we can see how the Helm release was just created:

And if we go to the service, we will find the LoadBalancer created in ARO:

Then we grab the LoadBalancer IP and use it in the Minecraft client. At this point, we are in the same step as when we restored through Ansible. We only have to enter the IP, and connect to the Minecraft server:

And we can check that all our Minecraft inventory is where we left it!

YouTube video with everything, using the Trilio UR to do the migration/disaster recovery:

Thank you for getting there! I hope it was interesting for you.

The github repo where you can find the supporting files to test this demo is in the following URL:

https://github.com/trilio-demo/rosatoarodr

  1. http://github.com/itzg/minecraft-server-charts
  2. http://github.com/itzg/minecraft-server-charts/tree/master/charts/minecraft
  3. http://github.com/gilesknap/k3s-minecraft
  4. http://artifacthub.io/packages/helm/minecraft-server-charts/minecraft
  5. Default values.yaml file  http://github.com/itzg/minecraft-server-charts/blob/master/charts/minecraft/values.yaml
  6. https://www.plural.sh/blog/how-to-run-a-minecraft-server-on-a-kubernetes-cluster/