Home / Ingress step by step

How to expose an app in Kubernetes with Ingress, step by step

From a Pod that only talks inside the cluster to a public domain with HTTPS.

By default, a Kubernetes Pod is only reachable inside the cluster. For a user on the internet to reach your app you need to chain three pieces together: the Pod, a Service giving it a stable address, and an Ingress routing external traffic to that Service by domain and path.

Step 1 — the Service (a stable internal address)

Pods are created and destroyed constantly (when scaling, when updating the image), so their IPs change. A Service gives them a name and an internal IP that never change, and spreads traffic across every Pod matching its selector:

apiVersion: v1
kind: Service
metadata:
  name: my-service
spec:
  type: ClusterIP
  selector:
    app: my-app
  ports:
    - port: 80
      targetPort: 80
      protocol: TCP

type: ClusterIP (the default) is enough here — the Ingress talks to this Service from inside the cluster, so it doesn't need to be reachable from outside on its own.

Step 2 — the Ingress Controller (install once)

An Ingress object on its own does nothing: it needs an Ingress Controller running in the cluster to read those objects and configure a real proxy (nginx, Traefik, HAProxy…). If your cluster is managed (GKE, EKS, AKS) it may already have one, or you install it with a single command (for example ingress-nginx via Helm). This is done once per cluster, not per app.

Step 3 — the Ingress object (the routing rules)

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: my-ingress
spec:
  ingressClassName: nginx
  tls:
    - hosts:
        - app.mydomain.com
      secretName: my-tls-secret
  rules:
    - host: app.mydomain.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: my-service
                port:
                  number: 80

ingressClassName tells Kubernetes which Ingress Controller should handle this rule (useful when you run more than one). Each entry under rules associates a host with a list of paths; each path points at a specific Service and port — so you can route /api to a backend and / to a frontend with the same Ingress.

Step 4 — TLS (the padlock in the browser)

The tls block tells the Ingress Controller to serve that host over HTTPS using the certificate stored in the Secret my-tls-secret (of type kubernetes.io/tls, with the keys tls.crt and tls.key). In production that Secret is almost always filled in automatically by cert-manager, requesting a free certificate from Let's Encrypt — but the Ingress doesn't need to know how it was generated, only where it is.

What if I only have one app and don't want an Ingress Controller?

For a very simple case, a Service of type LoadBalancer (on a cloud that supports it) gives you a public IP directly, with no Ingress needed. The downside is that each Service of that type usually bills its own cloud load balancer — with two or three apps, a single Ingress works out cheaper and tidier.

Generate the Service and the Ingress for your app — TLS block included — with our Kubernetes manifest generator, and combine both into a single file with the bundle mode.

← Back to the generator