k8wiz
All graphs

Kubernetes graph

Deployment, Service and Ingress: how a request reaches your Pods

Every object between a browser and a container in a classic Kubernetes web app: Deployment, ReplicaSet, Pods, Service, EndpointSlice, Ingress, TLS Secret and HPA.

This is the setup most people deploy first: a stateless web app behind an Ingress. You write five objects. Kubernetes and the ingress controller create the rest, and most debugging comes down to knowing which object created which.

The ingress controller here is Traefik, but the shape is the same with HAProxy, Contour or any other controller. The Service only finds Pods by label, and the controller sends traffic straight to Pod IPs that it reads from EndpointSlices. It doesn't go through the Service's ClusterIP.

Interactive graph

Click a resource to see what it does, or follow the setup step by step.

Outside the clusterComes with an add-onYou write itCreated by a controllertrafficreferencescreatesselects by label

How it works

All 13 resources and what they do

Client Browser
Sends GET https://shop.example.com/. DNS for shop.example.com points at the cloud load balancer.
Load balancer Cloud load balancer
Created by the cloud provider for the ingress controller's type: LoadBalancer Service. It forwards ports 80 and 443 to the controller Pods.
Deployment traefikapps/v1
The ingress controller, installed with its Helm chart. It watches Ingress objects of its class, loads their TLS Secrets, and proxies each request to a Pod IP it reads from EndpointSlices.
IngressClass traefiknetworking.k8s.io/v1
Names the controller that serves Ingresses with ingressClassName: traefik. A cluster can run several controllers, and the class decides which one picks up an Ingress.
Ingress shopnetworking.k8s.io/v1
Maps the host shop.example.com and path / to the shop Service on port 80, and names the Secret with the TLS certificate. It only describes routing. The controller does the work.
Secret shop-tlsv1
Holds the certificate and private key as tls.crt and tls.key. It must be in the Ingress's namespace. cert-manager can create and renew it for you.
Service shopv1
Selects Pods with the label app: shop and gives them one stable name, shop.shop.svc.cluster.local. Port 80 on the Service maps to port 8080 in the container.
EndpointSlice shop-x7k2pdiscovery.k8s.io/v1
Created by the EndpointSlice controller for the Service. It lists the IP of every Pod the selector matches, with a ready condition that follows the readiness probe. Ingress controllers and kube-proxy read this, not the Service.
Deployment shopapps/v1
Declares the Pod template and the rollout strategy. On every change to the template it creates a new ReplicaSet and scales the old one down.
ReplicaSet shop-7d9f8c6b5apps/v1
Created by the Deployment, one per version of the Pod template. The suffix is a hash of the template. It keeps the replica count of Pods running.
Pod shop-7d9f8c6b5-xxxxxv1
Three Pods created by the ReplicaSet, each with the label app: shop copied from the template. That label is the only link between them and the Service.
ConfigMap shop-configv1
Settings loaded as environment variables through envFrom. Pods read it only at start, so changing it needs a rollout, for example kubectl rollout restart deployment/shop.
HorizontalPodAutoscaler shopautoscaling/v2
Changes spec.replicas on the Deployment to keep average CPU near 70% of the requested 200m. It needs metrics-server and CPU requests on the containers.

Common mistakes

  • A selector that matches no Pods gives a Service with no endpoints, and the controller returns 503. kubectl get endpointslices -n shop -l kubernetes.io/service-name=shop shows an empty list when this happens. Compare the selector with kubectl get pods -n shop --show-labels.
  • An Ingress without ingressClassName is ignored, unless one IngressClass has the ingressclass.kubernetes.io/is-default-class: "true" annotation.
  • The Ingress, its backend Service and its TLS Secret must all be in the same namespace. An Ingress can't point at a Service in another namespace. Gateway API can, with a ReferenceGrant.
  • A failing readiness probe takes the Pod out of rotation, and that's by design. If every Pod fails it, the app is down even though kubectl get pods shows them all as Running.
  • Setting spec.replicas in a Deployment that an HPA manages makes every kubectl apply reset the count. Leave replicas out of the manifest once the HPA owns it.

The manifests you write

Everything above that is marked "You write it", in one file. The rest comes from add-ons and controllers.

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: shop
  namespace: shop
spec:
  ingressClassName: traefik
  tls:
    - hosts: [shop.example.com]
      secretName: shop-tls
  rules:
    - host: shop.example.com
      http:
        paths:
          - path: /
            pathType: Prefix
            backend:
              service:
                name: shop
                port:
                  number: 80
---
apiVersion: v1
kind: Secret
metadata:
  name: shop-tls
  namespace: shop
type: kubernetes.io/tls
data:
  tls.crt: LS0tLS1CRUdJTi... # base64 PEM
  tls.key: LS0tLS1CRUdJTi...
---
apiVersion: v1
kind: Service
metadata:
  name: shop
  namespace: shop
spec:
  selector:
    app: shop
  ports:
    - name: http
      port: 80
      targetPort: 8080
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: shop
  namespace: shop
spec:
  replicas: 3
  selector:
    matchLabels:
      app: shop
  template:
    metadata:
      labels:
        app: shop
    spec:
      containers:
        - name: shop
          image: ghcr.io/acme/shop:1.4.2
          ports:
            - containerPort: 8080
          envFrom:
            - configMapRef:
                name: shop-config
          readinessProbe:
            httpGet:
              path: /healthz
              port: 8080
          resources:
            requests:
              cpu: 200m
              memory: 256Mi
---
apiVersion: v1
kind: ConfigMap
metadata:
  name: shop-config
  namespace: shop
data:
  LOG_LEVEL: info
  PAYMENTS_URL: http://payments.payments.svc:8080
---
apiVersion: autoscaling/v2
kind: HorizontalPodAutoscaler
metadata:
  name: shop
  namespace: shop
spec:
  scaleTargetRef:
    apiVersion: apps/v1
    kind: Deployment
    name: shop
  minReplicas: 3
  maxReplicas: 10
  metrics:
    - type: Resource
      resource:
        name: cpu
        target:
          type: Utilization
          averageUtilization: 70

Keep going

More graphs