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)
This commit is contained in:
parent
ed5d39efa2
commit
1ccccde18d
3 changed files with 422 additions and 0 deletions
107
README.md
Normal file
107
README.md
Normal file
|
|
@ -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)
|
||||
```
|
||||
170
docs/presentation/final-talk.md
Normal file
170
docs/presentation/final-talk.md
Normal file
|
|
@ -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 <commit>` + `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?"
|
||||
145
docs/vm-setup.md
Normal file
145
docs/vm-setup.md
Normal file
|
|
@ -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 |
|
||||
Loading…
Add table
Reference in a new issue