Categories
devops virtual reality

How to play Pokemon in VR Minecraft

My young daughter is enjoying Minecraft, but somehow the vanilla game doesn’t cut it anymore. I am a gamer and a techie, which motivates me to find ways to spice up my own Minecraft experience while joining her in a game.

For her, the answer (on Java Minecraft at least) is to catch and train up Pokemon in the context of Minecraft. This makes the game way more fun for her, and makes it a more interesting challenge for me. Particularly since my client of choice is a Meta Quest 3, and I play Minecraft in VR via QuestCraft.

Not only that, but we had been utilizing Aternos for free servers, and while they are a solid choice for trying out Minecraft in multiplayer, they decidedly aren’t the right fit for a long term server. So I invested some time in finding a free solution that would be reliable and easy to maintain.

I resolved all of my pain points with the following architecture.

Server side:

A Kubernetes cluster on the Oracle free tier, with the itzg minecraft chart installed and modded with Fabric and Cobblemon, all applied using Terraform

Client side:

PC-side – Modrinth client for my daughter (playing Java edition Minecraft on an Ubuntu PC) also modded with Fabric and Cobblemon

Meta Quest (VR) – Sideloaded Questcraft with the patched Fabric installer

And for good measure, I also discovered how to battle wild Pokemon in VR with this mod https://modrinth.com/mod/quest-rebound (which needs this mod https://modrinth.com/mod/owo-lib as a dependency).

Want to try your hand at this yourself? Check out this three part tutorial series!

Create a Kubernetes Cluster on Oracle Cloud for free using Terraform

Create a Modded Minecraft Server on a hosted Kubernetes Cluster

Connecting to a Cobblemon Minecraft Java Server in VR

Categories
devops kubernetes Uncategorized

Create a Kubernetes Cluster on Oracle Cloud for free using Terraform

Credit: I forked this repository https://github.com/nce/oci-free-cloud-k8s in order to create this infrastructure on Oracle Cloud. Thank you to https://github.com/nce for the awesome Terraform bootstrap!

Parent Article: How to play Pokemon in VR Minecraft

If you are starting from scratch with Terraform on Oracle, I recommend you check out their tutorial series https://developer.hashicorp.com/terraform/tutorials/oci-get-started to get familiar with the concepts.

Then again, if you are already familiar with the concept of Infrastructure as Code you may be able to dive right in. Up to you!

Disclaimer: This infrastructure utilizes a Pay-As-You-Go account setup. Only follow this guide if you are ok with the possibility of incurring costs on Oracle. This setup is completely free, but I won’t be held responsible if you end up with a bill when something went sideways. I had to pay about a dollar to Oracle while exploring and learning how this worked.

Check out my repository https://github.com/saranicole/minecraft-oci-k8s with git. You will be making use of the infra directory in this guide, so change into that in your terminal:

git clone https://github.com/saranicole/minecraft-oci-k8s.git
cd oci-free-cloud-k8s/terraform/infra

If you haven’t registered for a Pay as You Go account on Oracle, do that now. Sign up at https://signup.cloud.oracle.com and add a payment method to convert it to Pay as You Go. Without doing this payment method step, your resources will never get created (the terraform will hang). Make sure you have the oci command line tool installed and authenticated as well – see https://docs.oracle.com/en-us/iaas/Content/API/SDKDocs/cliinstall.htm .

Manually create a single bucket in Oracle Cloud to hold your Terraform state – see https://docs.oracle.com/en-us/iaas/Content/Object/Tasks/managingbuckets_topic-To_create_a_bucket.htm . Name it “terraform-states” or similar – this name will need to match the “bucket” parameter in backend.conf . Note the “Namespace” in the bucket details – you will need that for you backend.conf file.

You will need to create a few files to make this work.

In the infra directory:

backend.conf

general.auto.tfvars

Example backend.conf ( replace <<Storage Namespace>> with the namespace you retrieved when you created the bucket ):

namespace = "<<Storage Namespace>>"
bucket    = "terraform-states"
key       = "infra/cluster.tfstate"

Example general.auto.tfvars

