CloudOpsGuide
kubernetes

Kubernetes Ingress and TLS: Exposing Services Properly

Intermediate
11 minutes
October 2026
CloudOpsGuide Team

Kubernetes Ingress and TLS: Exposing Services Properly

Services give your Pods stable networking inside the cluster. Ingress is how the outside world reaches them — HTTP/S routing, hostnames, paths, and TLS, all in one Kubernetes-native object.

Table of Contents

The mental model

An Ingress resource is just a rulebook. Something has to enforce it — the Ingress Controller (NGINX Ingress, Traefik, HAProxy, cloud LB controllers). Without a controller, Ingress objects do nothing.

kind cluster + ingress-nginx:

helm install ingress-nginx ingress-nginx/ingress-nginx \
  -n ingress-nginx --create-namespace

The controller spins up an nginx deployment watching Ingress objects, and exposes itself via a LoadBalancer/NodePort service.

Your first Ingress

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: web
spec:
  ingressClassName: nginx
  rules:
    - host: app.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: web
                port:
                  number: 80

Traffic flow: client → controller → Service web:80 → healthy Pods.

Path and host routing

rules:
  - host: api.example.com       # virtual host routing
    http:
      paths:
        - path: /
          pathType: Prefix
          backend: { service: { name: api,   port: { number: 8080 } } }
  - host: app.example.com
    http:
      paths:
        - path: /app            # path routing
          pathType: Prefix
          backend: { service: { name: web,   port: { number: 80 } } }
        - path: /static
          pathType: Prefix
          backend: { service: { name: cdn-cache, port: { number: 80 } } }

Prefix vs Exact matching matters — /app with Prefix also catches /apples. Use /app/ carefully.

TLS: free certificates with cert-manager

cert-manager automates Let's Encrypt inside Kubernetes:

helm install cert-manager jetstack/cert-manager \
  -n cert-manager --create-namespace \
  --set crds.enabled=true
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
  name: letsencrypt
spec:
  acme:
    server: https://acme-v02.api.letsencrypt.org/directory
    email: you@example.com
    privateKeySecretRef: { name: letsencrypt-key }
    solvers:
      - http01: { ingress: { class: nginx } }

Then one annotation on your Ingress provisions and renews certs:

metadata:
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt
spec:
  tls:
    - hosts: [app.example.com]
      secretName: app-tls    # cert-manager fills this

Debugging when it doesn't work

kubectl get ingress                       # ADDRESS empty? controller isn't routing yet
kubectl describe ingress web              # events show misconfigurations
kubectl logs -n ingress-nginx deploy/ingress-nginx-controller
kubectl get certificate                   # cert-manager status

Top three causes of "Ingress does nothing": missing ingressClassName, the Service name/port doesn't match, or DNS not pointing at the controller's address.

Ingress vs Gateway API

Gateway API is the successor — richer (TCP/UDP, traffic splitting, role separation between platform and app teams). Ingress isn't going anywhere soon, but for new builds on modern clusters, Gateway API is worth the look.

Related Articles


Last Updated: October 2026 Author: CloudOpsGuide Team Difficulty: Intermediate Estimated Reading Time: 11 minutes