{"id":19487152,"url":"https://github.com/tylerlittlefield/rpi-cluster","last_synced_at":"2026-05-18T05:35:59.066Z","repository":{"id":182545125,"uuid":"322466497","full_name":"tylerlittlefield/rpi-cluster","owner":"tylerlittlefield","description":":cake: Raspberry Pi Cluster","archived":false,"fork":false,"pushed_at":"2020-12-20T18:19:18.000Z","size":242,"stargazers_count":1,"open_issues_count":0,"forks_count":1,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-01-08T08:16:45.450Z","etag":null,"topics":["k8s","kubernetes","pi-cluster","raspberry-pi"],"latest_commit_sha":null,"homepage":"","language":"HTML","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/tylerlittlefield.png","metadata":{"files":{"readme":"README.Rmd","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null}},"created_at":"2020-12-18T02:25:19.000Z","updated_at":"2021-06-04T09:46:27.000Z","dependencies_parsed_at":"2023-07-20T12:30:51.579Z","dependency_job_id":null,"html_url":"https://github.com/tylerlittlefield/rpi-cluster","commit_stats":null,"previous_names":["tylerlittlefield/rpi-cluster"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tylerlittlefield%2Frpi-cluster","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tylerlittlefield%2Frpi-cluster/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tylerlittlefield%2Frpi-cluster/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/tylerlittlefield%2Frpi-cluster/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/tylerlittlefield","download_url":"https://codeload.github.com/tylerlittlefield/rpi-cluster/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":240728751,"owners_count":19848115,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["k8s","kubernetes","pi-cluster","raspberry-pi"],"created_at":"2024-11-10T20:44:14.320Z","updated_at":"2025-11-10T07:32:01.320Z","avatar_url":"https://github.com/tylerlittlefield.png","language":"HTML","funding_links":[],"categories":[],"sub_categories":[],"readme":"---\ntitle: rpi-cluster\noutput:\n  github_document:\n    toc: true\n    toc_depth: 2\n---\n\n\u003c!-- README.md is generated from README.Rmd. Please edit that file --\u003e\n\n```{r, include = FALSE}\nknitr::opts_chunk$set(\n  collapse = TRUE,\n  comment = \"#\u003e\"\n)\n```\n\n## `r emo::ji(\"man_technologist\")` Motivation\n\nThe Pi cluster is a hobby project I work on in my spare time. My primary motivation is to learn, but it's also just fun. In particular, I would like to learn:\n\n* Kubernetes\n* Linux stuff\n* Scaling shiny\n\n## `r emo::ji(\"toolbox\")` Hardware\n\n* MacBook Pro 2019 16\" laptop to work with the Pi\n* 3 Raspberry Pi's, 8GB model\n* 1 MicroSD card\n* 3 USB \u003e= 3.0\n* 1 Network switch with 4 PoE ports\n* 3 PoE hats\n* 3 CAT6 cables\n* 1 Cluster case that has 3 layers\n\n## `r emo::ji(\"microscope\")` Setting up the microSD card\n\nFirst step is to configure a microSD card that's running Raspberry Pi OS. I wont go into detail on how that part is done, check the official imaging tools, it's a simple process. Additionally, **I am not using WiFi at all**, so I skip steps like setting up the `wpa_supplicant.conf` file.\n\nAnyway, after you've written the Pi OS to a microSD card enable SSH:\n\n```bash\ntouch /Volumes/boot/ssh\n```\n\nNow unmount the drive, insert it into the Pi and turn it on! If all goes as planned, you can find your Pi's IP with `nmap`:\n\n```bash\nnmap -sn 192.168.1.0/24 # ip may very, check what your ip is\n```\n\nYou should see something like \"raspberrypi\", identify the IP associated with this and SSH into the device. From here, we can update the EEPROM:\n\n```bash\n# pw: raspberry\nssh pi@\u003cIP found in above step\u003e\n\n# upgrade eeprom and reboot\nsudo apt-get upgrade -y\nsudo rpi-eeprom-update -a\nsudo reboot\n```\n\n**This next step may not be applicable to others** but this was the key to get my Pi's booting from USB (I think, trial and error makes it all this fuzzy). We need to modify the boot order of the Pi's, I discovered this bit of information from: \n\n* https://jamesachambers.com/new-raspberry-pi-4-bootloader-usb-network-boot-guide/\n\nSSH back in the Pi and run:\n\n```bash\n# verify that the BOOT_ORDER=0x1 line is changed to BOOT_ORDER=0x4\nsudo -E rpi-eeprom-config --edit\n\n# then reboot\nsudo reboot\n```\n\nSSH back in the Pi and shut it down for now:\n\n```bash\nsudo shutdown -h now\n```\n\nWe are ready to set up the USB boot!\n\n## `r emo::ji(\"hiking_boot\")` Setting up USB boot\n\nJust as the imager tool was used with the microSD, do the same but with Ubuntu Server 20.10 on a USB device. Once this completes, we need to edit some files, I discovered this information from:\n\n* https://github.com/DavidUnboxed/Ubuntu-20.04-WiFi-RaspberyPi4B\n\nWe need to edit:\n\n1. `user-data`\n2. `network-config`\n\nYou can reference the repository above, or just reference the code below. For `network-config` we need something like:\n\n```bash\nversion: 2\nethernets:\n  eth0:\n    # Rename the built-in ethernet device to \"eth0\"\n    match:\n      driver: bcmgenet smsc95xx lan78xx\n    set-name: eth0\n    dhcp4: true\n    optional: true\n```\n\nFor `user-data` we need something like:\n\n```bash\n#cloud-config\n\nchpasswd:\n  expire: true\n  list:\n  - ubuntu:ubuntu\n\nssh_pwauth: true\n\npower_state:\n  mode: reboot\n```\n\nIf I remember correctly, the `power_state` part was needed to get WiFi working, and I ditched using WiFi entirely, so it may not be needed anymore (assuming you are going ethernet only route).\n\nNow, with the Pi shutdown and disconnected from power, insert the USB and remove the microSD. Turn on the Pi and it should boot from USB now. Repeat this process for all Pi's.\n\n## `r emo::ji(\"chef\")` Changing the hostname\n\nFor all my Pi's, I want clear hostnames to organize my cluster. I went with the following naming:\n\n1. main\n2. worker-01\n3. worker-02\n\nTo do this, SSH in the Pi and run:\n\n```bash\nsudo hostnamectl set-hostname \u003cdesired hostname\u003e\n```\n\nNow reboot the device with `sudo reboot`. Repeat all the stuff with the other Pi's.\n\n## `r emo::ji(\"bust_in_silhouette\")` Change user\n\nThe default user is `ubuntu` but I want to change it. In my case, I have a user `pirate` for all Pi's. To do this, I ran:\n\n```bash\n# check groups of ubuntu\ngroups\n\n# add a user\nsudo adduser pirate\n\n# set groups for pirate (i found these groups by running `groups` as you see above)\nsudo usermod -a -G adm,dialout,cdrom,floppy,sudo,audio,dip,video,plugdev,netdev,lxd pirate\n```\n\nLog out of the Pi with `exit` and try to log in with your new username. If you can login with out issue, delete the `ubuntu` user:\n\n```bash\nsudo deluser --remove-home ubuntu\n```\n\n## `r emo::ji(\"key\")` Set up `.pub` key authentication\n\nI think there are multiple ways you can set up key based authentication, there is a `.pem` and `.pub` file, I'm not sure which is better or what the difference is but I'm using `.pub`. This allows your to SSH into the Pi's without entering passwords and has a number of other benefits like allowing Ansible to control your Pi cluster. To do this, I start by making a key if you don't already have one:\n\n```bash\nssh-keygen -t rsa -b 4096 -C \"tyler@rpi\" # put whatever comment you want\n```\n\nNow copy the key to each Pi:\n\n```bash\nssh-copy-id -i ~/.ssh/id_rsa.pub pirate@\u003cip\u003e\n```\n\nNext time you SSH, no password should be required.\n\n## `r emo::ji(\"file_folder\")` SSH config file\n\nSet up a `config` file in `~/.ssh/` directory to you can assign a name to each connection:\n\n```bash\nnano ~/.ssh/config\n```\n\nThen add something like:\n\n```bash\nHost rpi-main\n  User pirate\n  HostName \u003cip\u003e\n\nHost rpi-worker-01\n  User pirate\n  HostName \u003cip\u003e\n\nHost rpi-worker-02\n  User pirate\n  HostName \u003cip\u003e\n```\n\nNow you can SSH into the Pi's with `ssh rpi-main`.\n\n## `r emo::ji(\"rocket\")` Setting up k3s\n\nI basically followed this:\n\n* https://www.jeffgeerling.com/blog/2020/installing-k3s-kubernetes-on-turing-pi-raspberry-pi-cluster-episode-3\n\nI clone the k3s-ansible project to this repo and removed some stuff I didn't need, things like the README, and then:\n\n1. Edit `inventory/hosts.ini`, add node IPs.\n2. Edit `inventory/group_vars/all.yml` and change the `ansible_user` to pirate.\n3. Run `ansible-playbook site.yml -i inventory/hosts.ini --ask-become-pass`\n\nNow grab the kube config file with:\n\n```bash\nscp pirate@main:~/.kube/config ~/.kube/config-rpi\n```\n\nIf `kubectl` isn't installed, `brew install kubectl`. Set the `KUBECONFIG` environment variable with:\n\n```bash\nexport KUBECONFIG=~/.kube/config-rpi\n```\n\nIf you want this to be permanent, put it in your `~/.zshrc` file. After all of this, you should be able to fetch all nodes with `kubectl get nodes`.\n\n```{r, echo=FALSE}\nknitr::include_graphics(\"images/readme-kubectl-get-nodes.png\")\n```\n\nNote, that I think the `--ask-become-pass` part is not supposed to be necessary. I may have configured things wrong, but adding it allows this playbook to complete.\n\n## `r emo::ji(\"chart_increasing\")` Setting up monitoring tools\n\nI basically followed this:\n\n* https://www.jeffgeerling.com/blog/2020/raspberry-pi-cluster-episode-4-minecraft-pi-hole-grafana-and-more\n\nAnd used [`carlosedp/cluster-monitoring`](https://github.com/carlosedp/cluster-monitoring) to easily set up monitoring for the Pis. I cloned this repository to my main node and followed the [k3s instructions](https://github.com/carlosedp/cluster-monitoring#quickstart-for-k3s).\n\n## `r emo::ji(\"man_teacher\")` Things I learned\n\n* **I struggled with WiFi on the Pi's and in the end decided it wasn't worth the effort.** After trial and error, and learning about `power_state` in the cloud-config, I could get WiFi working on USB but it wasn't reliable. For example, setting up k3s via Ansible would constantly error out. However, the Ansible playbook *just worked* after switching to ethernet.\n\n* **I struggled with [cloud-config](https://cloudinit.readthedocs.io/en/latest/topics/examples.html), but I want to revisit.** In this guide, I have some steps where I set the hostname, copy the SSH key, create a different user, and more. All of this can be handled in the cloud-config file on the first boot of the Pi, but I couldn't get it working. For example, I couldn't get `hostname` or `ssh_authorized_keys` to work.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftylerlittlefield%2Frpi-cluster","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftylerlittlefield%2Frpi-cluster","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftylerlittlefield%2Frpi-cluster/lists"}