Lesson 08 of 12 · Kubernetes Dataplane
Load balancing & proxies
Get traffic into bare-metal and edge clusters: LoadBalancer Services with MetalLB (L2 and BGP modes), the difference between L4 and L7 balancing, and preserving client IPs with PROXY protocol and forwarded headers.
L4 vs L7
| L4 (TCP/UDP) | L7 (HTTP/gRPC) | |
|---|---|---|
| Sees | IPs and ports | Hosts, paths, headers, cookies |
| Can do | Spread connections | Route by URL, retries, TLS termination, auth, rate limits |
| Examples | MetalLB, cloud NLB, IPVS, kube-proxy | Ingress controllers, Gateway implementations, Envoy, HAProxy (http mode) |
Most platforms stack them: L4 (a stable external IP) → L7 (the ingress or gateway) → Services → pods.
An L4 balancer is a traffic officer at the car park entrance: it only sees cars and sends them to any free lane. An L7 balancer is a receptionist inside: it reads your visitor slip ("orders department, second floor") and walks you to exactly the right desk.
LoadBalancer Services on bare metal: MetalLB
Clouds implement type: LoadBalancer for you. On bare metal and edge sites, MetalLB (or kube-vip) assigns external IPs from a pool you own and announces them to the network.
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: public
namespace: metallb-system
spec:
addresses:
- 10.10.0.200-10.10.0.220
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
name: public
namespace: metallb-system
spec:
ipAddressPools: [ "public" ]
$ kubectl -n traefik get svc traefik
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S)
traefik LoadBalancer 10.96.51.12 10.10.0.200 80:31080/TCP,443:31443/TCP
| Mode | How the IP is announced | Traffic | Failover |
|---|---|---|---|
| L2 | One node answers ARP for the IP | All through that node, then spread by kube-proxy | Another node takes over via gratuitous ARP (seconds) |
| BGP | Nodes advertise the IP to routers via BGP | Routers spread it across nodes (ECMP) | Route withdrawn quickly |
L2 needs nothing from the network team, which is ideal for small or edge sites. BGP needs router configuration but scales and balances properly.
Keeping the client IP
Each hop can hide the original client address:
- L4 (Service):
externalTrafficPolicy: ClusterSNATs when hopping between nodes → useLocalto keep the IP (lesson 06). - L4 load balancer → proxy: a TCP-level balancer can prepend a PROXY protocol header with the client IP. The proxy must be configured to expect it (both sides must agree, or connections break).
- Proxy → app (L7): the proxy adds
X-Forwarded-For(or the standardForwardedheader). The app must trust these headers only from known proxies, or clients can spoof them.
Health checks and draining
- Load balancers health-check backends (a TCP port or HTTP
/healthz). Make sure the check reflects real readiness. - During rollouts and node drains, backends must leave the pool before they stop serving: readiness probes, preStop delays and connection draining settings on the load balancer.
Try it: MetalLB on kind
- Find your kind network's range (
docker network inspect kind -f '{{(index .IPAM.Config 0).Subnet}}') and pick ~10 unused addresses near the top of it. - Install MetalLB (its manifest or Helm chart), then apply an
IPAddressPoolwith those addresses and anL2Advertisement. - Expose
webastype: LoadBalancerand curl the external IP from your machine (works on Linux hosts; Docker Desktop on macOS/Windows can't route to the kind network directly). - Check the speaker logs to see which node announces the IP; delete that node's speaker pod and watch the announcement move.
- Put Traefik behind MetalLB and look at the
X-Forwarded-Forheader your app receives (e.g. with an echo server image such asealen/echo-server).
Going deeper: edges in production
- Put control-plane VIPs (kube-vip) and application VIPs (MetalLB) on separate address ranges and failure domains.
- BGP with BFD speeds up failure detection; coordinate timers with the network team.
- Long-lived connections (WebSockets, gRPC) don't rebalance after scale-up or failover. Plan connection lifetimes and client reconnects.
- For multi-site setups, global load balancing (DNS-based, anycast, or a cloud edge) sits above all of this.
Recap
- L4 spreads connections; L7 routes requests. Platforms layer them.
- MetalLB gives bare-metal
LoadBalancerServices: L2 (simple) or BGP (scalable). - Preserve client IPs hop by hop:
externalTrafficPolicy: Local, PROXY protocol, X-Forwarded-For from trusted proxies. - Health checks and draining make rollouts invisible to users.
This site is a public version of my personal engineering knowledge hub. It intentionally excludes confidential company information and internal operational details.