This repository documents my Kubernetes-on-Raspberry-Pi-powered smart home. It contains my Home Assistant configuration and automations as well as the GitOps configuration for my small Kubernetes cluster and some Ansible configuration to control the Raspberry Pis.
The Pi cluster runs on k3s and uses Flux CD pointing at this repository to keep the cluster configuration up-to-date. The config for the home cluster can be found in here.
The main components powering my house are:
- UniFi Dream Machine as a switch and router with the access point disabled
- UniFi Switch Lite 16 PoE as a secondary switch providing PoE and additional ports
- UniFi Access Point WiFi 6 Pro as a WiFi 6 AP using PoE from the Switch 8 150W
- UniFi Flex Mini as an additional switch to provide some extra ports in a cute form factor
- Synology DS1621+ NAS for laptop backups and also exposing NFS volumes to my Kubernetes cluster via the nfs-subdir-external-provisioner. It regularly backs up to Amazon S3 Glacier
- A Raspberry Pi 3b running Pi-Hole as a network ad blocker
- 3 Raspberry Pi 4 8Gb forming the Kubernetes cluster
My Home Assistant instance is the brains for all smart home automations. This project is fantastic. Mine is connected to:
- Philips Hue smart lights, switches, and motion sensors
- SONOFF ZBBridge flashed with Tasmota firmware, acting as a bridge for Zigbee-based devices and connected via WiFi to Home Assistant
- SONOFF SNZB-02 wireless temperature and humidity sensors
- SONOFF SNZB-04 wireless door/window sensors
- Eclipse Mosquitto MQTT broker, connected to Home Assistant, that devices speaking MQTT can send messages to
- Xiaomi Mi Flora plant sensors, providing humidity, temperature, light, and conductivity readings over Bluetooth using the Pi's BLE stack
- Mi Flora MQTT Daemon, a daemon that polls all configured Mi Flora sensors and pushes the results to Mosquitto
- TP-Link Kasa KP115 and TP-Link Kasa KP303 WiFi smart plugs to provide both control and energy monitoring of our appliances such as humidifiers
- Security cameras
The main component that is not yet automated is my underfloor heating - a smart thermostat with zone support is on the list of things to investigate later.
I do not use IPv6 on my home network and all devices currently are on the same VLAN.
Range | Max devices | Description |
---|---|---|
192.168.1.0/28 | 14 | Networking hardware (Router, switches, APs) |
192.168.1.16/28 | 14 | Infrastructure (DNS, storage, printer) |
192.168.1.32/28 | 14 | Kubernetes cluster |
192.168.1.128/25 | 126 | DHCP allocation range |
192.168.2.0/24 | 254 | Office network |
192.168.3.0/24 | 254 | IoT network |
192.168.4.0/24 | 254 | Guest network, all devices isolated |
The UDM is the DHCP server and all DHCP advertisements from other clients are blocked.
My house isn't huge so a single Dream Machine is enough to give good 5GHz coverage for the whole house without any extra access points.
The Pi-hole uses multiple restriction lists and serves a few LAN DNS entries. It resolves non-blacklisted addresses using a local Unbound installation. The Pi 3b is plenty powerful enough to run this, but the config isn't currently stored in this repo.
- Move to a separate WiFi network for IoT devices and implement VLANs
- Update this README to cover single points of failure (DNS)
- Update this README with better instructions / notes
- Move to powering the Pi Kubernetes cluster with PoE
- Move to netbooting the Pi Kubernetes cluster - I've had two MicroSD cards fail and counting
Setting up a new Pi is pretty simple:
- Use the Raspberry Pi Imager tool to flash the MicroSD card, connect it to the switch and power up
- SSH in, change the password
- Set the hostname (e.g.
k8s-worker-3
in/etc/hostname
) - Update everything (
sudo apt-get update && sudo apt-get upgrade
) - Set a static IP in the Kubernetes subnet in the Unifi controller
- Print out a sticky label and label the network cable with the hostname (lesson learned the hard way)
- Add
cgroup_memory=1 cgroup_enable=memory
to the end of/boot/firmware/cmdline.txt
- Reboot the host (
sudo reboot
) - Copy my public key - the new hostname should resolve now (
ssh-copy-id ubuntu@k8s-worker-3
) - Add the host to my Ansible inventory in
ansible/home.yml
- Run Ansible (
ansible-playbook -i home.yml site.yml
) - Run
k3sup
:
k3sup join --server-host k8s-master --host k8s-worker-3 --user ubuntu
- Watch as the node is joined and the Rancher
system-upgrade-controller
cordons the node and upgrades it to the correct version and uncordons it