An Ingress is a list of host and path rules that point at Services. On its own it does nothing: an Ingress controller watches Ingresses and configures a proxy (NGINX 75 , Envoy 117,531 , HAProxy 6,072 , Traefik 27,315 or a cloud load balancer). Each controller registers an IngressClass, chosen by spec.ingressClassName; cloud-provider-kind 508 registers cloud-provider-kind as the default class. kubectl 5,150 create ingress writes the manifest from compact rules:
kubectl create ingress shop --class=cloud-provider-kind \
--rule='shop.example.com/api*=api:3000' --rule='shop.example.com/*=web:80'
sleep 20; kubectl get ingress shop
IP=$(kubectl get ingress shop -o jsonpath='{.status.loadBalancer.ingress[0].ip}')
curl -s -H 'Host: shop.example.com' http://$IP/api/books/2 | cut -c1-70ingress.networking.k8s.io/shop created
NAME CLASS HOSTS ADDRESS PORTS AGE
shop cloud-provider-kind shop.example.com 172.18.0.5,fc00:f853:ccd:e793::5 80 20s
{"id":2,"title":"Patterns of the Deep Web","author":"Tomas Reyes","gencloud-provider-kind translates each Ingress into Gateway API objects (a per-namespace kind-ingress-gateway and an HTTPRoute per host), served by an Envoy container on Docker 514 's kind 14,561 network, reachable from WSL 6 . The trailing * made each path pathType: Prefix, which matches whole path elements: /api matches /api/books but not /apis. Exact matches one path; ImplementationSpecific means whatever the controller decides. Everything beyond hosts, paths and TLS lives in controller-specific annotations, which is where Ingress stops being portable. The API is GA but frozen: it keeps working, and new features go into the Gateway API.