- apps/networking/metallb.yaml: MetalLB Helm app (chart 0.14.9) - apps/networking/metallb-config.yaml: IPAddressPool + L2Advertisement CRDs - apps/networking/ingress-nginx.yaml: Ingress-Nginx Helm app (chart 4.12.0) - manifests/networking/metallb/: values.yaml + metallb-config.yaml (pool 192.168.56.200-220) - manifests/networking/ingress-nginx/values.yaml: LB IP 192.168.56.200, class nginx - manifests/apps/podinfo/ingress.yaml: podinfo.192.168.56.200.nip.io - docs/03-metallb-ingress.md: Exercise 03 participant guide - manifests/argocd/values.yaml: ArgoCD ingress block commented (enabled in Ex03)
5.1 KiB
Exercise 03 — MetalLB + Ingress-Nginx (LAN exposure)
Time: ~45 min Goal: Expose podinfo and the ArgoCD UI on a real LAN IP — accessible from your laptop's browser without any port-forward.
What you'll learn
- What MetalLB is and why you need it in a bare-metal / local Kubernetes cluster
- How a LoadBalancer service gets a real IP via L2 ARP
- How Ingress-Nginx routes HTTP traffic by hostname
nip.io— a public wildcard DNS service for local development
Background
In cloud Kubernetes (EKS, GKE, AKS), type: LoadBalancer automatically provisions a cloud load balancer with a public IP. On bare metal or local VMs, nothing does that — so pods stay unreachable.
MetalLB fills that gap: it watches for LoadBalancer services and assigns IPs from a pool you define. In L2 mode it uses ARP to answer "who has 192.168.56.200?" — so your laptop routes directly to the VM.
Ingress-Nginx is a single LoadBalancer service that MetalLB gives one IP. All your apps share that IP — Nginx routes to the right service based on the Host: header.
nip.io is a public DNS wildcard: anything.192.168.56.200.nip.io resolves to 192.168.56.200. No /etc/hosts editing needed.
Steps
1. Enable MetalLB
The ArgoCD Application manifests for MetalLB are already in this repo. The root
App-of-Apps watches the apps/ directory, which includes apps/networking/.
They are already being applied — MetalLB just needs a moment to become healthy.
Check MetalLB is running:
kubectl get pods -n metallb-system
# NAME READY STATUS RESTARTS AGE
# controller-xxx 1/1 Running 0 Xm
# speaker-xxx 1/1 Running 0 Xm
Check the IP pool is configured:
kubectl get ipaddresspool -n metallb-system
# NAME AUTO ASSIGN AVOID BUGGY IPS ADDRESSES
# workshop-pool true false ["192.168.56.200-192.168.56.220"]
2. Enable Ingress-Nginx
Similarly, apps/networking/ingress-nginx.yaml is already in the repo. Wait for it
to become Synced in ArgoCD, then:
kubectl get svc -n ingress-nginx
# NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S)
# ingress-nginx-controller LoadBalancer 10.43.x.x 192.168.56.200 80:xxx,443:xxx
The EXTERNAL-IP column shows 192.168.56.200. MetalLB assigned it.
From your laptop (not the VM), verify:
curl http://192.168.56.200
# 404 from Nginx — correct! No ingress rule yet, but Nginx is reachable.
3. Add a podinfo Ingress
The Ingress resource is already in manifests/apps/podinfo/ingress.yaml.
ArgoCD will sync it automatically. After sync:
kubectl get ingress -n podinfo
# NAME CLASS HOSTS ADDRESS PORTS
# podinfo nginx podinfo.192.168.56.200.nip.io 192.168.56.200 80
Open from your laptop browser: http://podinfo.192.168.56.200.nip.io
You should see the podinfo UI with version 6.6.2.
4. Enable the ArgoCD ingress
Now let's expose ArgoCD itself on a nice URL. Open manifests/argocd/values.yaml
and find the commented-out ingress block near the server: section:
# ── Exercise 03: uncomment this block after Ingress-Nginx is deployed ──────
# ingress:
# enabled: true
# ...
Uncomment the entire block (remove the # characters):
ingress:
enabled: true
ingressClassName: nginx
hostname: argocd.192.168.56.200.nip.io
annotations:
nginx.ingress.kubernetes.io/ssl-passthrough: "false"
nginx.ingress.kubernetes.io/backend-protocol: "HTTP"
Commit and push:
git add manifests/argocd/values.yaml
git commit -m "feat(ex03): enable ArgoCD ingress"
git push
ArgoCD will detect the change, upgrade its own Helm release, and create the Ingress. Within a minute or two:
kubectl get ingress -n argocd
# NAME CLASS HOSTS ADDRESS
# argocd-server nginx argocd.192.168.56.200.nip.io 192.168.56.200
Open from your laptop: http://argocd.192.168.56.200.nip.io
Expected outcome
| URL | App |
|---|---|
| http://podinfo.192.168.56.200.nip.io | podinfo v6.6.2 |
| http://argocd.192.168.56.200.nip.io | ArgoCD UI |
Both accessible from your laptop without any port-forward.
Troubleshooting
| Symptom | Fix |
|---|---|
EXTERNAL-IP is <pending> on ingress-nginx svc |
MetalLB not ready yet — check kubectl get pods -n metallb-system |
| Curl to 192.168.56.200 times out from laptop | VirtualBox host-only adapter not configured; check VBoxManage list hostonlyifs |
nip.io doesn't resolve |
Temporary DNS issue; try again or use /etc/hosts with 192.168.56.200 podinfo.local |
| ArgoCD ingress gives 502 | Wait for ArgoCD to restart after values change; ArgoCD now runs in insecure (HTTP) mode |
What's next
In Exercise 04 you'll build a Tekton pipeline that:
- Validates manifests
- Bumps the podinfo image tag from
6.6.2to6.7.0indeployment.yaml - Pushes the commit — and ArgoCD picks it up automatically