compartment_id = << Tenancy OCID >>
region = << Region >>
ssh_public_key = << SSH Public Key >>
kubernetes_version = "v1.35.0"
user_ocid = << User OCID >>
fingerprint = << API Key fingerprint >>
private_key_path = << Path to API Key Secret File >>
bucket_namespace = << Storage Namespace >>
enable_minecraft_port = true

Parameters Explanation:
compartment_id – this is your tenancy ID. Retrieve it by clicking the profile dropdown, selecting “Tenancy”, then copying the first “OCID” value.

region – the region where you provisioned your account, this should be reasonably closest to you. See https://docs.oracle.com/en-us/iaas/Content/General/Concepts/regions.htm for a list of available choices. Try to avoid going with Ashburn since it is the most popular and has a chance of not being able to provision resources

ssh_public_key – This is the public (non-secret) component of an API Key. See https://docs.oracle.com/en-us/iaas/Content/API/Concepts/apisigningkey.htm for an explanation of API Key authentication. Create one at https://cloud.oracle.com/identity/domains/my-profile/auth-tokens and make sure to save the private key so that you can authenticate to Terraform using the oci command line tool

kubernetes_version – This is the Kubernetes Cluster version. See https://kubernetes.io/releases/ for the available versions. v1.35.0 was the latest at the time of writing.

user_ocid – This is the OCID under “User Settings”. Copy the value from https://cloud.oracle.com/identity/domains/my-profile/details

fingerprint – This is the fingerprint given to you when you created the API Key

private_key_path – this is the file path to the location where you saved the private key part of the API Key. Something like $HOME/my_secret_key.pem . Note this is not an SSH private key

bucket_namespace – this is the Storage Namespace again

enable_minecraft_port – set to true if you plan on using this as a Minecraft server. This will open up port 25565. If you want this for some other purpose, keep this turned off using false .

Run the init first to confirm that Terraform is working and make sure to inspect everything it will create.

terraform init -backend-config=backend.conf

Then run the plan

terraform plan

It should output something like this:

data.oci_containerengine_node_pool_option.node_pool_options: Reading...
module.vcn.data.oci_core_services.all_oci_services[0]: Reading...
data.oci_identity_availability_domains.ads: Reading...
oci_identity_tag_namespace.k8s_node_pool: Refreshing state...

...

Terraform used the selected providers to generate the following execution plan. Resource actions are indicated with the
following symbols:
  + create
  ~ update in-place

Terraform will perform the following actions:

  # oci_core_security_list.private_subnet_sl will be created

... yadda yadda

If there are any errors due to missing information, make sure your files are all filled out correctly.

Once the plan succeeds with no errors, you can apply the Terraform.

terraform apply

Enter “yes” when it prompts you.

It should finish like this:

Apply complete! Resources: xx added, 0 changed, 0 destroyed.

It will also create a .kube.config file that you will need for further provisioning and to access the cluster with kubectl.

After everything is running for a day, make sure to visit https://cloud.oracle.com/account-management/cost-analysis to make sure everything is truly running without any costs, or that any cost you did get is within your expectation.

Congratulations! You now have a Kubernetes cluster running on Oracle Cloud. Check out the next post in this series to install Minecraft on this cluster.

Create a Modded Minecraft Server on a hosted Kubernetes Cluster

Categories
devops minecraft

Create a Modded Minecraft Server on a hosted Kubernetes Cluster

Previous Post: Create a Kubernetes Cluster on Oracle Cloud for free using Terraform

Credit: This guy is the man, https://github.com/itzg . He maintains https://github.com/itzg/minecraft-server-charts/tree/master/charts/minecraft which is just an epic Minecraft Helm chart.

If you already have a Kubernetes cluster that’s perfect, if not you can follow the previous post to get one for free on Oracle Cloud.

If you are not using Oracle cloud you will need to modify the minecraft/_terraform.tf file slightly to use whatever storage backend you want for the terraform state file.

So change:

backend "oci" {}

to something like

backend "s3" {}

Or whatever your preference might be. See https://developer.hashicorp.com/terraform/language/backend if you need guidance on how to choose and what it means.

