From 1ccccde18d6333581473b28a8b20f233f04879d7 Mon Sep 17 00:00:00 2001 From: Paul Harkink Date: Sat, 28 Feb 2026 15:36:25 +0100 Subject: [PATCH] docs: README, vm-setup guide, and final presentation outline - README.md: quick start, exercise table, stack versions, solution branches - docs/vm-setup.md: VirtualBox + Vagrant setup, verification, troubleshooting - docs/presentation/final-talk.md: 20-min talk outline (architecture, why GitOps, what's next) --- README.md | 107 ++++++++++++++++++++ docs/presentation/final-talk.md | 170 ++++++++++++++++++++++++++++++++ docs/vm-setup.md | 145 +++++++++++++++++++++++++++ 3 files changed, 422 insertions(+) create mode 100644 README.md create mode 100644 docs/presentation/final-talk.md create mode 100644 docs/vm-setup.md diff --git a/README.md b/README.md new file mode 100644 index 0000000..63c426e --- /dev/null +++ b/README.md @@ -0,0 +1,107 @@ +# Kubernetes GitOps Workshop + +A hands-on 2.5–4 hour workshop teaching real-world cluster operations using +ArgoCD, MetalLB, Ingress-Nginx, and Tekton — all on a local single-node k3s cluster. + +--- + +## Quick start + +### Requirements + +- [VirtualBox 7.x](https://www.virtualbox.org/wiki/Downloads) +- [Vagrant 2.4.x](https://developer.hashicorp.com/vagrant/downloads) +- Git +- 12 GB RAM free on your laptop, ~15 GB disk + +### 1. Start the VM + +```bash +git clone https://github.com/innspire/ops-demo.git +cd ops-demo +vagrant up # first run: ~10–15 min +vagrant ssh +cd /vagrant +``` + +See [docs/vm-setup.md](docs/vm-setup.md) for verification steps and troubleshooting. + +### 2. Bootstrap ArgoCD + +```bash +./scripts/bootstrap.sh +``` + +Then follow the exercises in order. + +--- + +## Exercises + +| # | Exercise | Guide | Type | Est. Time | +|---|----------|-------|------|-----------| +| 01 | Bootstrap ArgoCD | [docs/01-argocd-bootstrap.md](docs/01-argocd-bootstrap.md) | Core | 30 min | +| 02 | Deploy podinfo via GitOps | [docs/02-deploy-podinfo.md](docs/02-deploy-podinfo.md) | Core | 30 min | +| 03 | MetalLB + Ingress-Nginx | [docs/03-metallb-ingress.md](docs/03-metallb-ingress.md) | Core | 45 min | +| 04 | Tekton pipeline | [docs/04-tekton-pipeline.md](docs/04-tekton-pipeline.md) | Core | 45 min | +| 05 | App upgrade + reflection | [docs/05-app-upgrade.md](docs/05-app-upgrade.md) | Core | 15 min | +| 06 | Prometheus + Grafana | [docs/06-monitoring.md](docs/06-monitoring.md) | Bonus | 60 min | + +**Beginners**: aim for Exercises 01–03 (~1h45m). +**Everyone else**: target 01–05 for the full core loop. + +--- + +## Stack + +| Component | Purpose | Version | +|-----------|---------|---------| +| k3s | Kubernetes | v1.31.4 | +| ArgoCD | GitOps engine | v2.13.x (chart 7.7.11) | +| MetalLB | Bare-metal LoadBalancer | v0.14.9 | +| Ingress-Nginx | HTTP routing | chart 4.12.0 | +| Tekton | CI pipeline | v0.65.1 | +| podinfo | Demo app | 6.6.2 → 6.7.0 | +| kube-prometheus-stack | Observability (bonus) | chart 68.4.4 | + +--- + +## Solution branches + +Stuck on an exercise? Each solution branch is cumulative — it contains the complete +working state up to and including that exercise. + +```bash +# View a specific file without checking out the branch +git fetch origin +git show origin/solution/03-metallb-ingress:manifests/networking/metallb/metallb-config.yaml +``` + +| Branch | State | +|--------|-------| +| `solution/01-argocd-bootstrap` | ArgoCD running | +| `solution/02-deploy-podinfo` | podinfo synced via ArgoCD | +| `solution/03-metallb-ingress` | LAN access via MetalLB + Ingress | +| `solution/04-tekton-pipeline` | Full GitOps CI loop | +| `solution/05-app-upgrade` | podinfo at v6.7.0 | +| `solution/06-monitoring` | Prometheus + Grafana running | + +--- + +## Network layout + +``` +Your laptop + │ + │ 192.168.56.x (VirtualBox host-only) + ▼ +VM: 192.168.56.10 + │ + └── MetalLB pool: 192.168.56.200–192.168.56.220 + │ + └── 192.168.56.200 → Ingress-Nginx + │ + ├── podinfo.192.168.56.200.nip.io + ├── argocd.192.168.56.200.nip.io + └── grafana.192.168.56.200.nip.io (bonus) +``` diff --git a/docs/presentation/final-talk.md b/docs/presentation/final-talk.md new file mode 100644 index 0000000..6ff18f5 --- /dev/null +++ b/docs/presentation/final-talk.md @@ -0,0 +1,170 @@ +# Final Talk — GitOps in Practice + +**Duration**: ~20 min + Q&A +**Format**: Slides or whiteboard; optional live demo + +--- + +## 1. What We Built (7 min) + +### Architecture diagram + +``` +┌─────────────────────────────────────────────────────────┐ +│ Your Laptop │ +│ │ +│ Browser ──────────────────────────────────────────► │ +│ podinfo.192.168.56.200.nip.io │ +│ argocd.192.168.56.200.nip.io │ +│ grafana.192.168.56.200.nip.io (bonus) │ +└────────────────────────┬────────────────────────────────┘ + │ VirtualBox host-only + ▼ 192.168.56.200 (MetalLB) +┌─────────────────────────────────────────────────────────┐ +│ VM: ops-demo (192.168.56.10) │ +│ │ +│ ┌──────────────────┐ ┌───────────────────────────┐ │ +│ │ Ingress-Nginx │ │ ArgoCD │ │ +│ │ (LB: .200) │ │ watches this Git repo │ │ +│ └──────┬───────────┘ └───────────┬───────────────┘ │ +│ │ │ syncs │ +│ ▼ ▼ │ +│ ┌──────────────────┐ ┌───────────────────────────┐ │ +│ │ podinfo │ │ MetalLB │ │ +│ │ (Deployment) │ │ (assigns LAN IPs) │ │ +│ └──────────────────┘ └───────────────────────────┘ │ +│ │ +│ ┌──────────────────────────────────────────────────┐ │ +│ │ Tekton Pipeline │ │ +│ │ clone → validate → bump tag → git push │ │ +│ └──────────────────────────────────────────────────┘ │ +└─────────────────────────────────────────────────────────┘ +``` + +### The GitOps loop (narrate this) + +1. Everything in the cluster is defined in **this Git repo** +2. ArgoCD watches the repo and reconciles the cluster to match +3. The Tekton pipeline is itself deployed by ArgoCD — and it pushes commits that ArgoCD then syncs +4. The only `kubectl apply` you ran today was: bootstrap ArgoCD + trigger PipelineRun + +### Stack recap + +| Component | Role | +|-----------|------| +| k3s | Single-binary Kubernetes | +| ArgoCD | GitOps engine (App-of-Apps) | +| MetalLB | Bare-metal LoadBalancer | +| Ingress-Nginx | HTTP routing by hostname | +| Tekton | CI pipeline (in-cluster) | +| podinfo | Demo application | +| kube-prometheus-stack | Observability (bonus) | + +--- + +## 2. Why GitOps in Production (8 min) + +### The old way: imperative deploys + +```bash +# Someone runs this on a Friday afternoon +kubectl set image deployment/api api=company/api:v2.3.1-hotfix +# No review. No audit trail. No way to know who ran it at 16:47. +``` + +### The GitOps way + +``` +PR: "bump API to v2.3.1-hotfix" + → peer review + → merge + → ArgoCD syncs + → deploy happens + → Git commit IS the audit trail +``` + +### Key benefits + +**Audit trail**: Every cluster change has a Git commit — who, what, when, why. + +**Drift detection**: If someone `kubectl apply`s directly, ArgoCD detects the drift and can auto-revert. The cluster always converges to what's in Git. + +**Disaster recovery**: The cluster is destroyed? `vagrant up` + `./scripts/bootstrap.sh` + `kubectl apply -f apps/root.yaml` — and ArgoCD recreates everything. Git is the backup. + +**Multi-team collaboration**: Developers open PRs to deploy. Ops reviews the manifest changes. No SSH keys to production. + +**Rollback**: `git revert ` + `git push`. No special tooling. + +### The App-of-Apps pattern (brief) + +One root Application manages all other Applications. Adding a new service = adding a single YAML file to `apps/`. The root app picks it up automatically. + +``` +apps/root.yaml ──manages──► apps/argocd.yaml + apps/apps/podinfo.yaml + apps/networking/metallb.yaml + apps/networking/ingress-nginx.yaml + apps/ci/tekton.yaml + apps/ci/pipeline.yaml + apps/monitoring/prometheus-grafana.yaml +``` + +--- + +## 3. What's Next (5 min) + +### Secrets management + +Today: plain Kubernetes Secrets with GitHub PATs. +Production: **Vault + external-secrets-operator** + +``` +Vault (secret store) + → external-secrets-operator pulls secrets + → creates Kubernetes Secrets + → ArgoCD syncs everything else +``` + +### Multi-cluster with ApplicationSets + +Today: one cluster, one repo. +Production: 10 clusters, one repo. + +```yaml +# ArgoCD ApplicationSet: deploy podinfo to every cluster in a list +generators: + - list: + elements: + - cluster: staging + - cluster: prod-eu + - cluster: prod-us +``` + +### Progressive delivery + +Today: rolling update (all-or-nothing). +Production: **Argo Rollouts** with canary or blue/green strategies. + +``` +New version → 5% of traffic + → metrics look good → 20% → 50% → 100% + → metrics bad → auto-rollback +``` + +--- + +## Optional live demo (~5 min) + +Make a one-line change to `manifests/apps/podinfo/deployment.yaml` (e.g. UI color), +push to GitHub, click **Refresh** in ArgoCD, and show the pod restart and new UI. + +The audience has already done this — seeing it narrated makes the loop visceral. + +--- + +## Q&A prompts (if the room is quiet) + +- "How would you handle database migrations in a GitOps flow?" +- "What happens if two people push to Git at the same time?" +- "When is GitOps NOT the right tool?" (answer: local dev, scripts, one-off jobs) +- "How do you keep secrets out of Git at scale?" diff --git a/docs/vm-setup.md b/docs/vm-setup.md new file mode 100644 index 0000000..f02aa4c --- /dev/null +++ b/docs/vm-setup.md @@ -0,0 +1,145 @@ +# VM Setup — Getting Started + +Everything runs inside a VirtualBox VM provisioned by Vagrant. +This page walks you through starting the VM and verifying it is healthy before the workshop begins. + +--- + +## Requirements (install on your laptop before the workshop) + +| Tool | Version | Download | +|------|---------|----------| +| VirtualBox | 7.x | https://www.virtualbox.org/wiki/Downloads | +| Vagrant | 2.4.x | https://developer.hashicorp.com/vagrant/downloads | +| Git | any | https://git-scm.com/downloads | + +**RAM**: The VM uses 8 GB. Your laptop should have at least 12 GB total RAM free. +**Disk**: ~15 GB free (Vagrant box ~1 GB + k3s images ~5 GB + workspace). + +--- + +## Step 1 — Clone the repo + +```bash +git clone https://github.com/innspire/ops-demo.git +cd ops-demo +``` + +--- + +## Step 2 — Start the VM + +```bash +vagrant up +``` + +First run takes **10–15 minutes**: Vagrant downloads the Ubuntu 24.04 box, installs +k3s, Helm, yq, and pre-pulls the workshop container images. Subsequent `vagrant up` +calls start the existing VM in under a minute. + +You should see: +``` +════════════════════════════════════════════════════════ + VM provisioned successfully! + SSH: vagrant ssh + Next step: follow docs/vm-setup.md to verify, then + run scripts/bootstrap.sh to install ArgoCD +════════════════════════════════════════════════════════ +``` + +--- + +## Step 3 — SSH into the VM + +```bash +vagrant ssh +``` + +You are now inside the VM. All workshop commands run here unless stated otherwise. + +--- + +## Step 4 — Verify the setup + +```bash +# 1. k3s is running +kubectl get nodes +# NAME STATUS ROLES AGE VERSION +# ops-demo Ready control-plane,master Xm v1.31.x+k3s1 + +# 2. Helm is available +helm version +# version.BuildInfo{Version:"v3.16.x", ...} + +# 3. The workshop repo is mounted at /vagrant +ls /vagrant +# apps/ docs/ manifests/ scripts/ Vagrantfile README.md + +# 4. The host-only interface has the right IP +ip addr show eth1 +# inet 192.168.56.10/24 +``` + +--- + +## Step 5 — Verify host connectivity + +From your **laptop** (not the VM), confirm you can reach the VM's host-only IP: + +```bash +ping 192.168.56.10 +``` + +If this times out, check your VirtualBox host-only network adapter: + +```bash +# macOS/Linux +VBoxManage list hostonlyifs +# Should show vboxnet0 with IP 192.168.56.1 + +# Windows +VBoxManage list hostonlyifs +``` + +If no host-only adapter exists: +```bash +VBoxManage hostonlyif create +VBoxManage hostonlyif ipconfig vboxnet0 --ip 192.168.56.1 --netmask 255.255.255.0 +``` + +Then re-run `vagrant up`. + +--- + +## Working directory + +Inside the VM, the repo is available at `/vagrant` (a VirtualBox shared folder). +All workshop commands are run from `/vagrant`: + +```bash +cd /vagrant +``` + +--- + +## Stopping and restarting the VM + +```bash +vagrant halt # graceful shutdown (preserves state) +vagrant up # restart +vagrant suspend # pause (faster resume, uses disk space) +vagrant resume # resume from suspend +vagrant destroy # delete the VM entirely (start fresh) +``` + +--- + +## Troubleshooting + +| Symptom | Fix | +|---------|-----| +| `vagrant up` fails: VT-x/AMD-V not enabled | Enable virtualisation in BIOS/UEFI settings | +| `vagrant up` fails: port conflict | Another VM may be using the host-only range; stop it | +| `kubectl get nodes` shows NotReady | k3s is still starting; wait 30–60 s | +| `/vagrant` is empty inside VM | Shared folder issue; try `vagrant reload` | +| Very slow image pulls | Images should be pre-pulled; if not, wait 5–10 min |