{"id":13821807,"url":"https://github.com/buroa/k8s-gitops","last_synced_at":"2026-01-17T11:53:29.540Z","repository":{"id":65279001,"uuid":"586914715","full_name":"buroa/k8s-gitops","owner":"buroa","description":"Fiancé-approved geeked homelab k8s cluster deployed on 🍏 Mac Minis with Talos Linux; automated via Flux, Renovate and GitHub Actions 🤖","archived":false,"fork":false,"pushed_at":"2024-04-13T23:48:20.000Z","size":39767,"stargazers_count":125,"open_issues_count":1,"forks_count":10,"subscribers_count":4,"default_branch":"master","last_synced_at":"2024-04-14T00:29:18.106Z","etag":null,"topics":["apple","flux","gitops","home-operations","homelab","k8s","kubernetes","kubesearch","renovate","selfhosted","talos"],"latest_commit_sha":null,"homepage":"https://ktwo.io","language":"YAML","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":"blackjid/k8s-gitops","license":"wtfpl","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/buroa.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":".github/CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":".github/CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":null,"codeowners":".github/CODEOWNERS","security":".github/SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null},"funding":{"github":"buroa"}},"created_at":"2023-01-09T14:29:27.000Z","updated_at":"2024-04-15T11:39:37.556Z","dependencies_parsed_at":"2024-01-17T09:35:50.105Z","dependency_job_id":"f65cb8b1-706c-453e-9b43-c7bb45b4aea3","html_url":"https://github.com/buroa/k8s-gitops","commit_stats":null,"previous_names":[],"tags_count":14,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/buroa%2Fk8s-gitops","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/buroa%2Fk8s-gitops/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/buroa%2Fk8s-gitops/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/buroa%2Fk8s-gitops/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/buroa","download_url":"https://codeload.github.com/buroa/k8s-gitops/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":213893315,"owners_count":15653524,"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":["apple","flux","gitops","home-operations","homelab","k8s","kubernetes","kubesearch","renovate","selfhosted","talos"],"created_at":"2024-08-04T08:01:29.119Z","updated_at":"2024-11-19T22:30:54.583Z","avatar_url":"https://github.com/buroa.png","language":"YAML","funding_links":["https://github.com/sponsors/buroa"],"categories":["YAML","kubernetes"],"sub_categories":[],"readme":"\u003cdiv align=\"center\"\u003e\n\n\u003cimg src=\"https://github.com/buroa/k8s-gitops/assets/36205263/14771e67-0c36-4b7c-923f-31f54529067d\" align=\"center\" width=\"144px\" height=\"144px\"/\u003e\n\n### My _geeked_ homelab k8s cluster :wheel_of_dharma:\n\n_... automated via [Flux](https://github.com/fluxcd/flux2), [Renovate](https://github.com/renovatebot/renovate) and [GitHub Actions](https://github.com/features/actions)_ :robot:\n\n\u003c/div\u003e\n\n\u003cdiv align=\"center\"\u003e\n\n[![Discord](https://img.shields.io/discord/673534664354430999?style=for-the-badge\u0026label\u0026logo=discord\u0026logoColor=white\u0026color=blue)](https://discord.gg/home-operations)\u0026nbsp;\u0026nbsp;\n[![Talos](https://img.shields.io/endpoint?url=https%3A%2F%2Fkromgo.ktwo.io%2Ftalos_version\u0026style=for-the-badge\u0026logo=talos\u0026logoColor=white\u0026color=blue\u0026label=%20)](https://talos.dev)\u0026nbsp;\u0026nbsp;\n[![Kubernetes](https://img.shields.io/endpoint?url=https%3A%2F%2Fkromgo.ktwo.io%2Fkubernetes_version\u0026style=for-the-badge\u0026logo=kubernetes\u0026logoColor=white\u0026color=blue\u0026label=%20)](https://kubernetes.io)\u0026nbsp;\u0026nbsp;\n[![Renovate](https://img.shields.io/github/actions/workflow/status/buroa/k8s-gitops/renovate.yaml?branch=master\u0026label=\u0026logo=renovatebot\u0026style=for-the-badge\u0026color=blue)](https://github.com/buroa/k8s-gitops/actions/workflows/renovate.yaml)\n\n\u003c/div\u003e\n\n\u003cdiv align=\"center\"\u003e\n\n[![Home-Internet](https://img.shields.io/endpoint?url=https%3A%2F%2Fhealthchecks.io%2Fb%2F2%2Fe8997a34-4964-4805-ab62-3522059c6f2b.shields\u0026style=for-the-badge\u0026logo=ubiquiti\u0026logoColor=white\u0026label=Home%20Internet)](https://status.ktwo.io)\u0026nbsp;\u0026nbsp;\n[![Status-Page](https://img.shields.io/endpoint?url=https%3A%2F%2Fstatus.ktwo.io%2Fapi%2Fv1%2Fendpoints%2F_gatus%2Fhealth%2Fbadge.shields\u0026style=for-the-badge\u0026logo=statuspage\u0026logoColor=white\u0026label=Status%20Page)](https://status.ktwo.io)\u0026nbsp;\u0026nbsp;\n[![Alertmanager](https://img.shields.io/endpoint?url=https%3A%2F%2Fhealthchecks.io%2Fb%2F2%2Fd6a71d48-9e97-4ba0-b7a0-ed0677d78304.shields\u0026style=for-the-badge\u0026logo=prometheus\u0026logoColor=white\u0026label=Alertmanager)](https://status.ktwo.io)\n\n\u003c/div\u003e\n\n\u003cdiv align=\"center\"\u003e\n\n[![Age-Days](https://img.shields.io/endpoint?url=https%3A%2F%2Fkromgo.ktwo.io%2Fcluster_age_days\u0026style=flat-square\u0026label=Age)](https://github.com/kashalls/kromgo)\u0026nbsp;\u0026nbsp;\n[![Uptime-Days](https://img.shields.io/endpoint?url=https%3A%2F%2Fkromgo.ktwo.io%2Fcluster_uptime_days\u0026style=flat-square\u0026label=Uptime)](https://github.com/kashalls/kromgo)\u0026nbsp;\u0026nbsp;\n[![Node-Count](https://img.shields.io/endpoint?url=https%3A%2F%2Fkromgo.ktwo.io%2Fcluster_node_count\u0026style=flat-square\u0026label=Nodes)](https://github.com/kashalls/kromgo)\u0026nbsp;\u0026nbsp;\n[![Pod-Count](https://img.shields.io/endpoint?url=https%3A%2F%2Fkromgo.ktwo.io%2Fcluster_pod_count\u0026style=flat-square\u0026label=Pods)](https://github.com/kashalls/kromgo)\u0026nbsp;\u0026nbsp;\n[![CPU-Usage](https://img.shields.io/endpoint?url=https%3A%2F%2Fkromgo.ktwo.io%2Fcluster_cpu_usage\u0026style=flat-square\u0026label=CPU)](https://github.com/kashalls/kromgo)\u0026nbsp;\u0026nbsp;\n[![Memory-Usage](https://img.shields.io/endpoint?url=https%3A%2F%2Fkromgo.ktwo.io%2Fcluster_memory_usage\u0026style=flat-square\u0026label=Memory)](https://github.com/kashalls/kromgo)\u0026nbsp;\u0026nbsp;\n[![Power-Usage](https://img.shields.io/endpoint?url=https%3A%2F%2Fkromgo.ktwo.io%2Fcluster_power_usage\u0026style=flat-square\u0026label=Power)](https://github.com/kashalls/kromgo)\n\n\u003c/div\u003e\n\n---\n\n## 📖 Overview\n\nThis is a repository for my home infrastructure and Kubernetes cluster. I try to adhere to Infrastructure as Code (IaC) and GitOps practices using tools like [Kubernetes](https://github.com/kubernetes/kubernetes), [Flux](https://github.com/fluxcd/flux2), [Renovate](https://github.com/renovatebot/renovate) and [GitHub Actions](https://github.com/features/actions).\n\n---\n\n## ⛵ Kubernetes\n\nThis semi hyper-converged cluster operates on [Talos Linux](https://github.com/siderolabs/talos), an immutable and ephemeral Linux distribution tailored for [Kubernetes](https://github.com/kubernetes/kubernetes), and is deployed on bare-metal [MS-01](https://store.minisforum.com/products/minisforum-ms-01) workstations. [Rook](https://github.com/rook/rook) supplies my workloads with persistent block, object, and file storage, while a separate server handles media file storage. The cluster is designed to enable a full teardown without any data loss.\n\nThere is a template at [onedr0p/cluster-template](https://github.com/onedr0p/cluster-template) if you want to follow along with some of the practices I use here.\n\n### Core Components\n\n- [actions-runner-controller](https://github.com/actions/actions-runner-controller): Self-hosted Github runners.\n- [cert-manager](https://github.com/cert-manager/cert-manager): Creates SSL certificates for services in my cluster.\n- [cilium](https://github.com/cilium/cilium): Internal Kubernetes container networking interface.\n- [cloudflared](https://github.com/cloudflare/cloudflared): Enables Cloudflare secure access to my ingresses.\n- [external-dns](https://github.com/kubernetes-sigs/external-dns): Automatically syncs ingress DNS records to a DNS provider.\n- [external-secrets](https://github.com/external-secrets/external-secrets): Managed Kubernetes secrets using [1Password Connect](https://github.com/1Password/connect).\n- [ingress-nginx](https://github.com/kubernetes/ingress-nginx): Kubernetes ingress controller using NGINX as a reverse proxy and load balancer.\n- [multus](https://github.com/k8snetworkplumbingwg/multus-cni): Multi-homed pod networking.\n- [rook](https://github.com/rook/rook): Distributed block storage for peristent storage.\n- [sops](https://github.com/getsops/sops): Managed secrets for Kubernetes which are commited to Git.\n- [spegel](https://github.com/spegel-org/spegel): Stateless cluster local OCI registry mirror.\n- [tailscale](https://github.com/tailscale/tailscale): Private WireGuard based VPN.\n- [volsync](https://github.com/backube/volsync): Backup and recovery of persistent volume claims.\n\n### GitOps\n\n[Flux](https://github.com/fluxcd/flux2) monitors my [kubernetes](./kubernetes) folder (see Directories below) and implements changes to my cluster based on the YAML manifests.\n\nFlux operates by recursively searching the [kubernetes/apps](./kubernetes/apps) folder until it locates the top-level `kustomization.yaml` in each directory. It then applies all the resources listed in it. This `kustomization.yaml` typically contains a namespace resource and one or more Flux kustomizations. These Flux kustomizations usually include a `HelmRelease` or other application-related resources, which are then applied.\n\n[Renovate](https://github.com/renovatebot/renovate) monitors my **entire** repository for dependency updates, automatically creating a PR when updates are found. When some PRs are merged, [Flux](https://github.com/fluxcd/flux2) applies the changes to my cluster.\n\n### Directories\n\nThis Git repository contains the following directories under [kubernetes](./kubernetes).\n\n```sh\n📁 kubernetes      # Kubernetes cluster defined as code\n├─📁 apps          # Apps deployed into my cluster grouped by namespace (see below)\n├─📁 bootstrap     # Flux installation\n└─📁 flux          # Main Flux configuration of repository\n```\n\n### Cluster layout\n\nThis is a high-level look how Flux deploys my applications with dependencies. Below there are 3 Flux kustomizations `postgres`, `postgres-cluster`, and `atuin`. `postgres` is the first app that needs to be running and healthy before `postgres-cluster` and once `postgres-cluster` is healthy `atuin` will be deployed.\n\n```mermaid\ngraph TD;\n  id1\u003eKustomization: cluster] --\u003e|Creates| id2\u003eKustomization: cluster-apps];\n  id2\u003eKustomization: cluster-apps] --\u003e|Creates| id3\u003eKustomization: postgres];\n  id2\u003eKustomization: cluster-apps] --\u003e|Creates| id5\u003eKustomization: postgres-cluster]\n  id2\u003eKustomization: cluster-apps] --\u003e|Creates| id8\u003eKustomization: atuin]\n  id3\u003eKustomization: postgres] --\u003e|Creates| id4[HelmRelease: postgres];\n  id5\u003eKustomization: postgres-cluster] --\u003e|Depends on| id3\u003eKustomization: postgres];\n  id5\u003eKustomization: postgres-cluster] --\u003e|Creates| id10[Postgres Cluster];\n  id8\u003eKustomization: atuin] --\u003e|Creates| id9(HelmRelease: atuin);\n  id8\u003eKustomization: atuin] --\u003e|Depends on| id5\u003eKustomization: postgres-cluster];\n```\n\n### Networking\n\n\u003cdetails\u003e\n  \u003csummary\u003eClick to see a high-level network diagram\u003c/summary\u003e\n\n  \u003cimg src=\"https://github.com/user-attachments/assets/c24d1d42-0cab-4aff-8b75-d2ebc1d15ab8\" align=\"center\" width=\"600px\" alt=\"network\"/\u003e\n\u003c/details\u003e\n\n---\n\n## 🌐 DNS\n\nI have two instances of `external-dns` running in my cluster. The private DNS instance synchronizes DNS records with a `UDM Pro Max`, while the public DNS instance does the same with `Cloudflare`. This setup is managed by creating ingresses with specific ingress classes: `internal` for the private DNS and `external` for the public DNS. Both ingresses use the `external-dns.alpha.kubernetes.io/target` annotation to specify the target. The `external-dns` instances then syncs the DNS records to their respective platforms accordingly.\n\n---\n\n## 🔧 Hardware\n\n\u003cdetails\u003e\n  \u003csummary\u003eClick to see my rack\u003c/summary\u003e\n\n  \u003cimg src=\"https://github.com/user-attachments/assets/43bd0ca8-a1a8-49d5-9b9a-04fbdcecdd3f\" align=\"center\" alt=\"rack\"/\u003e\n\u003c/details\u003e\n\n| Device                    | Count | OS Disk Size    | Data Disk Size              | Ram  | Operating System | Purpose         |\n|---------------------------|-------|-----------------|-----------------------------|------|------------------|-----------------|\n| MS-01 (i9-13900H)         | 3     | 1.92TB M.2 NVMe | 3.84TB U.2 NVMe (rook-ceph) | 96GB | Talos            | Kubernetes      |\n| USW Pro Max 24 PoE        | 1     | -               | -                           | -    | UniFi OS         | 2.5G PoE Switch |\n| USW Pro Aggregation       | 1     | -               | -                           | -    | UniFi OS         | 10G/25G Switch  |\n| USP PDU Pro               | 1     | -               | -                           | -    | UniFi OS         | PDU             |\n| UDM Pro Max               | 1     | -               | 2x16TB HDD                  | -    | UniFi OS         | Router \u0026 NVR    |\n| Synology NAS RS1221+      | 1     | -               | 8x22TB HDD                  | 32GB | -                | NFS             |\n| APC SMT15000RM2UNC        | 1     | -               | -                           | -    | -                | UPS             |\n| TESmart 8 Port KVM Switch | 1     | -               | -                           | -    | -                | KVM             |\n| PiKVM (RasPi 4)           | 1     | 64GB (SD)       | -                           | 4GB  | PiKVM (Arch)     | KVM             |\n---\n\n## ⭐ Stargazers\n\n\u003cdiv align=\"center\"\u003e\n\n\u003ca href=\"https://star-history.com/#buroa/k8s-gitops\u0026Date\"\u003e\n  \u003cpicture\u003e\n    \u003csource media=\"(prefers-color-scheme: dark)\" srcset=\"https://api.star-history.com/svg?repos=buroa/k8s-gitops\u0026type=Date\u0026theme=dark\" /\u003e\n    \u003csource media=\"(prefers-color-scheme: light)\" srcset=\"https://api.star-history.com/svg?repos=buroa/k8s-gitops\u0026type=Date\" /\u003e\n    \u003cimg alt=\"Star History Chart\" src=\"https://api.star-history.com/svg?repos=buroa/k8s-gitops\u0026type=Date\" /\u003e\n  \u003c/picture\u003e\n\u003c/a\u003e\n\n\u003c/div\u003e\n\n---\n\n## 🤝 Gratitude and Thanks\n\nMany thanks to my friend [@onedrop](https://github.com/onedr0p) and all the fantastic people who donate their time to the [Home Operations](https://discord.gg/home-operations) Discord community. Be sure to check out [kubesearch.dev](https://kubesearch.dev) for ideas on how to deploy applications or get ideas on what you may deploy.\n\n---\n\n## 📜 Changelog\n\nSee the latest [release](https://github.com/buroa/k8s-gitops/releases/latest) notes.\n\n---\n\n## 🔏 License\n\nSee [LICENSE](./LICENSE).\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fburoa%2Fk8s-gitops","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fburoa%2Fk8s-gitops","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fburoa%2Fk8s-gitops/lists"}