Kube Edge Deployment
I’ve been tinkering with Raspberry Pis since college, and over time the question stopped being “what should I build?” and started being “how do I manage all of this?”
The Problem: Deploying to a Fleet of Pis Link to heading
The usual options for running software on a Raspberry Pi are:
- Installing Docker to run your program as a container
- Creating a systemd entry to manage logs and restart on boot
- Scheduling execution via crontab
- Using Ansible to push script updates
These are all fine for personal projects, but they don’t scale well when you need to roll out changes across a fleet of devices. I’ve used Balena Cloud for managing IoT devices, it works great, but it means maintaining yet another tool outside my existing stack.
The Solution: KubeEdge Link to heading
I came across KubeEdge as a way to stay inside the Kubernetes ecosystem while still getting proper edge device management. It lets you join a Raspberry Pi as a node in your existing Kubernetes cluster.
This works through two components: Cloud Core runs on the cluster side and Edge Core runs on the Raspberry Pi. Together they handle the sync between the control plane and the edge node.
Once the Pi is a Kubernetes node, you can deploy workloads using standard Kubernetes primitives like Deployment, DaemonSet, CronJob and drive everything through Flux for GitOps.

My Cluster Link to heading
Here’s the current state of my homelab cluster. pi-zero-2 is the edge node; the three talos-* nodes are my main Kubernetes nodes running Talos Linux.
✗ kubectl get nodes
NAME STATUS ROLES AGE VERSION
pi-zero-2 Ready agent,edge 5d18h v1.28.6-kubeedge-v1.17.0
talos-4hg-lnx Ready <none> 29d v1.35.4
talos-858-ghf Ready control-plane 29d v1.35.4
talos-t2l-tbc Ready <none> 29d v1.35.4
Demo: Edge Chime Link to heading
The workload running on pi-zero-2 is a Go application called edge-chime. It subscribes to an MQTT topic and flickers the Pi’s onboard LED differently depending on the message received.
✗ kubectl get pods --all-namespaces -o wide --field-selector spec.nodeName=pi-zero-2
NAMESPACE NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES
edge-chime-ssh edge-chime-ssh-56569d689b-tjrxp 1/1 Running 0 10s 10.244.3.37 pi-zero-2 <none> <none>
The application writes directly to /sys/class/leds/ACT/brightness to control the LED, connects to an MQTT broker (configured via environment variables), and flickers at different speeds and counts based on the incoming message payload.
package main
import (
"fmt"
"os"
"strings"
"time"
mqtt "github.com/eclipse/paho.mqtt.golang"
)
const (
ledPath = "/sys/class/leds/ACT/brightness"
)
var (
mqttBroker = os.Getenv("MQTT_BROKER")
mqttTopic = os.Getenv("MQTT_TOPIC")
)
func setLED(on bool) {
val := "0"
if on {
val = "1"
}
os.WriteFile(ledPath, []byte(val), 0644)
}
func flicker(flickerTimeMiliSeconds int, flickTimes int) {
flickertimeRaw := flickerTimeMiliSeconds // 2
flickerTime := time.Duration(flickertimeRaw)
for i := 0; i < flickTimes; i++ {
setLED(true)
time.Sleep(flickerTime * time.Millisecond)
setLED(false)
time.Sleep(flickerTime * time.Millisecond)
}
}
func main() {
opts := mqtt.NewClientOptions().
AddBroker(mqttBroker).
SetClientID("edge-chime").
SetAutoReconnect(true)
opts.OnConnect = func(c mqtt.Client) {
fmt.Println("[edge-chime] connected to MQTT broker")
c.Subscribe(mqttTopic, 0, func(_ mqtt.Client, msg mqtt.Message) {
message := strings.TrimSpace(string(msg.Payload()))
switch message {
case "hi":
flicker(50, 10)
case "ayo":
flicker(50, 10)
case "helloooooo":
flicker(50, 100)
default:
flicker(100, 2)
}
})
}
client := mqtt.NewClient(opts)
for {
if token := client.Connect(); token.Wait() && token.Error() != nil {
fmt.Printf("[edge-chime] MQTT connect failed: %v, retrying in 5s\n", token.Error())
time.Sleep(5 * time.Second)
continue
}
break
}
select {}
}
Deploying via Flux Link to heading
To ship a new version, I build an arm64 Docker image and push it to my registry. Flux’s image update automation picks up the new tag and applies the change to the Pi — no SSH, no manual steps.
This brings cloud-native deployment patterns to edge devices. The same GitOps workflow I use for my main cluster nodes works identically for the Pi.
What This Unlocks Link to heading
Using KubeEdge lets me treat edge nodes as first-class citizens in the cluster. I can use node taints and pod tolerations to ensure workloads run on the right node, and scale up by simply joining more Pis.
It’s particularly well-suited for low-power workloads like:
- REST and gRPC APIs
- Cronjobs for small task processing
- IoT listeners and actuators