Ingress controllers and Ingress resources
How an Ingress routes web traffic by host and path, how pathTypes match, and how to serve HTTPS with a Secret.
Key ideas in this lesson · tap one for a simple explanation
What you will be able to do
- Tell the Ingress controller, the IngressClass and the Ingress apart, and find all three on a cluster.
- Write host and path rules with the right pathType, with kubectl or in YAML, and test them with curl.
- Turn on HTTPS for an Ingress with a kubernetes.io/tls Secret, and check which certificate is served.
A works inside the cluster. An lets web traffic in from outside, and sends each request to the right Service by its host name and path. For example, shop.local/api goes to Service shop-api, and every other path to shop-web. The exam topic is Know how to use Ingress controllers and Ingress resources.
A typical task gives you two Services and asks for one Ingress, sometimes with HTTPS. The is short. Points are lost on small details:
- a missing
ingressClassName ExactwherePrefixwas meant- a backend port that the Service does not have
Controller, class and Ingress: three names, three jobs
Three things work together here, and their names look alike:
An Ingress picks its class in spec.ingressClassName. Without a running controller, an Ingress routes nothing at all. Other controllers you may meet are Traefik, HAProxy and the cloud providers' own.
Client
asks for shop.local/api
Ingress controller
ingress-nginx; checks the host and path against the Ingress rules
Service
shop-api:80
Pods
a shop-api Pod answers
The Ingress object only holds the rules. The controller reads them, and sends each request to the matching Service's Pods.
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 backend
# No default class and no ingressClassName: no controller claims the Ingress.
# It just sits there with an empty ADDRESS column and no events.What an Ingress looks like
This Ingress sends shop.local/api to shop-api, and every other path on shop.local to shop-web:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: shop
namespace: nw-ing
spec:
ingressClassName: nginx
# defaultBackend: (optional) a Service for requests that match no rule
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. At equal length, Exact beats Prefix. That is why / with Prefix works as a catch-all next to /api. Also, the backend Service must be in the same namespace as the Ingress. Its port is the Service's port, not the 's targetPort.
kubectl create ingress
kubectl create ingress builds an Ingress in one line. Each --rule reads host/path=service:port.
# --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 secure --class=nginx --rule="secure.shop.local/*=shop-web:80,tls=secure-tls"
# 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: serving HTTPS
With TLS, the controller serves HTTPS for a host. It needs that host's certificate and private key. You store both in a of type kubernetes.io/tls, and the Ingress names that Secret in a tls list:
spec:
ingressClassName: nginx
tls:
- hosts:
- secure.shop.local
secretName: secure-tls # type kubernetes.io/tls, same namespace as the Ingress
rules:
- host: secure.shop.local # the same host name as under tlsTo try it, make a certificate, store it in a Secret, then check which certificate the controller serves:
# 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 -subjectClient
HTTPS to secure.shop.local
Ingress controller
decrypts with the certificate from Secret secure-tls
Service and Pods
get plain HTTP
"Terminating TLS" means the encryption ends at the controller. Your app never needs the certificate.
- Once a host has TLS, ingress-nginx answers plain HTTP for it with a
308redirect to HTTPS. So a curl on port 8080 suddenly returns nothing useful. - The Secret must hold
tls.crtandtls.key, and live in the Ingress's namespace. - If the certificate's names do not cover the host, the controller ignores it and serves its own fake certificate.
When an Ingress does not route
The HTTP status code tells you where to look. A 404 from nginx means no rule matched. A 503 means a rule matched, but the Service has no ready .
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 official docs· open on exam day too
- Ingresssearch: ingress pathType
- Ingress Controllerssearch: ingress controllers
- kubectl create ingresssearch: kubectl create ingress
- Secrets: TLS Secretssearch: kubernetes.io/tls secret
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.Cluster:kubectl config use-context kind-cka
- 1
Set up the scenario
curl -fsSL https://codewithmuh.com/labs/cka/t/nw-ing-1/setup | bash - 2
Solve it in your terminal
Use kubectl and the Kubernetes docs, like on exam day. Save any answer files under
/tmp/cka/. - 3
Check your work
curl -fsSL https://codewithmuh.com/labs/cka/t/nw-ing-1/verify | bashGot FAIL? Read which check failed, fix it, run it again. - 4
Clean up (optional)
curl -fsSL https://codewithmuh.com/labs/cka/t/nw-ing-1/cleanup | bash
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.Cluster:kubectl config use-context kind-cka
- 1
Set up the scenario
curl -fsSL https://codewithmuh.com/labs/cka/t/nw-ing-2/setup | bash - 2
Solve it in your terminal
Use kubectl and the Kubernetes docs, like on exam day. Save any answer files under
/tmp/cka/. - 3
Check your work
curl -fsSL https://codewithmuh.com/labs/cka/t/nw-ing-2/verify | bashGot FAIL? Read which check failed, fix it, run it again. - 4
Clean up (optional)
curl -fsSL https://codewithmuh.com/labs/cka/t/nw-ing-2/cleanup | bash
Finished this lesson?
0 of 2 tasks passed. Your readiness counts tasks, so run them before you move on.