Ingress controllers and Ingress resources
How an Ingress controller turns Ingress objects into HTTP routing, how hosts, paths and pathTypes match, and how to terminate TLS with a Secret.
After this lesson
- 01You can explain the split between the Ingress controller, the IngressClass and the Ingress resource, and find all three on a cluster.
- 02You can write host- and path-based Ingress rules with the right pathType, imperatively or in YAML, and test them with curl.
- 03You can terminate TLS on an Ingress with a kubernetes.io/tls Secret and prove which certificate is served.
This lesson covers Know how to use Ingress controllers and Ingress resources. A typical task gives you two Services and asks for one Ingress that routes by path or by host, sometimes with TLS. The YAML is short. The points are lost on details: a missing ingressClassName, Exact where Prefix was meant, or a backend port that does not exist on the Service.
Controller, class, resource
An Ingress is configuration only. Nothing routes until an Ingress controller runs: a Deployment (nginx, Traefik, HAProxy, a cloud load balancer's controller) that watches Ingress objects, renders them into its proxy config and receives traffic through its own Service. An IngressClass ties the two together. An Ingress names a class in spec.ingressClassName, and the class names the controller that owns it in spec.controller.
kubectl get ingressclass
# NAME CONTROLLER PARAMETERS AGE
# nginx k8s.io/ingress-nginx <none> 1h
kubectl get ingressclass -o yaml | grep is-default-class # a default class is used when ingressClassName is omitted
kubectl -n ingress-nginx get deploy,pods,svc -o wide
# Lab: the controller runs on cka-control-plane with hostPorts 80/443,
# which kind maps to localhost:8080 and localhost:8443 on your machine.
curl -s -o /dev/null -w '%{http_code}\n' localhost:8080/ # 404 from the controller's default backendIf no IngressClass is marked default and an Ingress has no ingressClassName, no controller picks it up. It sits there with an empty ADDRESS column and no events. The old kubernetes.io/ingress.class annotation is deprecated; use the field.
Anatomy of an Ingress
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: shop
namespace: nw-ing
spec:
ingressClassName: nginx
defaultBackend: # requests that match no rule (optional)
service:
name: shop-web
port:
number: 80
tls:
- hosts:
- shop.local
secretName: shop-tls # type kubernetes.io/tls, same namespace as the Ingress
rules:
- host: shop.local # omit host to match every host; "*.shop.local" matches one label
http:
paths:
- path: /api
pathType: Prefix
backend:
service:
name: shop-api
port:
number: 80 # or name: http for a named Service port
- path: /
pathType: Prefix
backend:
service:
name: shop-web
port:
number: 80When several paths match, the longest one wins, and Exact beats Prefix at equal length. That is why / with Prefix works as a catch-all next to /api. The backend must be a Service in the same namespace as the Ingress, and the port must be a Service port (port), not the container's targetPort.
kubectl create ingress
# --rule="host/path=service:port[,tls=secret]"; a trailing * means Prefix, no * means Exact
kubectl -n nw-ing create ingress shop --class=nginx \
--rule="shop.local/*=shop-web:80" \
--rule="shop.local/api*=shop-api:80"
kubectl -n nw-ing create ingress shop --class=nginx --rule="shop.local/api=shop-api:80" # Exact /api only!
kubectl -n nw-ing create ingress catch-all --class=nginx --default-backend=shop-web:80
kubectl -n nw-ing create ingress secure --class=nginx --rule="secure.shop.local/*=shop-web:80,tls=secure-tls"
kubectl -n nw-ing create ingress rewrite --class=nginx --rule="shop.local/v2*=shop-api:80" \
--annotation nginx.ingress.kubernetes.io/rewrite-target=/
# Always look at what you generated before applying it
kubectl -n nw-ing create ingress shop --class=nginx --rule="shop.local/*=shop-web:80" --dry-run=client -o yamlTLS termination
# A self-signed certificate for one host (use the files you are given on the exam)
openssl req -x509 -nodes -newkey rsa:2048 -days 365 \
-keyout tls.key -out tls.crt -subj "/CN=secure.shop.local" -addext "subjectAltName=DNS:secure.shop.local"
kubectl -n nw-tls create secret tls secure-tls --cert=tls.crt --key=tls.key # type kubernetes.io/tls
kubectl -n nw-tls get secret secure-tls -o jsonpath='{.type}{"\n"}'
# Test without touching /etc/hosts: --resolve pins the name to the lab's port
curl -sk --resolve secure.shop.local:8443:127.0.0.1 https://secure.shop.local:8443/hostname
# Which certificate is served? A wrong or missing Secret gives the controller's fake certificate
echo | openssl s_client -connect 127.0.0.1:8443 -servername secure.shop.local 2>/dev/null | openssl x509 -noout -subjectOnce a host has TLS, ingress-nginx answers plain HTTP for it with a 308 redirect to HTTPS. That is expected, and it is why a curl on port 8080 suddenly returns nothing useful. The Secret must hold tls.crt and tls.key, and it must live in the Ingress's namespace. A certificate whose names do not cover the host is ignored, and you get the fake certificate.
kubectl -n nw-ing describe ingress shop # rules, backends with their endpoints, events
kubectl -n nw-ing get endpointslices -l kubernetes.io/service-name=shop-api # no endpoints = 503
curl -s -H 'Host: shop.local' localhost:8080/api/orders # Host header selects the rule
kubectl -n ingress-nginx logs deploy/ingress-nginx-controller --tail=20 # one access-log line per request
# 404 from nginx: no rule matched (wrong host, Exact vs Prefix, missing class)
# 503: a rule matched, but the Service has no ready endpointsIn the docs · the tab you get on exam day
- Ingress ↗search: “ingress pathType”
- Ingress Controllers ↗search: “ingress controllers”
- kubectl create ingress ↗search: “kubectl create ingress”
- Secrets: TLS Secrets ↗search: “kubernetes.io/tls secret”
context · kubectl config use-context kind-cka
Route one host to two Services by path
nw-ing, create an Ingress named shop using IngressClass nginx for host shop.local. Requests for /api and every path below it must go to Service shop-api on port 80; all other paths must go to Service shop-web on port 80. On this lab, curl -s -H 'Host: shop.local' localhost:8080/hostname must be answered by a shop-web Pod and curl -s -H 'Host: shop.local' localhost:8080/api/orders by a shop-api Pod.- 01
Set up the scenario
curl -fsSL https://codewithmuh.com/labs/cka/t/nw-ing-1/setup | bash - 02
Solve it in your terminal
Work the way the exam makes you: kubectl, the docs, nothing else. Put any answer files under
/tmp/cka/. - 03
Check your work
curl -fsSL https://codewithmuh.com/labs/cka/t/nw-ing-1/verify | bashCounts toward your readiness score. - 04
Clean up
curl -fsSL https://codewithmuh.com/labs/cka/t/nw-ing-1/cleanup | bash
context · kubectl config use-context kind-cka
Terminate TLS on an Ingress
secure.shop.local are in /tmp/cka/nw-tls/tls.crt and /tmp/cka/nw-tls/tls.key. In namespace nw-tls, store them in a TLS Secret named secure-tls. Then create an Ingress named secure with IngressClass nginx that routes all paths of host secure.shop.local to Service secure-web on port 80 and terminates TLS for that host with the Secret. On this lab, https://secure.shop.local:8443 (resolved to 127.0.0.1) must serve that certificate.- 01
Set up the scenario
curl -fsSL https://codewithmuh.com/labs/cka/t/nw-ing-2/setup | bash - 02
Solve it in your terminal
Work the way the exam makes you: kubectl, the docs, nothing else. Put any answer files under
/tmp/cka/. - 03
Check your work
curl -fsSL https://codewithmuh.com/labs/cka/t/nw-ing-2/verify | bashCounts toward your readiness score. - 04
Clean up
curl -fsSL https://codewithmuh.com/labs/cka/t/nw-ing-2/cleanup | bash
Finished reading?
0 of 2 tasks passed. Readiness counts tasks, so run them before you move on.