Ingress Configuration

Ingress provides a flexible way to route HTTP and HTTPS traffic inside a Kubernetes cluster. While NodePort and LoadBalancer services are useful for exposing applications, they generally operate at the transport layer and offer limited control over hostnames, URL paths, and TLS termination. An Ingress resource adds layer 7 routing by matching incoming requests to Kubernetes Services based on domains, paths, and other HTTP attributes.

An Ingress object is only a declarative set of routing rules. An Ingress Controller must be running in the cluster to watch these resources and translate them into the configuration of an actual proxy or load balancer. Popular choices include NGINX Ingress Controller, Traefik, and HAProxy.
A typical request follows this path:

  1. A client sends an HTTP or HTTPS request to the cluster’s external endpoint.
  2. The request reaches the Ingress Controller, which is usually exposed through a LoadBalancer, NodePort, or cloud-managed load-balancer service.
  3. The controller evaluates the Ingress rules and selects the appropriate backend.
  4. The selected Kubernetes Service forwards the request to one of its ready Pod endpoints.

This design separates application routing rules from the implementation of the underlying load balancer. The same Ingress resource can therefore be used with different controllers, although controller-specific annotations and behavior may vary.

Prerequisites

Before creating an Ingress, make sure the following components are available:

  • A functioning Kubernetes cluster.
  • An installed and running Ingress Controller.
  • A DNS record or another method for directing traffic to the controller.
  • A backend application deployed behind a Kubernetes Service.
  • TLS certificates if the application must be served over HTTPS.

For the examples below, assume that a service named my-web-service exposes port 80 and connects to a deployment with ready replicas.

You can confirm that the controller is available with:

kubectl get ingressclass
kubectl get pods -n ingress-nginx

The namespace and controller name depend on how Ingress was installed.

Creating a Basic Ingress

Create a file named ingress-basic.yaml with the following content:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: example-ingress
  namespace: default
  annotations:
    kubernetes.io/ingress.class: "nginx"
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  rules:
    - host: app.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: my-web-service
                port:
                  number: 80

This configuration sends requests for app.example.com to the my-web-service service on port 80.

Depending on the controller installation, the Ingress class may instead be selected with spec.ingressClassName. The kubernetes.io/ingress.class annotation remains widely supported, but it should not be confused with the controller-specific annotations used for features such as path rewriting.

Important Fields

  • metadata.name identifies the Ingress resource within its namespace.
  • metadata.annotations contains optional configuration understood by a particular controller.
  • spec.rules defines the host and path routing rules.
  • host matches the hostname requested by the client. If it is omitted, the rule can match requests regardless of the requested domain.
  • http.paths maps URL paths to backend services.
  • pathType controls how paths are matched. Common values include:
    • Prefix: Matches a URL path prefix. Path segments are handled in a segment-aware manner by modern Kubernetes implementations.
    • Exact: Matches the complete URL path exactly.
    • ImplementationSpecific: Leaves the matching behavior to the Ingress Controller.
  • backend.service identifies the Kubernetes Service that should receive matching traffic.

A Prefix path of / commonly acts as a catch-all route. When several paths overlap, controller implementations may prioritize the most specific match.

Applying and Validating the Configuration

Apply the resource with kubectl:

kubectl apply -f ingress-basic.yaml

Then inspect its status and assigned address:

kubectl get ingress example-ingress -o wide
kubectl describe ingress example-ingress

The ADDRESS column may contain an IP address, a hostname, or both. The exact value depends on how the Ingress Controller is exposed.

For local testing, map the hostname to the controller’s address. On Linux or macOS, add an entry such as the following to /etc/hosts:

<INGRESS_CONTROLLER_IP> app.example.com

Alternatively, curl can set the Host header directly:

curl -H "Host: app.example.com" http://<INGRESS_CONTROLLER_IP>

A successful request should return a response from the backend application. If it does not, check that the Service has ready endpoints:

kubectl get service my-web-service
kubectl get endpointslices \
  -l kubernetes.io/service-name=my-web-service

Configuring TLS and HTTPS

Production applications should normally be served over HTTPS. Kubernetes stores TLS credentials in a Secret, while the Ingress resource specifies which hosts should use that certificate.

Creating the TLS Secret

If the certificate and private key are stored in tls.crt and tls.key, create the Secret with:

kubectl create secret tls example-tls-secret \
  --cert=path/to/tls.crt \
  --key=path/to/tls.key

The Secret must exist in the same namespace as the Ingress resource that references it. The certificate should include the complete certificate chain expected by clients.

Referencing the Secret

Create an Ingress configuration with a tls section:

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: example-ingress-tls
  namespace: default
  annotations:
    kubernetes.io/ingress.class: "nginx"
spec:
  tls:
    - hosts:
        - app.example.com
      secretName: example-tls-secret
  rules:
    - host: app.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: my-web-service
                port:
                  number: 80

Apply it and verify the endpoint:

kubectl apply -f ingress-tls.yaml
curl -I https://app.example.com

Once the controller loads the Secret, it will normally terminate TLS on port 443 and forward decrypted HTTP traffic to the backend service. TLS termination protects traffic between the client and controller; traffic between the controller and application pods may still be unencrypted. For end-to-end encryption, configure application-level TLS or a service mesh.

Useful Routing Patterns

An Ingress can direct different paths to different services:

spec:
  rules:
    - host: app.example.com
      http:
        paths:
          - path: /api
            pathType: Prefix
            backend:
              service:
                name: api-service
                port:
                  number: 8080
          - path: /web
            pathType: Prefix
            backend:
              service:
                name: web-service
                port:
                  number: 80

Annotations can add controller-specific behavior. For example, the following NGINX annotation rewrites the request path before forwarding it:

metadata:
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /

Because annotation behavior is controller-specific, it should be tested carefully. Rewriting can affect redirects, static assets, and APIs that expect the original URL path.

Common Troubleshooting Steps

If requests return 404, 503, or the wrong application, inspect the resource and controller events:

kubectl describe ingress example-ingress
kubectl get events --sort-by=.lastTimestamp
kubectl logs -n ingress-nginx deployment/ingress-nginx-controller

Common causes include:

  • The requested hostname does not match spec.rules[].host.
  • The request path does not match the configured pathType.
  • The backend Service has no ready endpoints.
  • The Ingress class points to a controller that is not running.
  • DNS resolves to the wrong address.
  • The TLS Secret is missing, invalid, or located in another namespace.
  • A rewrite annotation changes the path expected by the application.

Ingress is a central part of exposing Kubernetes workloads, but it works best as part of a larger routing setup. Combining precise host and path rules, TLS termination, controller-specific annotations, and thorough endpoint validation enables a reliable path from external traffic to application pods.