Check out the repository https://github.com/saranicole/minecraft-oci-k8s with git. We will be using the minecraft directory.

git clone https://github.com/saranicole/minecraft-oci-k8s.git
cd oci-free-cloud-k8s/terraform/minecraft

You will need to create a backend.conf file, a general.auto.tfvars, a minecraft.auto.tfvars file and possibly an oracle.auto.tfvars file. Depending on how you want this to end up you will put different contents into these tfvars files.

backend.conf

namespace = "<<Storage Namespace>>"
bucket    = "terraform-states"
key       = "infra/minecraft.tfstate"

general.auto.tfvars

chart_version = "5.1.2"

If you are using Oracle Cloud, create the oracle.auto.tfvars file.

oracle.auto.tfars

compartment_id = << Tenancy OCID >>
region = << Region >>
ssh_public_key = << SSH Public Key >>
user_ocid = << User OCID >>
fingerprint = << API Key fingerprint >>
private_key_path = << Path to API Key Secret File >>
bucket_namespace = << Storage Namespace >>

If you want a vanilla Minecraft server, use the structure below and tweak as needed (making sure to change accept_eula to TRUE):

# Change this to TRUE
accept_eula = "FALSE"
world_version = "26.1.1"
server_type = "VANILLA"
fabric_loader_version = "0.18.6"
difficulty = "easy"
whitelist = "<< YOUR MINECRAFT USERNAME >>,<< SOME OTHER MINECRAFT USERNAME >>"
ops = "<< YOUR MINECRAFT USERNAME >>,<< SOME OTHER MINECRAFT USERNAME >>"
motd = "Welcome to Minecraft on Kubernetes!"
mod_urls = [
  "<< MODRINTH JAR DIRECT DOWNLOAD URL >>",
  "<< SOME OTHER JAR DIRECT DOWNLOAD URL >>"
]
download_world_url = "<< DIRECT DOWNLOAD LINK OF ZIP FILE CONTAINING WORLD DATA >>"
rclone_dest_dir = "<< OBJECT STORAGE BUCKET SUCH AS S3 OR OCI BUCKET NAME >>/<< OBJECT STORAGE BUCKET PREFIX SUCH AS 'worlds' >>"
enable_oci_backup_bucket = false
enable_oci_load_balancer = false
rcon_password = "<< SUPER SECRET PASSWORD >>"

If you want Cobblemon, particularly cobblemon on Meta Quest, you will need to use contents like the following:

minecraft.auto.tfvars

# Change this to TRUE
accept_eula = "FALSE"
world_version = "1.21.1"
server_type = "FABRIC"
fabric_loader_version = "0.18.6"
difficulty = "easy"
whitelist = "<< YOUR MINECRAFT USERNAME >>,<< SOME OTHER MINECRAFT USERNAME >>"
ops = "<< YOUR MINECRAFT USERNAME >>,<< SOME OTHER MINECRAFT USERNAME >>"
motd = "Welcome to Cobblemon on Kubernetes!"
mod_urls = [
"https://cdn.modrinth.com/data/MdwFAVRL/versions/Ygf8KJFC/Cobblemon-fabric-1.7.0%2B1.21.1.jar",
"https://cdn.modrinth.com/data/P7dR8mSH/versions/yGAe1owa/fabric-api-0.116.9%2B1.21.1.jar"
]
download_world_url = "<< DIRECT DOWNLOAD LINK OF ZIP FILE CONTAINING WORLD DATA >>"
rclone_dest_dir = "<< OBJECT STORAGE BUCKET SUCH AS S3 OR OCI BUCKET NAME >>/<< OBJECT STORAGE BUCKET PREFIX SUCH AS 'worlds' >>"
enable_oci_backup_bucket = false
enable_oci_load_balancer = false
rcon_password = "<< SUPER SECRET PASSWORD >>"

If you are using Oracle, you will want to change both enable_oci_backup_bucket and enable_oci_load_balancer to true.

In the case of Oracle the rclone_dest_dir will be “minecraft-backups/worlds”.

Run the init first to confirm that Terraform is working and make sure to inspect everything it will create.

terraform init -backend-config=backend.conf

Then run the plan

