feat(ex03): MetalLB + Ingress-Nginx + podinfo ingress
- 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)
This commit is contained in:
parent
a5e57583b5
commit
633f3f6e46
8 changed files with 312 additions and 0 deletions
28
apps/networking/ingress-nginx.yaml
Normal file
28
apps/networking/ingress-nginx.yaml
Normal file
|
|
@ -0,0 +1,28 @@
|
||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: ingress-nginx
|
||||||
|
namespace: argocd
|
||||||
|
annotations:
|
||||||
|
argocd.argoproj.io/sync-wave: "3"
|
||||||
|
spec:
|
||||||
|
project: workshop
|
||||||
|
sources:
|
||||||
|
- repoURL: https://kubernetes.github.io/ingress-nginx
|
||||||
|
chart: ingress-nginx
|
||||||
|
targetRevision: "4.12.0"
|
||||||
|
helm:
|
||||||
|
valueFiles:
|
||||||
|
- $values/manifests/networking/ingress-nginx/values.yaml
|
||||||
|
- repoURL: https://github.com/innspire/ops-demo.git
|
||||||
|
targetRevision: HEAD
|
||||||
|
ref: values
|
||||||
|
destination:
|
||||||
|
server: https://kubernetes.default.svc
|
||||||
|
namespace: ingress-nginx
|
||||||
|
syncPolicy:
|
||||||
|
automated:
|
||||||
|
prune: true
|
||||||
|
selfHeal: true
|
||||||
|
syncOptions:
|
||||||
|
- CreateNamespace=true
|
||||||
24
apps/networking/metallb-config.yaml
Normal file
24
apps/networking/metallb-config.yaml
Normal file
|
|
@ -0,0 +1,24 @@
|
||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: metallb-config
|
||||||
|
namespace: argocd
|
||||||
|
annotations:
|
||||||
|
argocd.argoproj.io/sync-wave: "2"
|
||||||
|
spec:
|
||||||
|
project: workshop
|
||||||
|
source:
|
||||||
|
repoURL: https://github.com/innspire/ops-demo.git
|
||||||
|
targetRevision: HEAD
|
||||||
|
path: manifests/networking/metallb
|
||||||
|
directory:
|
||||||
|
include: "metallb-config.yaml"
|
||||||
|
destination:
|
||||||
|
server: https://kubernetes.default.svc
|
||||||
|
namespace: metallb-system
|
||||||
|
syncPolicy:
|
||||||
|
automated:
|
||||||
|
prune: true
|
||||||
|
selfHeal: true
|
||||||
|
syncOptions:
|
||||||
|
- CreateNamespace=true
|
||||||
29
apps/networking/metallb.yaml
Normal file
29
apps/networking/metallb.yaml
Normal file
|
|
@ -0,0 +1,29 @@
|
||||||
|
apiVersion: argoproj.io/v1alpha1
|
||||||
|
kind: Application
|
||||||
|
metadata:
|
||||||
|
name: metallb
|
||||||
|
namespace: argocd
|
||||||
|
annotations:
|
||||||
|
argocd.argoproj.io/sync-wave: "1"
|
||||||
|
spec:
|
||||||
|
project: workshop
|
||||||
|
sources:
|
||||||
|
- repoURL: https://metallb.github.io/metallb
|
||||||
|
chart: metallb
|
||||||
|
targetRevision: "0.14.9"
|
||||||
|
helm:
|
||||||
|
valueFiles:
|
||||||
|
- $values/manifests/networking/metallb/values.yaml
|
||||||
|
- repoURL: https://github.com/innspire/ops-demo.git
|
||||||
|
targetRevision: HEAD
|
||||||
|
ref: values
|
||||||
|
destination:
|
||||||
|
server: https://kubernetes.default.svc
|
||||||
|
namespace: metallb-system
|
||||||
|
syncPolicy:
|
||||||
|
automated:
|
||||||
|
prune: true
|
||||||
|
selfHeal: true
|
||||||
|
syncOptions:
|
||||||
|
- CreateNamespace=true
|
||||||
|
- ServerSideApply=true
|
||||||
166
docs/03-metallb-ingress.md
Normal file
166
docs/03-metallb-ingress.md
Normal file
|
|
@ -0,0 +1,166 @@
|
||||||
|
# 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:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
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:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
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:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
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:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
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:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
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:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# ── Exercise 03: uncomment this block after Ingress-Nginx is deployed ──────
|
||||||
|
# ingress:
|
||||||
|
# enabled: true
|
||||||
|
# ...
|
||||||
|
```
|
||||||
|
|
||||||
|
Uncomment the entire block (remove the `#` characters):
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
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:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
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:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
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:
|
||||||
|
1. Validates manifests
|
||||||
|
2. Bumps the podinfo image tag from `6.6.2` to `6.7.0` in `deployment.yaml`
|
||||||
|
3. Pushes the commit — and ArgoCD picks it up automatically
|
||||||
20
manifests/apps/podinfo/ingress.yaml
Normal file
20
manifests/apps/podinfo/ingress.yaml
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
apiVersion: networking.k8s.io/v1
|
||||||
|
kind: Ingress
|
||||||
|
metadata:
|
||||||
|
name: podinfo
|
||||||
|
namespace: podinfo
|
||||||
|
annotations:
|
||||||
|
nginx.ingress.kubernetes.io/rewrite-target: /
|
||||||
|
spec:
|
||||||
|
ingressClassName: nginx
|
||||||
|
rules:
|
||||||
|
- host: podinfo.192.168.56.200.nip.io
|
||||||
|
http:
|
||||||
|
paths:
|
||||||
|
- path: /
|
||||||
|
pathType: Prefix
|
||||||
|
backend:
|
||||||
|
service:
|
||||||
|
name: podinfo
|
||||||
|
port:
|
||||||
|
name: http
|
||||||
17
manifests/networking/ingress-nginx/values.yaml
Normal file
17
manifests/networking/ingress-nginx/values.yaml
Normal file
|
|
@ -0,0 +1,17 @@
|
||||||
|
# Ingress-Nginx Helm values
|
||||||
|
# The controller's LoadBalancer service will get 192.168.56.200 from MetalLB.
|
||||||
|
# All workshop ingresses use IngressClass "nginx".
|
||||||
|
controller:
|
||||||
|
ingressClassResource:
|
||||||
|
name: nginx
|
||||||
|
default: true
|
||||||
|
|
||||||
|
service:
|
||||||
|
type: LoadBalancer
|
||||||
|
# Request a specific IP so docs can reference it reliably
|
||||||
|
loadBalancerIP: "192.168.56.200"
|
||||||
|
|
||||||
|
resources:
|
||||||
|
requests:
|
||||||
|
cpu: 100m
|
||||||
|
memory: 128Mi
|
||||||
20
manifests/networking/metallb/metallb-config.yaml
Normal file
20
manifests/networking/metallb/metallb-config.yaml
Normal file
|
|
@ -0,0 +1,20 @@
|
||||||
|
# MetalLB L2 configuration
|
||||||
|
# IP pool: 192.168.56.200–192.168.56.220 (VirtualBox host-only subnet)
|
||||||
|
# First IP (200) will be claimed by Ingress-Nginx LoadBalancer service.
|
||||||
|
apiVersion: metallb.io/v1beta1
|
||||||
|
kind: IPAddressPool
|
||||||
|
metadata:
|
||||||
|
name: workshop-pool
|
||||||
|
namespace: metallb-system
|
||||||
|
spec:
|
||||||
|
addresses:
|
||||||
|
- 192.168.56.200-192.168.56.220
|
||||||
|
---
|
||||||
|
apiVersion: metallb.io/v1beta1
|
||||||
|
kind: L2Advertisement
|
||||||
|
metadata:
|
||||||
|
name: workshop-l2
|
||||||
|
namespace: metallb-system
|
||||||
|
spec:
|
||||||
|
ipAddressPools:
|
||||||
|
- workshop-pool
|
||||||
8
manifests/networking/metallb/values.yaml
Normal file
8
manifests/networking/metallb/values.yaml
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
# MetalLB Helm values
|
||||||
|
# No special configuration needed at chart level;
|
||||||
|
# IP pool is configured via metallb-config.yaml (CRDs).
|
||||||
|
speaker:
|
||||||
|
tolerations:
|
||||||
|
- key: node-role.kubernetes.io/control-plane
|
||||||
|
operator: Exists
|
||||||
|
effect: NoSchedule
|
||||||
Loading…
Add table
Reference in a new issue