Deployment, Service and Ingress
A Deployment runs the replicas, a Service gives them one stable address, and an Ingress routes outside traffic to it.
kubectl apply -f deployment.yaml -f service.yaml -f ingress.yamlKubernetes is told what you want, not what to do. You write manifests (YAML files describing objects), apply them, and controllers work to make the cluster match. A Node HTTP service normally needs three.
Deployment
A Deployment names the image to run and how many replicas (identical running copies) to keep. It also carries the environment variables for each copy. If a copy exits, the Deployment starts another.
Service
Each replica gets its own IP address, and that address changes whenever the replica is replaced. A Service is one stable name and address in front of all of them, spreading connections across the ready ones. port is the port the Service answers on; targetPort is the port inside the container it forwards to.
Ingress
A Service of the default type, ClusterIP, is reachable from inside the cluster only. An Ingress maps an outside hostname and path to a Service, and it needs an ingress controller running in the cluster to act on it. Without one, the Ingress object exists and nothing happens.
What Node has to do
Listen on every interface. server.listen(port) with the host left out binds the unspecified address — :: where IPv6 is available, otherwise 0.0.0.0 — and accepts connections from anywhere. The longhand server.listen(port, '0.0.0.0') says the same thing explicitly. server.listen(port, '127.0.0.1') accepts connections only from inside the container itself, so the Service and the probes get nothing.
Example
When to use it
- Putting a Node HTTP service behind one stable in-cluster name other services can call.
- Exposing that service on a public hostname through an ingress controller.
- Finding out why a Service returns nothing when the pods are running.
- Giving each environment its own replica count and image tag in one file.
More examples
The Deployment and the Service, side by side
Two labels do the wiring: the Deployment's selector finds its own pods, and the Service's selector finds the same pods. Referring to targetPort by name rather than number means the number lives in one place. A Service named api also creates the DNS name api, which is how another service in the same namespace calls this one.
apiVersion: apps/v1
kind: Deployment
metadata:
name: api
spec:
replicas: 3
selector:
matchLabels:
app: api # must match the pod labels below
template:
metadata:
labels:
app: api
spec:
containers:
- name: api
image: registry.example.com/api:1.4.2
ports:
- name: http # a name the Service and probes can refer to
containerPort: 8080
env:
- name: PORT
value: "8080"
---
apiVersion: v1
kind: Service
metadata:
name: api # other pods reach this as http://api
spec:
selector:
app: api # picks up every pod with this label
ports:
- port: 80 # the port the Service answers on
targetPort: http # the named container port; 8080 works tooAn Ingress for one hostname
The port here is the Service's port (80), not the port Node listens on (8080), which is the pair most often mixed up. pathType has no default and the API rejects a path without it. If requests return nothing after applying this, check that a controller matching ingressClassName is actually installed.
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: api
spec:
ingressClassName: nginx # which controller should handle this
rules:
- host: api.example.com
http:
paths:
- path: /
pathType: Prefix # required; Prefix or Exact
backend:
service:
name: api
port:
number: 80 # the Service's port, not the container'sSeeing what the cluster did with it
An empty endpoint list is the single most useful diagnostic: it separates a labelling mistake from an application problem. port-forward takes the Ingress and the load balancer out of the picture, so a failure there is inside the cluster and a success there points at the Ingress.
kubectl apply -f deployment.yaml -f service.yaml -f ingress.yaml
# Did the pods come up, and are they Ready?
kubectl get pods -l app=api
# Does the Service have endpoints? Empty means no pod matches the selector,
# or no pod is passing its readiness check.
kubectl get endpointslices -l kubernetes.io/service-name=api
# Reach the Service from your machine without an Ingress, for a quick check.
kubectl port-forward service/api 8080:80
Discussion