terraform plan

If there are any errors due to missing information, make sure your files are all filled out correctly.

Once the plan succeeds with no errors, you can apply the Terraform.

terraform apply

Enter “yes” when it prompts you.

It should finish like this:

Apply complete! Resources: xx added, 0 changed, 0 destroyed.

At the end you will see:

Outputs:
  + my_minecraft_server_ip = "xxx.xxx.xxx.xxx"

This is your Minecraft server ip address! Connect to port 25565 with this directly, or create a friendly DNS name in your preferred way.

If connecting with the ip address you can type in these numbers in this format:

xxx.xxx.xxx.xxx:25565

I recommend https://www.duckdns.org/ as a convenient way to give your Minecraft server a friendly url.

Way to go! You now have a Minecraft server in your preferred configuration set up on your Kubernetes cluster.

Interested in more? Take a look at the last blog post in this series:

Connecting to a Cobblemon Minecraft Java Server in VR

Categories
minecraft virtual reality

Connecting to a Cobblemon Minecraft Java Server in VR

QuestCraft! It’s awesome and I highly recommend subscribing to their Patreon. To emphasize a point they make many times over, you need to own Minecraft Java Edition in order for this to work, and you need access to your Microsoft login in order to log into Minecraft.

The basic installation instructions are available at https://github.com/QuestCraftPlusPlus/QuestCraft . You will need to follow these instructions and start a single player world on version 1.21.1 first in order to have the folder created that you need to place the mod jars into. You will also want to download this jar file https://files.xrcraftmc.com/QuestCraft/Cobblemon-fabric-1.7.0%2B1.21.1.jar which is the fixed Cobblemon mod which ONLY works with Minecraft version 1.21.1 . Make sure your server is running Minecraft version 1.21.1 as well, they have not yet released a more current patched version. Everything Minecraft 1.21.1!

Also, grab the Fabric API jar at 0.116.9 – https://cdn.modrinth.com/data/P7dR8mSH/versions/yGAe1owa/fabric-api-0.116.9%2B1.21.1.jar and https://cdn.modrinth.com/data/nOK0dI1c/versions/rKDl7Dxe/request-1.0.0%2B1.21.1.jar and https://cdn.modrinth.com/data/ccKDOlHs/versions/JB1fLQnc/owo-lib-0.12.15.4%2B1.21.jar while you are at it. These are the Quest-Rebound jars which enable battling Pokemon. You will need to install all of these mods in your mods folder on your headset.

Once you have successfully connected to a single player world, you will need to back out of the game and connect to the headset using SideQuest again.

Click the folder on the top bar which is how you can navigate the Quest’s directory structure.

………………………………………. This one
…………………………………………….

Then you will want to navigate to:

Android > data > com.qcxr.qcxr > files > instances > 1.21.1 > mods

Drag the jar files you downloaded earlier into this folder:

  • Cobblemon-fabric-1.7.0 1.21.1.jar from the QuestCraft folks
  • Fabric API at 0.116.9
  • Quest Rebound
  • owo-lib

Now you should be able to connect to a Cobblemon server!

How to Battle Wild Pokemon and other Cobblemon Stuff

You will quickly find that Cobblemon relies on keybinds that are unavailable in QuestCraft. Worry not! You can use Quest Rebound to overcome this barrier.

Instructions on using Quest Rebound are quoted from the modrinth website:

Quest Rebound – Rebinding Instructions

Add this mod to your QuestCraft instance as normal and start your game. In the game, you can go to Options -> Controls -> Open VR Bindings Menu to change your keybinds.

To reset your keybinds, delete the interaction_profiles directory from your instance root.

You *must* restart your game in order for key rebinds to take effect.

Specifically for battling wild Pokemon, you can rebind “Throw Selected Pokemon” to your left controller’s x key. Make sure to uncheck its current function checkboxes before checking the Cobblemon function box.

Personally I find the left x button a good choice because its default function is to dash forward a bit, which I do not need as much as I need to battle wild Pokemon.

You could try binding the Throw action to your radial menu, but the problem is you have to interact with a Pokemon to trigger it, and left clicking the radial menu while you’re facing the it will harm the Pokemon!

