{"id":19539515,"url":"https://github.com/se1exin/k8s-rpi","last_synced_at":"2025-08-23T01:06:01.292Z","repository":{"id":148895150,"uuid":"181096673","full_name":"se1exin/k8s-rpi","owner":"se1exin","description":"Kubernetes on Raspberry Pi Cluster - K3s w/ Traefik and LetsEncrypt - ansible playbooks for automated setup","archived":false,"fork":false,"pushed_at":"2020-09-27T11:49:08.000Z","size":52,"stargazers_count":11,"open_issues_count":0,"forks_count":2,"subscribers_count":3,"default_branch":"master","last_synced_at":"2025-04-26T16:45:49.195Z","etag":null,"topics":["ansible-playbook","grafana","influxdb","iot","k3s-cluster","letsencrypt","mqtt","prometheus","raspberry-pi-cluster","traefik"],"latest_commit_sha":null,"homepage":"","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/se1exin.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE.md","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,"zenodo":null}},"created_at":"2019-04-12T23:31:19.000Z","updated_at":"2023-07-17T18:38:39.000Z","dependencies_parsed_at":"2023-05-16T20:45:15.536Z","dependency_job_id":null,"html_url":"https://github.com/se1exin/k8s-rpi","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/se1exin/k8s-rpi","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/se1exin%2Fk8s-rpi","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/se1exin%2Fk8s-rpi/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/se1exin%2Fk8s-rpi/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/se1exin%2Fk8s-rpi/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/se1exin","download_url":"https://codeload.github.com/se1exin/k8s-rpi/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/se1exin%2Fk8s-rpi/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":271727502,"owners_count":24810561,"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","status":"online","status_checked_at":"2025-08-22T02:00:08.480Z","response_time":65,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["ansible-playbook","grafana","influxdb","iot","k3s-cluster","letsencrypt","mqtt","prometheus","raspberry-pi-cluster","traefik"],"created_at":"2024-11-11T02:40:10.756Z","updated_at":"2025-08-23T01:06:01.284Z","avatar_url":"https://github.com/se1exin.png","language":"Shell","funding_links":[],"categories":[],"sub_categories":[],"readme":"# K8s RPi\n\nConfigs for my Raspberry Pi Kubernetes Cluster (named \"rstack\") running [k3s](https://k3s.io/).\n\nGlamour shots of the cluster:\n\n![Glamour shots of the cluster](https://selexin.com/assets/img/2019-04-12-rpi-cluster.jpg)\n\nThis is the second iteration of my cluster setup ([I wrote a blog post about my first iteration](https://selexin.com/2019/04/12/kubernetes-on-raspberry-pi-cluster.html)).\nPreviously I was using full K8s with MetalLB for load balancing, now I'm using [k3s](https://k3s.io/) with [Traefik](https://docs.traefik.io/).\n\n## Standing up the Cluster\nThe `ansible` folder contains playbooks for provisioning and standing up the cluster, as well\nas for admin tasks such as bulk upgrading system packages.\n\n### Requirements / Prep steps\n - Install `ansible` and `ansible-playbook`.\n - Download and `dd` rasbian onto the Raspberry Pi SD cards.\n - Mount the `boot` partition of each SD card and `touch` the file `\u003cbootpart\u003e/ssh`.\n - Put SD cards into Raspberry Pis and boot them.\n - Accept SSH signatures and enable password-less SSH by running `ssh-copy-id pi@pi-address` on each of the Pis (will help ansible).\n - SSH into each pi and change the password for the `pi` user.\n - Add static IP assignments to your router for each of the Pis (grab their MAC addresses while you are SSH'd in).\n - Add each pi as a host in `/etc/hosts` (for ansible)\n - Update `ansible/hosts` with each host name.\n - Reboot the Pis so they pick up their static IPs. Double check the IPs have been leased properly by SSHing into each at their static IP/hostname.\n\n### Updating OS and Packages\nTo perform system updates (which you should to ensure security patches etc are installed), run:\n```\nansible-playbook -i ansible/hosts ansible/update-all.yml\n```\n\n### Installing k3s\nSimply run the ansible playbook and wait:\n```\nansible-playbook -i ansible/hosts ansible/provision-k3s.yml\n```\n\n## Post Install\n### Setting up `kubectl`\nThe master node will have a kubectl config folder at `/root/.kube`. Copy this folder from the master node\nover to your computer somewhere (e.g. with `rsync`) so you can run `kubectl` commands from your computer.\n\nTo set this `kubectl` config as your default config, export the `KUBECONFIG` variable in your `.bashrc` file:\n```\nexport KUBECONFIG=/path/to/.kube/config\n```\n\nTest `kubectl` to check everything is working (don't forget to `source ~/.bashrc`):\n```\nkubectl get nodes\n```\n\n```\nNAME           STATUS   ROLES    AGE   VERSION\nrstack-node0   Ready    master   91d   v1.15.4-k3s.1\nrstack-node2   Ready    worker   91d   v1.15.4-k3s.1\nrstack-node1   Ready    worker   91d   v1.15.4-k3s.1\nrstack-node3   Ready    worker   91d   v1.15.4-k3s.1\n```\n\n### Setting up Traefik (with LetsEncrypt certs working as well)\n[Traefik](https://docs.traefik.io/) works great as an Ingress controller with k3s (I couldn't get ingress-nginx to work).\n\nThe LetsEncrypt setup uses DNS validation via Cloudflare, so your domain's DNS needs to hosted with Cloudflare (although other providers do work - see [Traefik's Provider Docs](https://docs.traefik.io/https/acme/#providers)).\n\n#### Install Helm\nTraefik is installed via helm, so we need to install helm first. Use the helper script:\n```\nbash ./install-helm.sh\n```\n\n#### Setup Cloudflare API keys\nLetsEncrypt needs your Cloudflare API key (the 'Global' one, not an API 'token') to validate DNS challenges.\nAdd it as a k8s secret:\n```\nkubectl -n kube-system create secret generic cloudflare-api-key \\\n  --from-literal=CLOUDFLARE_EMAIL=youremail@incloudflareaccount \\\n  --from-literal=CLOUDFLARE_API_KEY=cloudflareapikey\n```\n\n#### Setup Traefik config\nUpdate the values in `config/traefik/values.yml` - notably `acme.email` to match your CloudFlare email.\n\nYou may also want to enable the dashboard with authentication, example yaml:\n```\ndashboard:\n  enabled: true\n  domain: customdomain.name\n  auth:\n    basic:\n      customusername: password-generated-with-htpasswd\n```\nSee [Traefik's BasicAuth Docs](https://docs.traefik.io/v2.0/middlewares/basicauth/) for more info.\n\n#### Install Traefik\nFinally we can install Traefik:\n```\nhelm install stable/traefik --name traefik --namespace kube-system --values config/traefik/values.yml\n```\n\n#### Test Traefik\nThere is a test nginx deployment/service/ingress at `config/traefik/test-ingress.yml`. Update the domains/host values and apply:\n```\nkubectl apply -f config/traefik/test-ingress.yml\n```\n\nDelete it with:\n```\nkubectl delete -f config/traefik/test-ingress.yml\n```\n\n#### Uninstall Traefik\nIn case you need to rollback the traefik install, run:\n```\nhelm delete traefik \u0026\u0026 helm del --purge traefik\nkubectl delete secret -n kube-system cloudflare-api-key\nkubectl delete -f config/traefik/test-ingress.yml\n```\n\n## Kubernetes Deployments/Configs\nThe `config` folder contains a number of K8s deployments/services.\n\n- `config/dashboard` - (not in use) [Kubernetes Dashboard](https://kubernetes.io/docs/tasks/access-application-cluster/web-ui-dashboard/) deployment files for monitoring the Cluster.\n- `config/dnscrypt` - [DNSCrypt](https://www.dnscrypt.org/) service for encrypted DNS (for home network).\n- `config/sensor-monitoring` - Contains all the microservices for my IoT [Home Monitoring setup](https://github.com/se1exin/home-monitoring), which monitors the temperature around my house using [MQTT](https://mqtt.org/), [Influxdb](https://www.influxdata.com/products/influxdb-overview/), and [Grafana](https://grafana.com/), and my computer stats using [Prometheus](https://prometheus.io/docs/introduction/overview/).\n- `config/docker-cloudflare-ddns.yml` - Dynamic DNS service if you do not have a static IP (uses same Cloudflare API key as traefik).\n- `config/hue-im-home.yml` - [Hue-Im-Home](https://github.com/se1exin/Hue-Im-Home) service to automatically turn off/on house lights when leaving for/coming home from work.\n\n## License\nI hope this repo is of help to anyone else setting up k3s on a Raspberry Pi Cluster.\n\nMIT - see [LICENSE.md](LICENSE.md)","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fse1exin%2Fk8s-rpi","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fse1exin%2Fk8s-rpi","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fse1exin%2Fk8s-rpi/lists"}