From a5e57583b53061bdf3936f3e102e74dd223bc32a Mon Sep 17 00:00:00 2001 From: Paul Harkink Date: Sat, 28 Feb 2026 15:26:26 +0100 Subject: [PATCH] feat(ex02): deploy podinfo via GitOps - apps/apps/podinfo.yaml: ArgoCD Application for podinfo - manifests/apps/podinfo/: namespace, deployment (6.6.2), service - docs/01-argocd-bootstrap.md: Exercise 01 participant guide - docs/02-deploy-podinfo.md: Exercise 02 participant guide --- apps/apps/podinfo.yaml | 22 ++++ docs/01-argocd-bootstrap.md | 117 ++++++++++++++++++ docs/02-deploy-podinfo.md | 158 +++++++++++++++++++++++++ manifests/apps/podinfo/deployment.yaml | 42 +++++++ manifests/apps/podinfo/namespace.yaml | 4 + manifests/apps/podinfo/service.yaml | 12 ++ 6 files changed, 355 insertions(+) create mode 100644 apps/apps/podinfo.yaml create mode 100644 docs/01-argocd-bootstrap.md create mode 100644 docs/02-deploy-podinfo.md create mode 100644 manifests/apps/podinfo/deployment.yaml create mode 100644 manifests/apps/podinfo/namespace.yaml create mode 100644 manifests/apps/podinfo/service.yaml diff --git a/apps/apps/podinfo.yaml b/apps/apps/podinfo.yaml new file mode 100644 index 0000000..4c0a779 --- /dev/null +++ b/apps/apps/podinfo.yaml @@ -0,0 +1,22 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: podinfo + namespace: argocd + annotations: + argocd.argoproj.io/sync-wave: "10" +spec: + project: workshop + source: + repoURL: https://github.com/innspire/ops-demo.git + targetRevision: HEAD + path: manifests/apps/podinfo + destination: + server: https://kubernetes.default.svc + namespace: podinfo + syncPolicy: + automated: + prune: true + selfHeal: true + syncOptions: + - CreateNamespace=true diff --git a/docs/01-argocd-bootstrap.md b/docs/01-argocd-bootstrap.md new file mode 100644 index 0000000..2522ba4 --- /dev/null +++ b/docs/01-argocd-bootstrap.md @@ -0,0 +1,117 @@ +# Exercise 01 — Bootstrap ArgoCD + +**Time**: ~30 min +**Goal**: Get ArgoCD running on your local k3s cluster and apply the App-of-Apps root application. + +--- + +## What you'll learn +- How to install ArgoCD via Helm +- The App-of-Apps pattern: one ArgoCD Application that manages all others +- How ArgoCD watches a Git repository and syncs cluster state + +--- + +## Prerequisites + +Make sure your VM is up and you are SSHed in: + +```bash +vagrant up # first time takes ~10 min (downloads images) +vagrant ssh +cd /vagrant +``` + +Verify k3s is healthy: + +```bash +kubectl get nodes +# NAME STATUS ROLES AGE VERSION +# ops-demo Ready control-plane,master Xm v1.31.x+k3s1 +``` + +--- + +## Steps + +### 1. Run the bootstrap script + +```bash +./scripts/bootstrap.sh +``` + +This script: +1. Creates the `argocd` namespace +2. Installs ArgoCD via Helm (chart 7.7.11 → ArgoCD v2.13.x) +3. Applies `apps/project.yaml` — a permissive `AppProject` for all workshop apps +4. Applies `apps/root.yaml` — the App-of-Apps entry point + +At the end it prints the admin password. **Copy it now.** + +--- + +### 2. Open the ArgoCD UI + +In a second terminal on your laptop (not the VM), run: + +```bash +vagrant ssh -- -L 8080:localhost:8080 & +# or, inside the VM: +kubectl port-forward svc/argocd-server -n argocd 8080:443 +``` + +Then open **https://localhost:8080** in your browser (accept the self-signed cert). + +Login: `admin` / `` + +--- + +### 3. Explore the root Application + +In the ArgoCD UI you should see one application: **root**. + +- Click it. Notice it is syncing the `apps/` directory from this repo. +- It found `apps/argocd.yaml` and `apps/project.yaml` and is managing them. +- ArgoCD is now **self-managing** — any change you push to `apps/` will be picked up automatically. + +```bash +# Confirm from the CLI too +kubectl get applications -n argocd +``` + +--- + +### 4. Check the self-managing ArgoCD app + +Click the **argocd** application in the UI. It should show **Synced / Healthy**. + +ArgoCD is now reconciling its own Helm release from Git. If you push a change to +`manifests/argocd/values.yaml`, ArgoCD will apply it to itself. + +--- + +## Expected outcome + +``` +NAME SYNC STATUS HEALTH STATUS +argocd Synced Healthy +root Synced Healthy +``` + +--- + +## Troubleshooting + +| Symptom | Fix | +|---------|-----| +| `kubectl get nodes` shows NotReady | Wait 30–60 s; k3s is starting | +| Helm install fails with timeout | Run `kubectl get pods -n argocd` — if image pull is slow, wait | +| UI shows "Unknown" sync status | Click **Refresh** on the application | +| Port-forward drops | Re-run the `kubectl port-forward` command | + +--- + +## What's next + +In Exercise 02 you will deploy your first application — **podinfo** — purely through +Git: no `kubectl apply`, just a YAML file committed to the repo. diff --git a/docs/02-deploy-podinfo.md b/docs/02-deploy-podinfo.md new file mode 100644 index 0000000..c4ba5b0 --- /dev/null +++ b/docs/02-deploy-podinfo.md @@ -0,0 +1,158 @@ +# Exercise 02 — Deploy podinfo via GitOps + +**Time**: ~30 min +**Goal**: Deploy a real application to the cluster purely through Git — no `kubectl apply`. + +--- + +## What you'll learn +- How adding an ArgoCD `Application` manifest to Git is the only deploy action needed +- How to read ArgoCD sync status and application health +- The GitOps feedback loop: commit → push → ArgoCD detects change → cluster updated + +--- + +## Prerequisites + +Exercise 01 complete: ArgoCD is running and the root app is Synced. + +--- + +## Background: what is podinfo? + +`podinfo` is a tiny Go web app by Stefan Prodan (ArgoCD's author) — often used in +Kubernetes demos. It shows its own version number, has `/healthz` and `/readyz` +endpoints, and looks good in a browser. No external dependencies, no secrets needed. + +--- + +## Steps + +### 1. Understand what already exists + +The repo already contains the podinfo manifests. Take a look: + +```bash +ls manifests/apps/podinfo/ +# namespace.yaml deployment.yaml service.yaml +``` + +Open `manifests/apps/podinfo/deployment.yaml` and find the image tag: + +```yaml +image: ghcr.io/stefanprodan/podinfo:6.6.2 +``` + +This is version **6.6.2**. Remember it — you'll upgrade it later. + +--- + +### 2. Create the ArgoCD Application + +This is the only thing you need to "deploy" the app — tell ArgoCD to watch the manifests: + +```bash +cat apps/apps/podinfo.yaml +``` + +You'll see it points ArgoCD at `manifests/apps/podinfo/` in this repo. The app +already exists in the repo, so ArgoCD's root app will pick it up automatically. + +Check ArgoCD now — you should already see a **podinfo** application appearing. + +> **The GitOps point**: You didn't run any `kubectl apply` for podinfo. You committed +> `apps/apps/podinfo.yaml` to Git, and ArgoCD synced it. That's the entire workflow. + +--- + +### 3. Watch it sync + +```bash +kubectl get application podinfo -n argocd -w +``` + +Wait until you see `Synced` and `Healthy`. Then: + +```bash +kubectl get pods -n podinfo +# NAME READY STATUS RESTARTS AGE +# podinfo-xxxxxxxxx-xxxxx 1/1 Running 0 30s +``` + +--- + +### 4. Verify the app is working + +Port-forward to test locally (inside the VM): + +```bash +kubectl port-forward svc/podinfo -n podinfo 9898:80 +``` + +In another terminal (or using curl inside the VM): + +```bash +curl http://localhost:9898 +# {"hostname":"podinfo-xxx","version":"6.6.2", ...} +``` + +You can see `"version":"6.6.2"` — that matches the image tag in `deployment.yaml`. + +--- + +### 5. Make a GitOps change + +Let's change the UI color to prove the loop works. + +Edit `manifests/apps/podinfo/deployment.yaml` and change: +```yaml +value: "#6C48C5" +``` +to any hex color you like, e.g.: +```yaml +value: "#2ecc71" +``` + +Commit and push: + +```bash +git add manifests/apps/podinfo/deployment.yaml +git commit -m "chore: change podinfo UI color" +git push +``` + +Within ~3 minutes (ArgoCD's default poll interval) you'll see the pod restart and +the new color appear. You can also click **Refresh** in the ArgoCD UI to trigger +an immediate sync. + +--- + +## Expected outcome + +``` +NAME SYNC STATUS HEALTH STATUS +podinfo Synced Healthy +``` + +```bash +curl http://localhost:9898 | jq .version +# "6.6.2" +``` + +--- + +## Troubleshooting + +| Symptom | Fix | +|---------|-----| +| Application stuck in "Progressing" | `kubectl describe pod -n podinfo` — usually image pull | +| `ImagePullBackOff` | Image was pre-pulled; run `kubectl get events -n podinfo` | +| ArgoCD shows OutOfSync after push | Click **Refresh** or wait 3 min for next poll | + +--- + +## What's next + +podinfo is running but only accessible via port-forward. In Exercise 03 you'll +expose it on your LAN using MetalLB (a real load balancer) and Ingress-Nginx, +so you can reach it from your laptop's browser without any port-forward. diff --git a/manifests/apps/podinfo/deployment.yaml b/manifests/apps/podinfo/deployment.yaml new file mode 100644 index 0000000..e64a2f6 --- /dev/null +++ b/manifests/apps/podinfo/deployment.yaml @@ -0,0 +1,42 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: podinfo + namespace: podinfo +spec: + replicas: 1 + selector: + matchLabels: + app: podinfo + template: + metadata: + labels: + app: podinfo + spec: + containers: + - name: podinfo + image: ghcr.io/stefanprodan/podinfo:6.6.2 + ports: + - containerPort: 9898 + name: http + env: + - name: PODINFO_UI_COLOR + value: "#6C48C5" + readinessProbe: + httpGet: + path: /readyz + port: 9898 + initialDelaySeconds: 5 + periodSeconds: 10 + livenessProbe: + httpGet: + path: /healthz + port: 9898 + initialDelaySeconds: 5 + periodSeconds: 30 + resources: + requests: + cpu: 50m + memory: 64Mi + limits: + memory: 128Mi diff --git a/manifests/apps/podinfo/namespace.yaml b/manifests/apps/podinfo/namespace.yaml new file mode 100644 index 0000000..5128776 --- /dev/null +++ b/manifests/apps/podinfo/namespace.yaml @@ -0,0 +1,4 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: podinfo diff --git a/manifests/apps/podinfo/service.yaml b/manifests/apps/podinfo/service.yaml new file mode 100644 index 0000000..e070eed --- /dev/null +++ b/manifests/apps/podinfo/service.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: Service +metadata: + name: podinfo + namespace: podinfo +spec: + selector: + app: podinfo + ports: + - port: 80 + targetPort: 9898 + name: http