{"id":16827023,"url":"https://github.com/retocode/raspberry-k8s","last_synced_at":"2026-05-05T22:32:59.712Z","repository":{"id":154107315,"uuid":"167599666","full_name":"ReToCode/raspberry-k8s","owner":"ReToCode","description":"My kubernetes cluster on a \"rack\" of PIs","archived":false,"fork":false,"pushed_at":"2019-01-27T16:44:25.000Z","size":1738,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-03-17T19:49:16.946Z","etag":null,"topics":["arm","kubernetes","kubernetes-cluster","raspberry-pi","raspberrypi"],"latest_commit_sha":null,"homepage":null,"language":"Shell","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/ReToCode.png","metadata":{"files":{"readme":"README.MD","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2019-01-25T19:11:25.000Z","updated_at":"2020-02-28T17:03:01.000Z","dependencies_parsed_at":null,"dependency_job_id":"5c0494ac-4896-4ef7-a08e-c212f7441fdb","html_url":"https://github.com/ReToCode/raspberry-k8s","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/ReToCode/raspberry-k8s","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ReToCode%2Fraspberry-k8s","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ReToCode%2Fraspberry-k8s/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ReToCode%2Fraspberry-k8s/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ReToCode%2Fraspberry-k8s/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/ReToCode","download_url":"https://codeload.github.com/ReToCode/raspberry-k8s/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/ReToCode%2Fraspberry-k8s/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":260252967,"owners_count":22981369,"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":["arm","kubernetes","kubernetes-cluster","raspberry-pi","raspberrypi"],"created_at":"2024-10-13T11:19:24.891Z","updated_at":"2026-05-05T22:32:59.685Z","avatar_url":"https://github.com/ReToCode.png","language":"Shell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Kubernetes with a few addons on a raspberry PI cluster\nInspired by:\n- https://www.hanselman.com/blog/HowToBuildAKubernetesClusterWithARMRaspberryPiThenRunNETCoreOnOpenFaas.aspx\n- https://itnext.io/building-an-arm-kubernetes-cluster-ef31032636f9\n- https://blog.alexellis.io/serverless-kubernetes-on-raspberry-pi/\n\nSources copied/modified from: \n- https://github.com/carlosedp/kubernetes-arm\n- https://github.com/carlosedp/prometheus-operator-ARM\n- https://github.com/carlosedp/prometheus-ARM\n\n# Setup\n![cluster](https://github.com/retocode/raspberry-k8s/raw/master/img/raspi_cluster.jpg \"The raspberry pi cluster\")\n\n## Parts\n- 5x Raspberry PI B+\n- 5x Samsung Evo+ 32GB, Class 10 microSD\n- Anker PowerPort 6 (12A, 60W)\n- Renkforce 8-Port Switch (USB powered)\n- Ethernet and Micro-USB-Cables\n- 5 Layer Raspberry PI Stack Case\n\n## Network layout\n```\nNetwork: 192.168.184.0/24\nGateway: 192.168.184.1\n\nDNS: 192.168.184.1\n\n* 192.168.184.1 - Router\n* 192.168.184.100-249 DHCP Range\n\nKubernetes Nodes:\n    - k8s-master1: 192.168.184.20\n    - k8s-node1: 192.168.184.21 (also NFS server)\n    - k8s-node2: 192.168.184.22\n    - k8s-node3: 192.168.184.23\n    - k8s-node4: 192.168.184.24\n\nMetalLB CIDR: 192.168.184.49/28\n    - 192.168.184.48 - 192.168.184.62\n\nTraefik Internal Ingress IP: 192.168.184.48\n```\n\n# Installing kube\n## The basic setup for all PIs:\n\n```\n# On the router\n# Create static IPs for all the PIs\n\n# On all the PIs\n\n# Set hostname\nsudo rasbpi-config\n\n# Configure the static ip\nsudo vi /etc/dhcpcd.conf\nprofile static_eth0\nstatic ip_address=192.168.184.xx/24\nstatic routers=192.168.184.1\n\n# Install docker\ncurl -sSL get.docker.com | sh \u0026\u0026 \\\n  sudo usermod pi -aG docker\n\n# Disable swap\nsudo dphys-swapfile swapoff \u0026\u0026 \\\n  sudo dphys-swapfile uninstall \u0026\u0026 \\\n  sudo update-rc.d dphys-swapfile remove\n\n# Install kube packages\ncurl -s https://packages.cloud.google.com/apt/doc/apt-key.gpg | sudo apt-key add - \u0026\u0026 \\\n  echo \"deb http://apt.kubernetes.io/ kubernetes-xenial main\" | sudo tee /etc/apt/sources.list.d/kubernetes.list \u0026\u0026 \\\n  sudo apt-get update -q \u0026\u0026 \\\n  sudo apt-get install -qy kubeadm\n\n# Enable cgroups in kernel\necho Adding \" cgroup_enable=cpuset cgroup_memory=1 cgroup_enable=memory\" to /boot/cmdline.txt\n\nsudo cp /boot/cmdline.txt /boot/cmdline_backup.txt\norig=\"$(head -n1 /boot/cmdline.txt) cgroup_enable=cpuset cgroup_memory=1 cgroup_enable=memory\"\n\necho $orig | sudo tee /boot/cmdline.txt\n\n# Reboot\nsudo reboot\n```\n\n## Kubernetes on the master\n```\n# Setup kubernetes control pane\nkubeadm init --token-ttl=0 --pod-network-cidr=10.244.0.0/16\n\n# Patch startup time if this does not run becase of timeout\ncd /etc/kubernetes/manifests/\nvi kube-apiserver.yaml\nkubeadm init --skip-phases=preflight,kubelet-start,certs,kubeconfig,control-plane,etcd\n\n# Copy auth to non-root user\nmkdir -p $HOME/.kube\nsudo cp -i /etc/kubernetes/admin.conf $HOME/.kube/config\nsudo chown $(id -u):$(id -g) $HOME/.kube/config\n\n# Network plugin (WeaveNet)\nkubectl apply -f \"https://cloud.weave.works/k8s/net?k8s-version=$(kubectl version | base64 | tr -d '\\n')\"\n```\n\n## Kubernetes on the node \n```\n# Join the cluster using the token\nkubeadm join 192.168.184.20:6443 --token xxx --discovery-token-ca-cert-hash sha256:xxx\n```\n\n# Installing plugins\n\n## 1) Load balancers with metal\nInstalling metal:\n```\nkubectl apply -f 1-metal\n```\n\n## 2) Traefik\n```\n# rbac\nkubectl apply -f 2-traefik\n\n# Get external IP from metal LB\nkubectl -n=kube-system get services\n```\n\n## 3) NFS Storage\nI used one of the PIs as a remote NFS server.\n\n### Server setup\n```\nsudo apt-get install nfs-kernel-server nfs-common\nsudo systemctl enable nfs-kernel-server\n\n# Create path for exports\nsudo mkdir /pvs/\n\n# Add following like to /etc/exports\n/pvs/ 192.168.184.1/255.255.0.0(rw,sync,no_subtree_check,no_root_squash)\n\nsudo exportfs -a\n```\n\n### Setup NFS auto provisioning on kubernetes\n```\nkubectl apply -f 3-nfs/nfs-provisioner-rbac.yaml\nkubectl apply -f 3-nfs/nfs-provisioner.yaml\nkubectl apply -f 3-nfs/nfs-storageclass.yaml\n\nkubectl get storageclass\n# If it's not the default storage class, change it\n\nkubectl patch storageclass nfs-node1-sdcard -p '{\"metadata\":{\"annotations\": {\"storageclass.kubernetes.io/is-default-class\": \"true\"}}}'\n```\n\n## 4) Kubernetes dashboard\n```\nkubectl apply -f 4-dashboard\n```\n\n## 5) Monitoring (Prometheus \u0026 Grafana)\n```\n# Build docker images\n5-monitoring/build_images.sh\n\n# Expose necessary services on all masters \u0026 workers\n5-monitoring/expose_services.sh\n\n# Create services with open ports\nkubectl apply -f 5-monitoring/k8s\n\n# Deploy prometheus operator\nexport NAMESPACE='monitoring'\nkubectl create namespace \"$NAMESPACE\"\nkubectl --namespace=\"$NAMESPACE\" apply -f 5-monitoring/prometheus-operator\n\n# Wait for deployment of CRDs\nuntil kubectl --namespace=\"$NAMESPACE\" get alertmanagers.monitoring.coreos.com \u003e /dev/null 2\u003e\u00261; do sleep 1; printf \".\"; done\n\n# Deploy exporters\nkubectl --namespace=\"$NAMESPACE\" apply -f 5-monitoring/node-exporter\nkubectl --namespace=\"$NAMESPACE\" apply -f 5-monitoring/arm-exporter\n\n# Kube state metrics\nkubectl --namespace=\"$NAMESPACE\" apply -f 5-monitoring/kube-state-metrics\nkubectl --namespace=\"$NAMESPACE\" apply -f 5-monitoring/grafana\n\n# Prometheus\nfind 5-monitoring/prometheus -type f ! -name prometheus-k8s-roles.yaml ! -name prometheus-k8s-role-bindings.yaml -exec kubectl --namespace \"$NAMESPACE\" apply -f {} \\;\n\nkubectl apply -f 5-monitoring/prometheus/prometheus-k8s-roles.yaml\nkubectl apply -f 5-monitoring/prometheus/prometheus-k8s-role-bindings.yaml\n\n# Alertmanager\nkubectl --namespace=\"$NAMESPACE\" apply -f 5-monitoring/alertmanager\n\n```\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fretocode%2Fraspberry-k8s","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fretocode%2Fraspberry-k8s","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fretocode%2Fraspberry-k8s/lists"}