... managed by Flux, Renovate, GitHub Actions, Terraform, Ansible, and Powershell 🤖
👋 Welcome to my Home Operations repository, tnwks /tee-networks/. This is a mono repository that serves as the foundation for my home infrastructure.
I try to adhere to Infrastructure as Code (IaC) and GitOps practices using the tools like Ansible, Terraform, Kubernetes, Flux, Renovate and GitHub Actions.
The cluster is running on VMs hosted on Proxmox Virtual Environment, an open-source hypervisor built on Debian. A PVE Ceph Cluster is handling my VM storage, along with an externally-connected implementation of Rook Ceph that is providing my K8s workloads with persistent block, object, and file storage.
- actions-runner-controller: Self-hosted Github runners.
- cilium: Internal Kubernetes networking plugin.
- cert-manager: Creates SSL certificates for services in my Kubernetes cluster.
- external-dns: Automatically manages DNS records from my cluster in a cloud DNS provider.
- external-secrets: Managed Kubernetes secrets using 1Password Connect.
- ingress-nginx: Ingress controller to expose HTTP traffic to pods over DNS.
- rook: Distributed block storage for peristent storage.
- sops: Managed secrets for Kubernetes, Ansible and Terraform which are commited to Git.
- volsync and snapscheduler: Backup and recovery of persistent volume claims.
Flux watches my kubernetes folder (see Directories below) and makes the changes to my cluster based on the YAML manifests.
The way Flux works for me here is it will recursively search the kubernetes/apps folder until it finds the most top level kustomization.yaml
per directory and then apply all the resources listed in it. That aforementioned kustomization.yaml
will generally only have a namespace resource and one or many Flux kustomizations. Those Flux kustomizations will generally have a HelmRelease
or other resources related to the application underneath it which will be applied.
Renovate watches my entire repository looking for dependency updates, when they are found a PR is automatically created. When some PRs are merged Flux applies the changes to my cluster.
This Git repository contains the following directories under kubernetes.
📁 kubernetes # Kubernetes cluster defined as code
├─📁 bootstrap # Flux installation
├─📁 flux # Main Flux configuration of repository
└─📁 apps # Apps deployed into my cluster grouped by namespace (see below)
Below is a a high level look at the layout of how my directory structure with Flux works. In this brief example you are able to see that authelia
will not be able to run until glauth
and cloudnative-pg
are running. It also shows that the Cluster
custom resource depends on the cloudnative-pg
Helm chart. This is needed because cloudnative-pg
installs the Cluster
custom resource definition in the Helm chart.
# Key: <kind> :: <metadata.name>
GitRepository :: k8s-gitops
Kustomization :: cluster
Kustomization :: cluster-apps
Kustomization :: cluster-apps-authelia
DependsOn:
Kustomization :: cluster-apps-glauth
Kustomization :: cluster-apps-cloudnative-pg-cluster
HelmRelease :: authelia
Kustomization :: cluster-apps-glauth
HelmRelease :: glauth
Kustomization :: cluster-apps-cloudnative-pg
HelmRelease :: cloudnative-pg
Kustomization :: cluster-apps-cloudnative-pg-cluster
DependsOn:
Kustomization :: cluster-apps-cloudnative-pg
Cluster :: postgres
Name | CIDR |
---|---|
Kubernetes Nodes VLAN | 10.0.0.0/24 |
Kubernetes external services (Cilium w/ BGP) | 7.0.0.0/8 |
Kubernetes pods | 10.244.0.0/16 |
Kubernetes services | 10.245.0.0/16 |
- Cilium is configured with the
io.cilium/lb-ipam-ips
annotation to expose Kubernetes services with their own IP over BGP which is configured on my router. - cloudflared provides a secure tunnel for Cloudflare to ingress traffic from the Internet into my Kubernetes cluster.
blocky provides the first hop of DNS resolution inside my network. DNS requests to my public domain are forwarded to k8s-gateway which checks to see if it's present in my cluster; if not, it talks out to 1.1.1.1 which is configured as my primary DNS provider.
external-dns is deployed in my cluster and configured to sync DNS records to Cloudflare. The only ingresses this external-dns
instance looks at to gather DNS records to put in Cloudflare
are ones that have an annotation of external-dns.alpha.kubernetes.io/target
.
The documentation that goes along with this repo can be found over here.
Device | Count | OS Disk Size | Data Disk Size | Ram | Operating System | Purpose |
---|---|---|---|---|---|---|
Ubiquiti Edge Router Lite | 1 | - | - | - | - | Router |
Unifi UDM Pro | 1 | - | - | - | - | Router |
UISP EdgePoint R6 | 1 | - | - | - | - | Router |
airMAX LiteAP 5AC | 1 | - | - | - | - | AP |
airMAX LiteBeam AC Gen2 | 1 | - | - | - | - | AP |
UAP-AC-Pro | 2 | - | - | - | - | AP |
UAP-AC-HD | 1 | - | - | - | - | AP |
HP 1810g | 1 | - | - | - | - | Switch |
Aruba S2500-24P | 1 | - | - | - | - | Switch |
HP DL360p G8 | 3 | 16GB JetFlash 780 | 1.2TB HDD, 960GB Samsung PM1633a | 64GB | PVE | Hypervisor |
Whitebox NAS | 1 | 64GB SATA SSD | 2x 2TB WD Purple HDD | 16GB | FreeNAS | NVR |
CyberPower CP1500AVR | 1 | - | - | - | - | UPS |
Thanks to all the people who donate their time to the Kubernetes @Home Discord community. A lot of inspiration for my cluster comes from the people that have shared their clusters using the k8s-at-home GitHub topic. Be sure to check out the Kubernetes @Home search for ideas on how to deploy applications or get ideas on what you can deploy.
See LICENSE