So instead, bind the action to your x key, then when you want to battle a wild Pokemon, face it and press x on your left controller, and you will get the battle menu.

The “Open overlay” and other controls are fine to bind to the radial menu. To do this, click “Options”, then “VR Settings” then “Radial Menu”. Click the number that appears in the center and you will get more blank radial tiles. Click one of these tiles and you will get a bunch of actions you can assign to the tiles, including Cobblemon-related actions.

To use the radial menu once you’ve assigned it, click the y button on the right controller and it will open.

Happy Cobblemon’ing! I’m in the QuestCraft Discord server, user “saranicole1980” so feel free to ping me there if you have any questions!

Categories
truth

America, The Beautiful Idea

Our forefathers handed down a dilemma. How can tribes, often warring against each other, become peaceful? The Greeks created games to stand in for the conflict, the Romans conquered and civilized, the Chinese built a wall. The Americans invited them all to become American.

The expansiveness of the American idea is its opportunity. The gentle acceptance of any creed, language, ethnicity, gender expression and sexual preference, is the hallmark of American society, unique across the globe, even when this acceptance has been imperfectly granted.

Even more radically, the acceptance of the poor yearning “to breathe free” has inspired hope in people around the world. Once we did not call them “immigrants”. Once we called them pilgrims. Those strangers were we ourselves, and we received a compassionate welcome in the United States that gladdened our struggling hearts and marked a new chapter in our lives.

A welcome, yes, and justice, for all. The legal system is founded on the principle that all may seek refuge in unbiased opinion, so that right may not be dictated by the strongest, but instead by the impartial.

The idea of America is inherent to the people who have pledged allegiance to its flag, who have promised to hold its citizenry as indivisible as its twin pillars of liberty and justice. Therefore, this beautiful beacon of America must outshine the dark night of tribalism, for it is we the people who hold it sacred. For its sake, we shall unite.

Categories
raspberrypi technology virtualreality

Control your Raspberry Pi 5 from your Meta Quest 3 over Bluetooth

The Meta Quest 3 is capable of so much since it is an Android based device and can leverage the existing Android app ecosystem – if you know how to do it! Let’s control our Raspberry Pi 5 from within virtual reality over Bluetooth.

Keep in mind that using Bluetooth to pair these two devices limits our ability to connect from a physically distant location. I personally prefer this since exposing it over say, SSH, would open it up to potential exploits over the Internet. I personally wouldn’t trust an SSH private key to an Android app – if you see one asking you for that, I would recommend against using it. For my use case, Bluetooth works perfectly well since I always use my Pi when I’m in close proximity to my Quest.

Disclaimer:

In this tutorial I endorse the use of Bluedot, an Android app by the tech rockstar Martin O’Hanlon. The app is MIT licensed which means you are free to use it for private or commercial use, and you can even distribute it, but you don’t have any warranty or liability claims when using it.

Prerequisites:

  • Follow this video tutorial or this pdf tutorial and have SideQuest downloaded, installed and connected to your Quest 3. Note that you will need the “advanced” version of SideQuest in order to install apk files not distributed by the SideQuest store.
  • You will need to download the apk file from the Bluedot Github repository – click here for the direct download link, or here for the repository link
  • You should be familiar with how to sideload an apk file (not from the SideQuest store). See page 7 of the pdf tutorial for a refresher
  • Raspberry Pi 5 with appropriate accessories
    • an SD card with the Raspberry Pi OS and enough space for this exercise – 50 GB or more should be plenty
    • a power supply that outputs 27W that connects via USB-C
    • a micro HDMI cable with an output compatible with a monitor of your choice
    • a mouse and keyboard that can connect via USB type A (the standard big type) or Bluetooth

If you are brand new to the Raspberry Pi, there is a great “Getting Started” tutorial at https://www.raspberrypi.com/documentation/computers/getting-started.html . This tutorial assumes you have already gone through these steps and have your Pi powered, booted up, configured with your login details, and connected to Wifi .

Steps:

  1. Sideload the Bluedot apk onto the Meta Quest 3

