This is a collection of tools and setup scripts to make setting up a home Kubernetes dev environment as painless as possible.
This project focuses on self-hosted projects, allowing you to keep as much of the development lifecycle within your home network as possible.
I've tried to cover as many of the basics as possible, as well as include some useful tools. Most of what I have included are things I have found myself wanting access to at some point, just to make development simpler. That being said, this is mostly tailored to meet my needs. Feel free to fork this repo or make a pull request to make it work for you.
Also, this project does include some AI slop. Mostly in the setup scripts and docs. Just a disclaimer.
Big Disclaimer:
DO NOT RUN THIS IN PRODUCTION
The configs below work for a home environment where you don't really care if you lose data. A lot of the settings below are not appropriate if you are running something that will be public in any way, shape, or form.
I also turn off TLS on EVERYTHING.
- Quickstart
- What's Been Added So Far
- Installation Process
- How to Use This Repo
- Finalize Install
- Post Install Info
- Individual Tools Details
- Creating Secrets and Deploying Them With Vault Secrets Operator
- Wishlist for Future Things to Add (or automate)
- Development
Fill out the configuration.cfg file with your environment-specific values.
For Windows:
.\deploy.batFor Linux:
./deploy.shTemplate-Only Mode: If you want to generate the temp/ directory with all template substitutions without deploying, use the --template-only (or -t) flag:
# Windows
.\deploy.bat --template-only
# Linux
./deploy.sh --template-onlySee the section on [Creating Vault Secrets](### Creating Secrets and Deploying Them With Vault Secrets Operator)
- Istio
- Istio Documentation
- Installed in Ambient mode (configurable via
APPLICATIONS.ISTIO.AMBIENTinconfiguration.cfg) - Acts as the service mesh and ingress gateway using Kubernetes Gateway API
- ArgoCD
- ArgoCD Documentation
- GitOps controller managing all applications
- Prometheus Stack (prometheus-community/kube-prometheus-stack)
- Prometheus
- Prometheus Node Exporter
- Kube State Metrics
- Grafana
- Grafana Loki
- Grafana Loki Documentation
- Log aggregation
- Grafana Tempo
- Grafana Tempo Documentation
- Distributed tracing backend
- Grafana Alloy
- Grafana Alloy Documentation
- Telemetry collection agent
- Cert Manager
- Cert Manager Documentation
- Self-signed wildcard certificate management
- Gateway API
- Gateway API Documentation
- Kubernetes Gateway API for ingress routing with Istio
- Kubernetes Dashboard
- Kubernetes Dashboard Documentation
- Web UI for cluster management with custom reverse proxy
- IT-Tools
- IT-Tools Documentation
- Collection of handy developer tools
- telemetrygen
- telemetrygen Documentation
- Sample telemetry generator for testing observability stack
- HashiCorp Vault
- HashiCorp Vault Documentation
- Secrets management
- Vault Secrets Operator
- Vault Secrets Operator Documentation
- Syncs Vault secrets to Kubernetes
- Keycloak
- Keycloak Documentation
- Identity and access management
- Argo Workflows
- Argo Workflows Documentation
- Workflow orchestration engine
- Gitea
- Gitea Documentation
- Self-hosted Git service with Act Runner for CI/CD
- NATS
- NATS Documentation
- Message broker with web UI
- PGAdmin
- PGAdmin Documentation
- PostgreSQL management tool
- Docker Registry UI
- Docker Registry UI Documentation
- Web interface for browsing Docker registry
- kubectl - Installed and connected to your target Kubernetes cluster
- Helm - Installed and configured (pointing to your cluster)
- Docker (optional) - Required only if you want to use the Kubernetes Dashboard reverse proxy. You'll need to build and push the proxy image to your private registry.
This repo assumes you have a Kubernetes cluster setup, and that your kubectl is pointing to that cluster.
This setup does not require an external load balancer. The Istio Gateway is configured with NodePort services.
When deploying, a patch operation sets the NodePorts to:
- 30080 - HTTP traffic
- 30443 - HTTPS traffic
Configure your router/firewall to forward ports 80 and 443 to these NodePorts on your cluster node.
You MUST have a DNS configuration setup.
Actually, maybe not. You might be able to do this by using an IP address. Honestly, I've never tried. Make a pull request to update this if you try it and it works!
Install Helm. Helm Documentation
Edit the configuration.cfg file with your environment-specific values. The format is simple key-value pairs:
KEY: value
Variables use the format APPLICATIONS.SERVICE.KEY (e.g., APPLICATIONS.GITEA.ADMIN.USERNAME). During deployment, all ${KEY} placeholders in templates are replaced with these values.
Istio can be configured for MicroK8s and Ambient mode via the configuration file:
APPLICATIONS.GLOBAL.MICROK8S: true/false- Enable MicroK8s-specific settingsAPPLICATIONS.ISTIO.AMBIENT: true/false- Enable Istio Ambient mode (sidecar-less service mesh)APPLICATIONS.ISTIO.GLOBAL.PLATFORM: <string>|none- Sets Helm--set global.platform=...for Istio charts (blank/noneomits the flag; supports any Istio-supported platform value)APPLICATIONS.ISTIO.CNI.CHAINED: true|false|none- Sets Helm--set chained=...for the Istio CNI chart (blank/noneomits the flag)
.\deploy.bat./deploy.shTo generate the temp/ directory without deploying:
# Windows
.\deploy.bat --template-only
# Linux
./deploy.sh -tNote: The initial commit to the Gitea repository sometimes fails. If it does, re-run the finalization script located in .\temp\deployments\finalize\ (push-repo.bat or push-repo.sh).
Run the commands to setup Vault and create the secrets for Keycloak.
Simplified instructions are here: Creating Secrets and Deploying Them With Vault Secrets Operator
Set up the following DNS routes to point to your cluster's IP (where the Istio Gateway is exposed on ports 30080/30443).
Using *.example.com to match the default configuration.cfg file. Update to match your APPLICATIONS.GLOBAL.BASE_URL setting.
alloy.example.com
argocd.example.com
kiali.example.com
grafana.example.com
keycloak.example.com
nats.example.com
prometheus.example.com
tools.example.com
vault.example.com
workflows.example.com
pgadmin.example.com
docker.example.com
gitea.example.com
dashboard.example.com
A bookmarks file with all configured URLs is available at docs/bookmarks.md after deployment.
Not everything installed has a section here. This is mostly just capturing what configs are needed.
Istio serves as both the service mesh and ingress gateway. It can be installed in ambient mode (sidcar-less) by setting APPLICATIONS.ISTIO.AMBIENT: true in configuration.cfg.
All namespaces are annotated to be included in the Istio mesh. Ingress routing uses the Kubernetes Gateway API with support for HTTPRoute and TCPRoute resources.
Gateway Configuration:
- Standard Gateway API: v1.4.0
- Experimental features enabled (includes TCPRoute)
- NodePorts: 30080 (HTTP), 30443 (HTTPS)
cert-manager is used to create all our certificates. These are all self-signed wildcard certs.
The Kubernetes Gateway API provides ingress routing capabilities through Istio. Both standard and experimental resources are installed:
- HTTPRoute for HTTP/HTTPS routing
- TCPRoute for TCP-based services
- Gateway resource defining the ingress points
All service routes are defined in /applications/*/routes/ directories and managed by ArgoCD.
The Kubernetes Dashboard provides a web UI for cluster management. Access is secured through a custom reverse proxy that injects the admin bearer token.
Setup Requirements:
-
Build the reverse proxy image:
cd reverse-proxy docker build -t registry.${APPLICATIONS.GLOBAL.BASE_URL}/kube-dash-proxy .
-
Push to your private registry:
docker push registry.${APPLICATIONS.GLOBAL.BASE_URL}/kube-dash-proxyReplace
${APPLICATIONS.GLOBAL.BASE_URL}with your actual domain fromconfiguration.cfg. -
Get the admin token:
kubectl -n kubernetes-dashboard get secret admin-user -o jsonpath="{.data.token}" | base64 -d
-
Access the dashboard: Navigate to
https://dashboard.${APPLICATIONS.GLOBAL.BASE_URL}
Local Testing (optional):
# Port-forward the dashboard service
kubectl -n kubernetes-dashboard port-forward svc/kubernetes-dashboard-kong-proxy 8443:443
# Run the reverse proxy locally
cd reverse-proxy
docker-compose up -d
# Access at http://localhost:8080We install ArgoCD.
To get the default password to login, run this command:
kubectl -n argocd get secret argocd-initial-admin-secret -o jsonpath="{.data.password}" | base64 -dGitea is a self-hosted Git service that hosts the infrastructure repository for ArgoCD.
During deployment:
- Gitea is installed
- An
infrarepository is created - The
applications/,deployments/, andsecrets/directories are committed and pushed - ArgoCD monitors this repository for GitOps automation
Act Runner is included for CI/CD workflows with Docker-in-Docker support.
Access Gitea at https://gitea.${APPLICATIONS.GLOBAL.BASE_URL}
Credentials are defined in configuration.cfg:
- Username:
APPLICATIONS.GITEA.ADMIN.USERNAME - Password:
APPLICATIONS.GITEA.ADMIN.PASSWORD
To access IT-Tools, navigate to https://tools.example.com
To access Grafana, navigate to https://grafana.example.com
Default username is admin
To get the password, run the following command
kubectl get secret --namespace grafana prometheus-grafana -o jsonpath="{.data.admin-password}" | base64 --decode
Once Loki has been deployed, you need to connect it to Grafana.
This should already be done for you, but in case something goes wrong and you need to re-connect it:
In Grafana, add a new Data Source of type Loki.
This is your connection URL:
http://loki.loki.svc.cluster.local:3100
You will also need to add an HTTP Header.
They Header is X-Scope-OrgID, the value needs to match your APPLICATIONS.GRAFANA.HEADER_VALUE config.
After this is completed, you should be able to view the logs through the Explore function in Grafana.
Alloy is setup as a logs/metrics/traces collector.
It should grab all the logs from your pods and make them available in Grafana through Loki. Traces sent to it will be forwarded to Tempo.
Tempo is used to store your traces. The Otlp endpoint is tempo.tempo.svc.cluster.local:4317. From here, configure Grafana to pull them.
Prometheus is deployed as part of the kube-prometheus-stack and automatically scrapes metrics from Kubernetes and Istio.
Access Prometheus at https://prometheus.${APPLICATIONS.GLOBAL.BASE_URL}
Service monitors are defined in /applications/prometheus/monitors/ for custom metric collection.
You will need to run through the vault setup. The ui is available at https://vault.example.com
Keycloak provides identity and access management.
Important: Keycloak will fail to start until you configure Vault secrets. See Creating Secrets and Deploying Them With Vault Secrets Operator.
Access Keycloak at https://keycloak.${APPLICATIONS.GLOBAL.BASE_URL}
Admin credentials are stored in Vault and configured during the Vault setup process.
To connect NUI to your nats server:
- Open the UI
- Create a new connection
- Name can be whatever
- Host is going to be
nats-headless.nats.svc.cluster.local - No auth other settings needed.
This gives you a UI for browsing your docker images. The one we deploy is this one: https://github.com/Joxit/docker-registry-ui
There is a sample telemetry generator app that's installed, mostly to test the observability stuff. Feel free to delete it if you don't want it.
Vault Secrets Operator is installed.
After Vault has been initialized, you can follow the setup instructions here:
https://developer.hashicorp.com/vault/tutorials/kubernetes/vault-secrets-operator#configure-vault
This is how you create the secrets needed for applications, and have them automatically created in Kubernetes with the Vault Secrets Operator.
Keycloak will fail to start until you set this up. But it also forces you to make the Vault deployment healthy, as it requires you to unlock it.
-
Login to vault.
-
Create a new Authentication Method.
- Type should be Kubernetes.
- Being lazy and naming it
kubernetes - Make sure to set the host for the kubernetes api.
- It's probably okay to use
https://kubernetes.default.svc
- It's probably okay to use
-
Create a
Kubernetestype secret engine. Call itkubernetes.- Go to Configuration
- Use the
Local Clusterconfiguration - Create a role in the secrets engine.
- Select
Generate entire Kubernetes object chain - Name it
vault - Type will be
ClusterRole - Allowed Kubernetes Namespaces set to
*
-
Create a new
Policy. Call itkeycloak. Add this policy:path "/keycloak/data/*" { capabilities = ["read", "list"] } -
In the
kubernetesAuthentication Method, add a role.- Name it
keycloak - Audience should be
vault - Bound service account names, add
keycloak - Bound service account namespaces, add
keycloak - Under the
Tokensdropdown, scroll down toGenerated Token's Policies - Add
keycloak.
- Name it
-
Create a new KV Secrets Engine. We'll use the
keycloakdeployment as an example. Name the Secrets Enginekeycloak. -
Create a new
Secretinside thekeycloaksecrets engine.- Name it
postgres - Add the following secret data to it:
- POSTGRES_DB
- POSTGRES_PASSWORD
- POSTGRES_USER
- Name it
-
Create a new
Secretinside thekeycloaksecrets engine.- Name it
keycloak-admin - Add the following secret data to it:
- KC_BOOTSTRAP_ADMIN_PASSWORD
- KC_BOOTSTRAP_ADMIN_USERNAME
- These will be your credentials to login to Keycloak.
- Name it
-
Finally, create your Service Account, VaultAuth, and VaultStaticSecret.
- See
/applications/keycloak/secrets.yamlfor an example.
- See
If you want to create additional secrets for different namespaces, begin from step 4.
Change values as appropriate. For the most part, you can use the /applications/keycloak/secrets.yaml file as a template.
- Kubernetes Automated Install https://kubernetes.io/
- Container Repository https://hub.docker.com/_/registry
- Package Registry TODO: Pick one
- Add Cert Manager to Applications.
There's also a few things that still need to be taken care of as part of this project:
- Move as many secrets as possible to Vault.
- Gitea
- That secret is needed before Vault is setup. Bootstrap paradox.
- PGAdmin
- Just lazy, didn't want to create a super-long readme.
- Gitea
Deployment script workflow:
-
Template Processing:
- Creates
temp/directory - Copies
deployments/,secrets/, andapplications/totemp/ - Reads
configuration.cfgand replaces all${KEY}placeholders with configured values - No external dependencies like
yq- uses native PowerShell/Bash text processing
- Creates
-
Sequential Deployment:
- Deployment directories are processed in numerical order (00, 01, 02, etc.)
- Files within each directory are also processed by number
-
File Type Handling:
.yamlfiles →kubectl apply.opsfiles → Line-by-line command execution (platform-agnostic).batfiles → Windows batch execution.shfiles → Linux shell execution
-
Template-Only Mode:
- Use
--template-onlyor-tflag to generatetemp/without deploying - Useful for verifying template substitutions
- Use
Adding New Services:
- Create directory in
/applications/ - Add ArgoCD Application manifest in
/applications/applications/ - For secrets: follow Vault pattern in
/applications/keycloak/secrets.yaml - For routes: add HTTPRoute/TCPRoute in service's
routes/subdirectory
Adding Deployment Steps:
- Create numbered file in appropriate
/deployments/subdirectory - Use
.opsfor platform-agnostic commands - For platform-specific needs, provide both
.batand.shversions