Skip to content

Commit 61f7146

Browse files
feat(docs): Add troubleshooting guide for k3s, Traefik, cert-manager, and monitoring
- Created troubleshooting.md with common issues and resolutions for k3s, Traefik, and cert-manager. - Added detailed sections for node readiness, certificate errors, and worker node issues. - Included troubleshooting steps for Grafana and Prometheus in the monitoring section. feat(docs): Document cert-manager installation and usage - Added cert-manager.md detailing automatic TLS certificate issuance and renewal. - Explained the architecture, installation process, and usage of ClusterIssuers. - Included examples for using certificates in IngressRoutes and checking certificate status. feat(docs): Introduce k3s documentation - Created k3s.md outlining the lightweight Kubernetes distribution. - Explained architecture, prerequisites, installation flags, and firewall rules. - Documented the installation workflow for master and worker nodes. feat(docs): Add monitoring and observability documentation - Created monitoring.md detailing the observability stack components and architecture. - Documented deployment steps for kube-prometheus-stack, Loki, and Promtail. - Included Grafana access instructions and available dashboards. feat(docs): Document Traefik ingress controller setup - Added traefik.md explaining Traefik's role as the ingress controller. - Documented Helm installation, entry points, and TLS hardening. - Included instructions for creating the Traefik dashboard and deploying services. fix(makefiles): Update paths for k3s-lab - Changed references from k3s-homelab to k3s-lab in makefiles for consistency. - Updated paths in k3s installation, kubeconfig fetching, and stack deployment scripts.
1 parent 6cd169d commit 61f7146

File tree

18 files changed

+2016
-102
lines changed

18 files changed

+2016
-102
lines changed

.env.example

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ MASTER_IP=1.2.3.4 # Public IP of the master (control-plane) VPS
88
WORKER_IP=5.6.7.8 # Public IP of the worker VPS
99

1010
# --- SSH ---
11-
SSH_USER=kevin # SSH user AFTER bootstrap (regular user, not root)
11+
SSH_USER=debian # SSH user AFTER bootstrap (regular user, not root)
1212
SSH_KEY=~/.ssh/id_ed25519 # Path to your private key
1313
INITIAL_USER=root # User for the first connection (before bootstrap)
1414

.github/workflows/ci-cd.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
# =============================================================================
2-
# CI — k3s-homelab lint, tests & security
2+
# CI — k3s-lab lint, tests & security
33
#
44
# Runs on every push and PR to main.
55
# Does NOT require a real cluster — all checks are static/offline.

Makefile

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,18 @@ SHELL := /bin/bash
66
export
77

88
# Defaults (overridable via .env or environment)
9-
SSH_USER ?= kevin
9+
SSH_USER ?= debian
1010
SSH_PORT ?= 22
1111
SSH_KEY ?= $(HOME)/.ssh/id_ed25519
1212
SSH_KEY := $(subst ~,$(HOME),$(SSH_KEY))
1313
INITIAL_USER ?= root
1414
MASTER_IP ?=
1515
WORKER_IP ?=
16-
KUBECONFIG_CONTEXT ?= k3s-homelab
16+
KUBECONFIG_CONTEXT ?= k3s-lab
1717
K3S_VERSION ?= v1.32.2+k3s1
1818

1919
# Root of this repo (works whether used standalone or as a submodule)
20-
K3S_HOMELAB := $(abspath $(dir $(MAKEFILE_LIST)))
20+
K3S_LAB := $(abspath $(dir $(MAKEFILE_LIST)))
2121