2. Boot up your Pi and ensure that Bluetooth is enabled – on mine it came up enabled automatically.

3. Create a Python script on your Pi to listen for Bluedot button presses. Here is a simple one from the Bluedot docs that says “Hello World” when the button is pressed

from bluedot import BlueDot
from signal import pause

def say_hello():
    print("Hello World")

bd = BlueDot()
bd.when_pressed = say_hello

pause()

4. Install the dependencies bluedot and signal, using a virtual environment as described in this tutorial. Keep in mind that using pip to install packages in the Pi environment directly may break system packages.

5. Run the Python script on the Pi. Unless this script is active and running Bluedot on the Pi will not be able to pair with the Bluedot app on the Quest 3

(myenv)pi@raspberrypi:~ $ python3 myrecipe.py

6. Back on the Quest, turn on Settings > Bluetooth. It should automatically begin scanning for available devices

7. On the Pi, click the Bluetooth icon and click “Make Discoverable”.

The icon should begin flashing

8. On the Quest you should see “raspberrypi” as an available device. When you click it, it will give you a pairing code. Back on the Pi, click the pop-up for pairing. On the Quest, click “Pair” as well. I found it easier to click the pairing pop-up on the Pi first and then on the Quest. If you happen to do it in the reverse order clicking “Pair” on the Quest first, you will need to click “Stop Discovery” on the Pi to get it to recognize the pairing.

The Quest and Pi should be paired via Bluetooth at this point.

9. Open the Bluedot app from App Library > Unknown Sources

10. Select the raspberrypi from the list of devices.

It should pop up with a screen that says “Connected” and a big blue dot

11. Click the dot, and check the Pi to see if it says “Hello World”

12. If it does, congratulations, you have connected your Quest 3 to your Pi 5!

In this tutorial we learned how to connect a Raspberry Pi 5 to a Quest 3 over Bluetooth, and click a button to execute an action on the Pi from with virtual reality.

Enjoy!

Categories
raspberrypi technology virtualreality

Adventures with Immersed VR on the Pi 5

Raspberry Pis are cool. Virtual Reality, also cool.

Let’s make a Raspberry Pi Virtual Reality coolness sandwich!

To be clear, this tutorial is about getting an Immersed VR virtual monitor working with the Pi 5. It is NOT about running a VR simulator with the Pi 5 – if you want that you can get some guides with a Google search on “DIY VR on raspberry pi.”

Disclaimer:

This tutorial makes use of a prototype build compatible with the Raspberry Pi which the Immersed VR team made available to me through Discord. It is not yet available on their downloads page and may not be compatible with all headset/raspberry pi combinations. YMMV.

Shout-Out:
This tutorial would not have been possible without the inspiring work done by Augusto Ícaro . Check out https://github.com/augustoicaro/Immersed-Linux-Virtual-Monitors and be prepared to go ooooh-ahhhhh 🙂

Prerequisites:

  • An Immersed VR account – their free starter mode should work, although you can also earn Pro by using Immersed in starter mode minimum 3 out of 7 days. More on that at https://immersed.com/faq#how_to_unlock_pro_mode
  • Access to the Immersed VR Discord – invite available at https://discord.com/invite/zy6KMbJ – in order to request and download the prototype build. Check out the #linux-help channel for the download and any assistance you might need
  • Headset compatible with Immersed VR – you can see their compatibility statement at https://immersed.com/faq under the “Compatibility” heading
  • Raspberry Pi 5 with appropriate accessories
    • an SD card with the Raspberry Pi OS and enough space for this exercise – 50 GB or more should be plenty
    • a power supply that outputs 27W that connects via USB-C
    • a micro HDMI cable with an output compatible with a monitor of your choice
    • a mouse and keyboard that can connect via USB type A (the standard big type) or Bluetooth
  • Wifi connectivity – Immersed VR works over your wifi network. Both the Pi and the headset should be connected to the same wifi network.
    ** Note that it is advisable to use a private wifi network rather than a public one, since public ones are vulnerable to hacking and could result in your session being compromised

