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.
Contents
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 appear 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:
[simterm]
$ kubectl apply -f svc-example.yaml pod/nginx-pod created service/nginx-svc created
[/simterm]
Check the Service:
[simterm]
$ 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
[/simterm]
Kubernetes Endpoints
Now, let’s take a closer look at it:
[simterm]
$ 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
[/simterm]
In the end, we can the Endpoints of this Service – the IP od the pod.
Check this Pod:
[simterm]
$ 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 ...
[/simterm]
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:
[simterm]
$ kubectl get endpoints nginx-svc NAME ENDPOINTS AGE nginx-svc 10.21.56.143:80 18m
[/simterm]
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:
[simterm]
$ kubectl apply -f svc-example.yaml deployment.apps/nginx-deploy created service/nginx-svc unchanged
[/simterm]
And check the Endpoints:
[simterm]
$ 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
[/simterm]
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:
[simterm]
$ 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
[/simterm]
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 Serviceaddresses
: 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 iptablesports.port
andports.name
also must be the same as the corresponding Service
Create them:
[simterm]
$ kubectl apply -f external-endpoint.yaml service/external-svc created endpoints/external-svc created
[/simterm]
Check the Service and its Endpoints:
[simterm]
$ 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
[/simterm]
Run a Pod to check if this Service working:
[simterm]
$ kubectl run pod --rm -i --tty --image ubuntu -- bash
[/simterm]
Install the curl
in this pod:
[simterm]
root@pod:/# apt update && apt -y install curl
[/simterm]
And check the Service by its name:
[simterm]
root@pod:/# curl -Ls external-svc | grep \<title\> <title>RTFM: Linux, DevOps, and system administration</title>
[/simterm]
Or by using its FQDN:
[simterm]
root@pod:/# curl -Ls external-svc.default.svc.cluster.local | grep \<title\> <title>RTFM: Linux, DevOps, and system administration</title>
[/simterm]
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:
[simterm]
root@pod:/# curl -Ls rtfm-service | grep \<title\> <title>RTFM: Linux, DevOps, and system administration</title>
[/simterm]
Done.