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: 70Kubernetes 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.
How it works
All 13 resources and what they do
- Client Browser
- Sends
GET https://shop.example.com/. DNS forshop.example.compoints at the cloud load balancer. - Load balancer Cloud load balancer
- Created by the cloud provider for the ingress controller's
type: LoadBalancerService. 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.comand path/to theshopService 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.crtandtls.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: shopand 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
readycondition 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: shopcopied 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 examplekubectl rollout restart deployment/shop. - HorizontalPodAutoscaler shopautoscaling/v2
- Changes
spec.replicason 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=shopshows an empty list when this happens. Compare the selector withkubectl get pods -n shop --show-labels. - An Ingress without
ingressClassNameis ignored, unless one IngressClass has theingressclass.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 podsshows them all as Running. - Setting
spec.replicasin a Deployment that an HPA manages makes everykubectl applyreset the count. Leavereplicasout 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.
Keep going
More graphs
- Gateway API: GatewayClass, Gateway and HTTPRoute with a canary split
- PVC, StorageClass and CSI: how a cloud disk ends up in your Pod
- RBAC: how a ServiceAccount gets its permissions
- cert-manager with Let's Encrypt: Certificate, CertificateRequest, Order and Challenge
- A private CA with cert-manager and trust-manager
- Istio traffic management: Gateway, VirtualService, DestinationRule and policies
- Flux dependencies: Git and OCI sources, Kustomizations and HelmReleases
- Argo CD: ApplicationSet, AppProject and the Applications it generates
- Inside an OCI image: tag, index, manifests, config and layers
- OCI artifacts: Helm charts, Flux artifacts and image volumes