If you are brand new to the Raspberry Pi, there is a great “Getting Started” tutorial at https://www.raspberrypi.com/documentation/computers/getting-started.html . This tutorial assumes you have already gone through these steps and have your Pi powered, booted up, configured with your login details, and connected to Wifi .

All the following steps should be executed on the Pi itself, except for the scp command which would be from a separate computer.

Steps:

  1. Download the app image from the Discord #linux-help Immersed VR channel to your Pi. If you don’t want to install Discord on your Pi, you can also download it on a separate computer that has Discord and use secure copy (scp) to transfer it to the Pi
    To use this second method, first copy your main computer’s public ssh key to the Pi as ~/.ssh/authorized_keys. A sample scp command to do this would be:
scp -i mylaptop_private_ssh_key /Users/mylaptopuser/Downloads/Immersed-aarch64.AppImage mypiuser@192.168.1.165:/home/mypiuser/Downloads

2. Once the App Image is on the Pi, grab the Linux setup script

wget https://raw.githubusercontent.com/augustoicaro/Immersed-Linux-Virtual-Monitors/main/scripts/immersed-setup/immersed-setup.sh

3. This script assumes your app image is in /home/mypiuser/Applications. Either create that directory and move both the setup script and the app image into that directory, or modify the setup script to find these resources wherever you want them to live.

4. Modify the setup script to use the App Image you downloaded. I had to replace “x86_” with “aarch”. A sample command to do this is:

sed -i -e 's/x86_/aarch/g' ~/Applications/immersed-setup.sh

5. Make the setup script executable

chmod a+x ~/Applications/immersed-setup.sh

6. Put your Applications directory on your PATH by adding this export line to your .bashrc file and then sourcing it to load it in your terminal.

echo -n "export PATH=$PATH:$HOME/Applications" >> ~/.bashrc
source ~/.bashrc

7. Install additional packages and make a symbolic link for libwlroots. Note that these versions are specific to the 10.3.2 version of the App Image and may change when this is updated.

sudo apt install -y libfuse2 libwebkit2gtk-4.0 libva2 libva-drm2
sudo ln -s /usr/lib/aarch64-linux-gnu/libwlroots.so.11 /usr/lib/aarch64-linux-gnu/libwlroots.so.5

8. Adjust the ~/.ImmersedConf file to setup your v4l2 camera device (to enable the virtual webcam feature). Use the Text Editor to find the line that starts with “CameraDevice” and adjust it to read like so:

CameraDevice=/dev/video7

8. Run the immersed-setup.sh script from the Applications directory.

cd ~/Applications
./immersed-setup.sh


This script may end with an error similar to this:

modprobe fatal module card_label=Immersed not found in directory /lib/modules/6.6.31+rpt-rpi-2712

If so not to worry, it means the v4l2loopback module hasn’t loaded into your current session. The v4l2loopback module relates to the webcam functionality.

To load the module, restart your Pi with shutdown now -r or by hitting the power button, letting it power off, and hitting the power button again.

9. At this point you should be able to run the setup script and not get any errors. Now it’s time to run the app image!

cd ~/Applications
./Immersed-aarch64.AppImage

Depending on what happened with the v4l2loopback module, the app image may generate a pop-up prompting you to install a few more dependencies. If so not to worry, we already installed these in step 7, so you can click “Do not display again” on these.

At this point you should be able to sign in with your Immersed VR account and pair the VR app with the Pi. The pop-up should say “Agent Ready” when it is available for the VR app.

10. In the VR app, select “Computers” and click the “raspberry pi” option. It should connect after a few moments. If it does not connect right away, try stopping the AppImage with Ctrl + C and re-run it.

11. View your fancy new monitor in VR!

OCULUS_ATTRIBUTION_ID:9279578942068913–

Congratulations! You now have the ability to connect to your Raspberry Pi 5 in virtual reality!

If you have any questions or get stuck, feel free to ping in the #linux-help channel of the Immersed VR Discord and we’ll see what we can do!

Categories
devops

Celebrating 10 Years in Cloud Engineering

