Kubernetes: what are Endpoints
Arseny Zinchenko
Posted on March 18, 2021
Usually, we don’t see Endpoints objects when using Kubernetes Services, as they are working under the hood, similarly to ReplicaSets which are “hidden” behind Kubernetes Deployments.
Kubernetes Service
So, Service is a Kubernetes abstraction that uses labels to chose pods to route traffic to, see the Kubernetes: ClusterIP vs NodePort vs LoadBalancer, Services, and Ingress — an overview with examples and Kubernetes: Service, load balancing, kube-proxy, and iptables:
apiVersion: v1
kind: Service
metadata:
name: my-service
spec:
selector:
app: MyApp
ports:
- protocol: TCP
port: 80
targetPort: 9376
As soon as a new pod appears in a cluster, with labels matching with Service’s selector
, the app=MyApp
in the example above - Service will start sending traffic to it.
This is achieved by adding an IP address of this Pod to the Endpoints list of this Service.
Let’s create a simple example:
--------
apiVersion: v1
kind: Pod
metadata:
name: nginx-pod
labels:
app: nginx
spec:
containers:
- name: nginx-container
image: nginx
ports:
- name: web
containerPort: 80
protocol: TCP
--------
apiVersion: v1
kind: Service
metadata:
name: nginx-svc
spec:
selector:
app: nginx
ports:
- protocol: TCP
port: 80
targetPort: 80
Here, we are creating a Pod with NGINX, and a Service with the default type ClusterIP
.
Apply the manifest:
$ kubectl apply -f svc-example.yaml
pod/nginx-pod created
service/nginx-svc created
Check the Service:
$ kubectl get service nginx-svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
nginx-svc ClusterIP 172.20.69.253 <none> 80/TCP 26s
Kubernetes Endpoints
Now, let’s take a closer look at it:
$ kubectl describe service nginx-svc
Name: nginx-svc
Namespace: default
Labels: <none>
Annotations: <none>
Selector: app=nginx
Type: ClusterIP
IP Families: <none>
IP: 172.20.69.253
IPs: <none>
Port: <unset> 80/TCP
TargetPort: 80/TCP
Endpoints: 10.21.56.143:80
In the end, we can the Endpoints of this Service — the IP of the pod.
Check this Pod:
$ kubectl describe pod nginx-pod
Name: nginx-pod
Namespace: default
Priority: 0
Node: ip-10–21–49–33.us-east-2.compute.internal/10.21.49.33
Start Time: Sat, 13 Mar 2021 08:37:55 +0200
Labels: app=nginx
Annotations: kubernetes.io/psp: eks.privileged
Status: Running
IP: 10.21.56.143
…
Here is the IP mentioned above.
And now, let’s check the Ednpointds, which are dedicated API-objects and which can be observed in the same way as Services and Pods:
$ kubectl get endpoints nginx-svc
NAME ENDPOINTS AGE
nginx-svc 10.21.56.143:80 18m
If we will add other pods with the same labels by describing them as additional objects in the manifest file or by creating a Deployment — those pods will be added as Endpoints for the Service:
--------
apiVersion: apps/v1
kind: Deployment
metadata:
name: nginx-deploy
labels:
app: nginx
spec:
replicas: 2
selector:
matchLabels:
app: nginx
template:
metadata:
labels:
app: nginx
spec:
containers:
- name: nginx-container
image: nginx
ports:
- name: web
containerPort: 80
protocol: TCP
--------
apiVersion: v1
kind: Service
metadata:
name: nginx-svc
spec:
selector:
app: nginx
ports:
- protocol: TCP
port: 80
targetPort: 80
Create the Deployment:
$ kubectl apply -f svc-example.yaml
deployment.apps/nginx-deploy created
service/nginx-svc unchanged
And check the Endpoints:
$ kubectl get endpoints nginx-svc
NAME ENDPOINTS AGE
nginx-svc 10.21.37.55:80,10.21.54.174:80,10.21.56.143:80 21m
Here we can see our 10.21.56.143:80 from the previous pod, and two new — from the pods specified in the replicas
of the Deployment above.
Find those pods by using the --selector, similarly, as a Service looks for pods to add them to its Endpoints:
$ kubectl get pod --selector=app=nginx -o wide
NAME READY STATUS RESTARTS AGE IP
nginx-deploy-7fcd954c94-gbm6d 1/1 Running 0 2m28s 10.21.54.174
nginx-deploy-7fcd954c94-mg8kr 1/1 Running 0 2m28s 10.21.37.55
nginx-pod 1/1 Running 0 23m 10.21.56.143
Custom Endpoint
We also can create a custom endpoint that will be pointed to any desired resource.
For example, describe a new Service:
kind: Service
apiVersion: v1
metadata:
name: external-svc
spec:
ports:
- name: web
protocol: TCP
port: 80
targetPort: 80
Pay attention, that in this case, we didn’t add the selector
field.
And describe the Endpoints object:
kind: Endpoints
apiVersion: v1
metadata:
name: external-svc
subsets:
- addresses:
- ip: 139.59.205.180
ports:
- port: 80
name: web
Here:
-
name
: must be the same as the Service -
addresses
: an address to send traffic to, in this example this an IP address of a server in the DigitalOcean cloud where the rtfm.co.ua is leaving, but you can set multiply address so the Service will do load-balancing between them as described in the Kubernetes: Service, load balancing, kube-proxy, and iptables -
ports.port
andports.name
also must be the same as the corresponding Service
Create them:
$ kubectl apply -f external-endpoint.yaml
service/external-svc created
endpoints/external-svc created
Check the Service and its Endpoints:
kubectl describe svc external-svc
Name: external-svc
Namespace: default
Labels: <none>
Annotations: <none>
Selector: <none>
Type: ClusterIP
IP Families: <none>
IP: 172.20.45.77
IPs: <none>
Port: web 80/TCP
TargetPort: 80/TCP
Endpoints: 139.59.205.180:80
Run a Pod to check if this Service working:
$ kubectl run pod — rm -i — tty — image ubuntu — bash
Install the curl
in this pod:
root@pod:/# apt update && apt -y install curl
And check the Service by its name:
root@pod:/# curl -Ls external-svc | grep \<title\>
<title>RTFM: Linux, DevOps, and system administration</title>
Or by using its FQDN:
root@pod:/# curl -Ls external-svc.default.svc.cluster.local | grep \<title\>
<title>RTFM: Linux, DevOps, and system administration</title>
externalName
Another solution to access an external resource can be using a Service with the externalName type:
--------
apiVersion: v1
kind: Service
metadata:
name: rtfm-service
spec:
ports:
- port: 80
type: ExternalName
externalName: rtfm.co.ua
Apply, and check:
$ root@pod:/# curl -Ls rtfm-service | grep \<title\>
<title>RTFM: Linux, DevOps, and system administration</title>
Done.
Originally published at RTFM: Linux, DevOps и системное администрирование.
Posted on March 18, 2021
Join Our Newsletter. No Spam, Only the good stuff.
Sign up to receive the latest update from our blog.