2222
# Terminal colors
2323
GREEN := \033[0;32m

README.md

Lines changed: 37 additions & 84 deletions
Original file line numberDiff line numberDiff line change
@@ -1,106 +1,59 @@
1-
# k3s-homelab
1+
# k3s-lab
22

3-
> Reusable k3s cluster setup — scripts, Kubernetes manifests, and Makefile targets for a production-ready lightweight Kubernetes cluster on VPS nodes.
3+
> Production-ready k3s cluster on VPS — automated setup with Traefik, cert-manager, Prometheus, Grafana, Loki, and Promtail.
4+
5+
[![CI / CD](https://github.com/KevinDeBenedetti/k3s-lab/actions/workflows/ci-cd.yml/badge.svg)](https://github.com/KevinDeBenedetti/k3s-lab/actions/workflows/ci-cd.yml)
46

57
## Stack
68

79
| Tool | Role |
8-
|------|------|
10+
|---|---|
911
| [k3s](https://k3s.io) | Lightweight Kubernetes distribution |
10-
| [Traefik](https://traefik.io) | Ingress controller + HTTPS reverse proxy |
12+
| [Traefik](https://traefik.io) | Ingress controller + HTTPS |
1113
| [cert-manager](https://cert-manager.io) | Automatic TLS via Let's Encrypt |
14+
| [kube-prometheus-stack](https://github.com/prometheus-community/helm-charts) | Prometheus + Grafana + Alertmanager |
1215
| [Loki](https://grafana.com/oss/loki/) | Centralized log storage |
13-
| [Promtail](https://grafana.com/docs/loki/latest/send-data/promtail/) | Kubernetes log collector |
14-
| [kube-prometheus-stack](https://github.com/prometheus-community/helm-charts) | Prometheus + Grafana monitoring |
15-
16-
## Repository Layout
17-
18-
```
19-
.
20-
├── .env.example # Environment variables template — copy to .env
21-
├── k3s/
22-
│ ├── install-master.sh # Bootstrap the control-plane node
23-
│ ├── install-worker.sh # Join a worker node to the cluster
24-
│ └── uninstall.sh # Remove k3s from a node
25-
├── kubernetes/
26-
│ ├── namespaces/ # apps, ingress, cert-manager, monitoring
27-
│ ├── ingress/ # Traefik Helm values + secured dashboard
28-
│ ├── cert-manager/ # Let's Encrypt ClusterIssuers
29-
│ ├── monitoring/ # Prometheus, Grafana, Loki, Promtail
30-
│ └── apps/ # Example app deployment + ingress
31-
├── lib/
32-
│ ├── load-env.sh # .env loader (no-overwrite semantics)
33-
│ ├── log.sh # Coloured logging helpers
34-
│ └── ssh-opts.sh # SSH_OPTS array builder
35-
├── makefiles/ # Modular Makefile targets
36-
│ ├── 10-help.mk # Auto-generated help
37-
│ ├── 30-k3s.mk # k3s install / uninstall
38-
│ ├── 40-kubeconfig.mk # Fetch & merge kubeconfig
39-
│ ├── 50-deploy.mk # Deploy base + monitoring stack
40-
│ ├── 60-status.mk # Cluster status helpers
41-
│ └── 70-ssh.mk # SSH shortcuts
42-
└── scripts/
43-
├── deploy-stack.sh # Deploy Traefik + cert-manager (local machine)
44-
├── deploy-monitoring.sh # Deploy Prometheus + Grafana + Loki + Promtail
45-
└── get-kubeconfig.sh # Fetch & merge kubeconfig from master
46-
```
16+
| [Promtail](https://grafana.com/docs/loki/latest/send-data/promtail/) | Log collector |
4717

48-
## Quick Start
18+
## Quick start
4919

5020
```bash
51-
# 1. Copy and fill in your values
52-
cp .env.example .env
53-
54-
# 2. Install k3s on the master node
55-
make k3s-master
56-
57-
# 3. Fetch kubeconfig
58-
make kubeconfig
59-
60-
# 4. Deploy the base stack (Traefik + cert-manager)
61-
make deploy
62-
63-
# 5. Deploy monitoring (Prometheus + Grafana + Loki)
64-
make deploy-monitoring
21+
cp .env.example .env # Fill in your values
22+
make k3s-master # Bootstrap control plane (~5 min)
23+
make k3s-worker # Join worker node (~3 min)
24+
make kubeconfig # Fetch kubeconfig
25+
make deploy-dashboard-secret
26+
make deploy # Traefik + cert-manager (~3 min)
27+
make deploy-grafana-secret
28+
make deploy-monitoring # Prometheus + Grafana + Loki (~10 min)
6529
```
6630

67-
## Available Targets
31+
## Documentation
6832

69-
```
70-
make help
71-
```
33+
📖 **[kevindebenedetti.github.io/k3s-lab](https://kevindebenedetti.github.io/k3s-lab)**
7234

73-
## Usage as a Git Submodule
35+
| | |
36+
|---|---|
37+
| [Getting started](https://kevindebenedetti.github.io/k3s-lab/getting-started) | Prerequisites, step-by-step deploy |
38+
| [Configuration](https://kevindebenedetti.github.io/k3s-lab/configuration) | All `.env` variables |
39+
| [k3s](https://kevindebenedetti.github.io/k3s-lab/stack/k3s) | Install flags, sysctl, firewall |
40+
| [Traefik](https://kevindebenedetti.github.io/k3s-lab/stack/traefik) | Ingress, TLS, dashboard |
41+
| [cert-manager](https://kevindebenedetti.github.io/k3s-lab/stack/cert-manager) | Let's Encrypt, HTTP-01 |
42+
| [Monitoring](https://kevindebenedetti.github.io/k3s-lab/stack/monitoring) | Prometheus, Grafana, Loki |
43+
| [Make targets](https://kevindebenedetti.github.io/k3s-lab/operations/make-targets) | Full `make` reference |
44+
| [Troubleshooting](https://kevindebenedetti.github.io/k3s-lab/operations/troubleshooting) | Common issues |
7445

75-
This repo is designed to be embedded in a private infra repo:
46+
## Submodule usage
7647

7748
```bash
78-
git submodule add git@github.com:KevinDeBenedetti/k3s-homelab.git k3s-homelab
49+
git submodule add https://github.com/KevinDeBenedetti/k3s-lab.git k3s-lab
7950
```
8051

81-
In the parent `Makefile`:
82-
8352
```makefile
84-
K3S_HOMELAB := $(ROOT_DIR)/k3s-homelab
85-
include $(K3S_HOMELAB)/makefiles/30-k3s.mk
86-
include $(K3S_HOMELAB)/makefiles/40-kubeconfig.mk
87-
include $(K3S_HOMELAB)/makefiles/50-deploy.mk
88-
include $(K3S_HOMELAB)/makefiles/60-status.mk
89-
include $(K3S_HOMELAB)/makefiles/70-ssh.mk
53+
K3S_LAB := $(ROOT_DIR)/k3s-lab
54+
include $(K3S_LAB)/makefiles/30-k3s.mk
55+
include $(K3S_LAB)/makefiles/40-kubeconfig.mk
56+
include $(K3S_LAB)/makefiles/50-deploy.mk
57+
include $(K3S_LAB)/makefiles/60-status.mk
58+
include $(K3S_LAB)/makefiles/70-ssh.mk
9059
```
91-
92-
## Environment Variables
93-
94-
See [.env.example](.env.example) for the full list. Key variables:
95-
96-
| Variable | Description |
97-
|----------|-------------|
98-
| `MASTER_IP` | Public IP of the master VPS |
99-
| `WORKER_IP` | Public IP of the worker VPS |
100-
| `SSH_USER` | SSH user (default: `kevin`) |
101-
| `SSH_KEY` | Path to SSH private key |
102-
| `K3S_VERSION` | Pinned k3s version |
103-
| `DOMAIN` | Primary domain (e.g. `example.com`) |
104-
| `EMAIL` | Let's Encrypt registration email |
105-
| `GRAFANA_DOMAIN` | Grafana dashboard domain |
106-
| `KUBECONFIG_CONTEXT` | kubectl context name |

docs/.vitepressrc.json

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
2-
"title": "k3s-homelab",
3-
"description": "Reusable GitHub automation scripts, stack makefile fragments, Docker templates, and a Rust CLI for developer workflows.",
4-
"icon": "🛠",
2+
"title": "k3s-lab",
3+
"description": "Production-ready k3s cluster on VPS — automated setup with Traefik, cert-manager, Prometheus, Grafana, Loki, and Promtail.",
4+
"icon": "",
55
"order": 5,
6-
"repo": "KevinDeBenedetti/k3s-homelab"
6+
"repo": "KevinDeBenedetti/k3s-lab"
77
}

docs/configuration.md

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
# Configuration Reference
2+
3+
All configuration is managed through a `.env` file at the repository root. Copy the template and fill in your values:
4+
5+
```bash
6+
cp .env.example .env
7+
```
8+
9+
> ⚠️ **Never commit `.env` to git.** It is listed in `.gitignore`. The `.env.example` file (with placeholder values) is committed instead.
10+
11+
---
12+
13+
## All variables
14+
15+
### VPS nodes
16+
17+
| Variable | Example | Required | Description |
18+
|---|---|---|---|
19+
| `MASTER_IP` | `1.2.3.4` || Public IP of the control-plane VPS |
20+
| `WORKER_IP` | `5.6.7.8` || Public IP of the worker VPS |
21+
22+
### SSH
23+
24+
| Variable | Default | Required | Description |
25+
|---|---|---|---|
26+
| `SSH_USER` | `ubuntu` || SSH user after bootstrap (regular user, not root) |
27+
| `SSH_KEY` | `~/.ssh/id_ed25519` || Path to your SSH private key |
28+
| `INITIAL_USER` | `root` || User for the very first connection (before bootstrap creates `SSH_USER`) |
29+
| `SSH_PORT` | `22` || SSH port (Makefile default, not in `.env.example`) |
30+
31+
> `INITIAL_USER` is only used for the first `make k3s-master` run. After the VPS is bootstrapped with your regular user, `SSH_USER` takes over.
32+
33+
### k3s
34+
35+
| Variable | Example | Required | Description |
36+
|---|---|---|---|
37+
| `K3S_VERSION` | `v1.32.2+k3s1` || Pinned k3s version — must match on master and worker |
38+
| `K3S_NODE_TOKEN` | *(auto-filled)* || Shared secret for worker join — auto-saved by `make k3s-master` |
39+
40+
> `K3S_NODE_TOKEN` is automatically written to `.env` after `make k3s-master` completes. You do not need to generate it manually.
41+
42+
### Helm chart versions
43+
44+
| Variable | Default | Description |
45+
|---|---|---|
46+
| `TRAEFIK_CHART_VERSION` | `34.4.0` | Traefik Helm chart version |
47+
| `CERT_MANAGER_VERSION` | `v1.17.1` | cert-manager Helm chart version |
48+
| `KUBE_PROMETHEUS_VERSION` | `82.10.3` | kube-prometheus-stack chart version |
49+
| `LOKI_VERSION` | `6.35.1` | Loki Helm chart version |
50+
| `PROMTAIL_VERSION` | `6.17.1` | Promtail Helm chart version |
51+
52+
Helm chart versions are pinned and managed by [Renovate](https://docs.renovatebot.com/) via the shared preset in `renovate.json`.
53+
54+
### Application
55+
56+
| Variable | Example | Required | Description |
57+
|---|---|---|---|
58+
| `DOMAIN` | `example.com` || Primary domain (used for app subdomains) |
59+
| `EMAIL` | `admin@example.com` || Email for Let's Encrypt ACME registration |
60+
61+
### Traefik dashboard
62+
63+
| Variable | Example | Required | Description |
64+
|---|---|---|---|
65+
| `DASHBOARD_DOMAIN` | `dashboard.example.com` || Subdomain for the Traefik admin dashboard |
66+
| `DASHBOARD_PASSWORD` | *(htpasswd hash)* || BasicAuth password — set via `make deploy-dashboard-secret` |
67+
68+
> `DASHBOARD_PASSWORD` is the **plain text** password. `make deploy-dashboard-secret` hashes it with `htpasswd -nb admin <password>` before storing it in the Kubernetes Secret.
69+
70+
### Grafana
71+
72+
| Variable | Example | Required | Description |
73+
|---|---|---|---|
74+
| `GRAFANA_DOMAIN` | `grafana.example.com` || Subdomain for Grafana |
75+
| `GRAFANA_PASSWORD` | *(your password)* || Grafana admin password |
76+
77+
### Kubeconfig
78+
79+
| Variable | Default | Required | Description |
80+
|---|---|---|---|
81+
| `KUBECONFIG_CONTEXT` | `k3s-lab` || kubectl context name created by `make kubeconfig` |
82+
83+
---
84+
85+
## Variable precedence
86+
87+
Variables are loaded with **no-overwrite semantics**: a value already set in the shell environment takes precedence over the `.env` file.
88+
89+
This allows Makefile targets to override `.env` at call time:
90+
91+
```bash
92+
make deploy DOMAIN=staging.example.com
93+
```
94+
95+
---
96+
97+
## Minimal `.env` for a first deploy
98+
99+
```bash
100+
# Nodes
101+
MASTER_IP=1.2.3.4
102+
WORKER_IP=5.6.7.8
103+
104+
# SSH
105+
SSH_USER=ubuntu
106+
SSH_KEY=~/.ssh/id_ed25519
107+
108+
# k3s
109+
K3S_VERSION=v1.32.2+k3s1
110+
111+
# Application
112+
DOMAIN=example.com
113+
EMAIL=you@example.com
114+
115+
# Traefik dashboard
116+
DASHBOARD_DOMAIN=dashboard.example.com
117+
DASHBOARD_PASSWORD=changeme
118+
119+
# Grafana
120+
GRAFANA_DOMAIN=grafana.example.com
121+
GRAFANA_PASSWORD=changeme
122+
123+
# Kubeconfig
124+
KUBECONFIG_CONTEXT=k3s-lab
125+
```

0 commit comments

Comments
 (0)