The year was 2014 and I was working at Internet of Things startup Axeda (later acquired by PTC). I was building prototypes of Internet of Things solutions using the Axeda platform, and this particular one needed a UI, customer facing component. My manager suggested using an EC2 instance on AWS, which I had never tried before. I went through the flow of choosing an AMI, tweaking the knobs, and launching it. The invisible computer appeared!

That very year, the first annual State of DevOps report was released Nicole Forsgren, Gene Kim, Jez Humble and others. After the acquisition of Axeda, I applied for my first “DevOps Engineer” job and worked at Teradata automating the provisioning of flavors of Hadoop clusters across various clouds. Although SRE would later become known as the “implementation of class DevOps”, I always preferred to consider myself working in DevOps as that embodied to me the principle of bridging gaps between siloed developers and ops engineers.

At Acquia, I was able to mature my engineering experience to encompass Enterprise-grade practices. I worked with compliance concerns, went on call for the first time, and used Puppet to automate complex tasks. However at that time they did not offer a DevOps career track, so I transitioned into a full time DevOps role at Tomorrow.io (formerly ClimaCell).

It was at Tomorrow.io that I was able to find my sweet spot of working with Kubernetes on a daily basis, adopting Terraform and Helm as orchestration go-to tools. I used GitOps to ensure that the state of the deployment always matched the code, and hooked it all up to a Gitlabs pipeline for on demand releases.

The basis for my current work at Sensible Weather relies on the foundation laid by my combination of Enterprise and Start-up experience. I have the depth to understand how mature companies need to work, and the breadth to implement solutions tailored to the particular challenges of a growing org.

Ultimately, I am extremely grateful for the opportunity to enjoy meaningful work that remains fresh and interesting to this day.

Here’s to another ten years!

Categories
devops

Eliminating NaNs in PromQL Histogram Quantile

Working with Prometheus and PromQL can be tricky. I found it challenging to define an SLO using sloth-sli for a service whose histogram had a lot of NaN (Not a Number) values. I searched around for an out of the box solution and didn’t find what I was looking for.

The key to the solution was the knowledge that in PromQL an NaN doesn’t equal itself: NaN != NaN.

With this in mind I could use the “unless” operator to filter out any value that didn’t equal itself.

p50 Latency Error Query

histogram_quantile(0.5, sum(rate(http_request_duration_seconds_bucket{job="$job", namespace="$namespace"}[{{.window}}])) by (le)) > 5 unless (histogram_quantile(0.5, sum(rate(http_request_duration_seconds_bucket{job="$job", namespace="$namespace"}[{{.window}}])) by (le)) != histogram_quantile(0.5, sum(rate(http_request_duration_seconds_bucket{job="$job", namespace="$namespace"}[{{.window}}])) by (le))) OR on() vector(0)



This query returns the 0.5 bucket values that are over 5, and if the values that it evaluates do not equal themselves (i.e., are NaNs), it turns those into nulls. The nulls are evaluated to false (while the NaNs are evaluated to true) and then OR’ed with the vector 0 to create a consistent graph with no gaps.

Hope this tidbit helps someone, SLOs are hard enough as it is without NaNs in your life!

Categories
devops

Startup Life with DevOps at Sensible Weather

During my time so far at Sensible Weather, I’ve built an infrastructure pipeline which moves code from Github to an EKS cluster via Argo CD, a project lovingly named Margaritaville, since once you’re done with it you can go sip margaritas … 🙂 This project leveraged Terraform in Github Actions to deploy Helm applications onto the cluster. The only gap here was the management of secrets, which I initially deployed using Velero as a stopgap. Velero is a powerful tool which allows you to back up Kubernetes resources from a cluster and then restore them either to the same or a different cluster. Using it for secrets management didn’t make sense in the long term however, so as soon as I was able I migrated us to the External Secrets project, which enables the syncing of Kubernetes secrets to an external secrets provider. In this case we used AWS Parameter Store since we didn’t need cross-region or cross-account secrets sync ( and hey, free ).

Once this was all set up we needed centralized metrics, logging, and tracing, so I made use of the excellent Grafana open source LGTM stack . I used Pomerium to provide SSO for these tools which I covered in a post featured on Sensible Weather’s official blog.

Next steps – setting up an official on call with integrations into our comms. #StartupLife !