Happy Dussehra! May good always win. Happy Diwali! Wishing you a bright year ahead. Merry Christmas! Warm wishes from Vizag. Happy New Year! Here’s to a great year ahead.

Archive · Kubernetes

Ingress: One Entry Point for Many Services

Route HTTP and HTTPS traffic to many Services through one load balancer using the networking.k8s.io/v1 Ingress API and ingress-nginx, with TLS and path rules.

4 min read

  • Kubernetes 1.22
  • Ingress networking.k8s.io/v1
  • ingress-nginx 0.49
  • Helm 3

Giving every web service its own LoadBalancer means one cloud load balancer, one IP and one bill per service. An Ingress describes HTTP routing rules (hostnames and paths) so a single entry point serves many Services, and can also terminate TLS.

Versions in use on this date. Kubernetes 1.22 (4 August 2021) serves Ingress only as networking.k8s.io/v1; the beta versions were removed. The community controller ingress-nginx is at 0.49, with a 1.0 release expected shortly that also targets the v1 API and IngressClass (covered in the next series entry). Ingress is a resource; it does nothing until an ingress controller is running.

Request flow

flowchart TB
  U[Users] -->|app.example.com| DNS[DNS A or CNAME record]
  DNS --> LB[Cloud load balancer or node ports<br/>one public entry]
  LB --> IC[ingress-nginx controller pods<br/>watch Ingress objects]
  IC -->|Host app.example.com path /| WEB[Service web]
  IC -->|Host app.example.com path /api| API[Service api]
  IC -->|Host admin.example.com| ADM[Service admin]
  WEB --> P1[Web pods]
  API --> P2[API pods]
  ADM --> P3[Admin pods]
  CERT[TLS Secret] -.-> IC

The controller turns Ingress rules into its own proxy configuration (an nginx config) and reloads it when they change.

Install the controller

helm upgrade --install ingress-nginx ingress-nginx \
  --repo https://kubernetes.github.io/ingress-nginx \
  --namespace ingress-nginx --create-namespace
kubectl -n ingress-nginx get pods,svc
kubectl -n ingress-nginx get svc ingress-nginx-controller -o jsonpath='{.status.loadBalancer.ingress[0]}'

On a cloud cluster the controller’s Service of type LoadBalancer gets an external address; point DNS there (a wildcard record such as *.example.com simplifies things). On kind, use the port-mapping configuration from the earlier post and the kind-specific manifest. Pin the chart version in real deployments and read the upgrade notes before moving between controller versions.

An Ingress with two paths and TLS

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: shop
  namespace: shop
  annotations:
    nginx.ingress.kubernetes.io/proxy-body-size: "10m"
    nginx.ingress.kubernetes.io/ssl-redirect: "true"
spec:
  ingressClassName: nginx
  tls:
    - hosts: [shop.example.com]
      secretName: shop-tls
  rules:
    - host: shop.example.com
      http:
        paths:
          - path: /api
            pathType: Prefix
            backend: { service: { name: api, port: { number: 8080 } } }
          - path: /
            pathType: Prefix
            backend: { service: { name: web, port: { number: 80 } } }
kubectl -n shop apply -f ingress.yaml
kubectl -n shop get ingress
kubectl -n shop describe ingress shop
curl -H "Host: shop.example.com" http://<load-balancer-address>/
curl --resolve shop.example.com:443:<address> -k https://shop.example.com/api/health
  • pathType: Prefix matches by path elements (/api matches /api and /api/orders), Exact matches only that path, ImplementationSpecific leaves it to the controller. It is required in v1.
  • Longer, more specific paths win; keep rules readable.
  • The Service ports refer to the Service port, and each Service must exist in the same namespace as the Ingress.

TLS

Create the certificate Secret from files, or let cert-manager issue and renew it automatically (the cert-manager post covers this):

kubectl -n shop create secret tls shop-tls --cert=fullchain.pem --key=privkey.pem

The Secret must be in the Ingress namespace. Without a tls section, ingress-nginx serves a default fake certificate for HTTPS.

Useful annotations (ingress-nginx)

Annotation Purpose
nginx.ingress.kubernetes.io/rewrite-target: /$2 Strip a path prefix (with a regex path such as /app(/|$)(.*))
...proxy-read-timeout: "120" Longer upstream timeouts
...whitelist-source-range: 10.0.0.0/8 IP allow-list
...auth-url / auth-signin External authentication
...limit-rps: "20" Basic rate limiting
...backend-protocol: "HTTPS" Upstream speaks TLS

Annotations are controller-specific; other controllers (AWS Load Balancer Controller, Traefik, Contour, HAProxy) use their own.

Troubleshooting

  1. kubectl describe ingress shows the backends and any events; <error: endpoints not found> means the Service has no ready pods.
  2. 404 from nginx: no rule matched the Host header or path; check ingressClassName and spelling.
  3. 503: Service exists but has no endpoints.
  4. 502/504: backend unreachable or too slow; test with kubectl port-forward svc/web 8080:80.
  5. Controller logs show the decision: kubectl -n ingress-nginx logs deploy/ingress-nginx-controller --tail=50.
  6. The Ingress shows no ADDRESS: the controller is not running, or watches a different class.

Design notes

Ingress handles HTTP(S) only; for TCP/UDP use a LoadBalancer Service. Keep one controller per class and separate public and internal entry points when needed. The Gateway API is the planned successor, still evolving, so use Ingress today and watch the project.