Using endpoints and external services in kubernetes

Sometimes we need to access services in our cluster via network which are not yet part of the cluster, but we plan on migrating them at some point. Or there are webservices still running on some old piece of junk, but we'd like to have all the comforts of an ingress controller in place, before we are touching that old damn thing.

Luckily, there are at least two ways (network plugins such as cilium offer even further ways) to reflect such things in native kubernetes resources, which, although simple, are not that well known as one would expect.

Endpoint + Service

Usually when working with services, we use labels to select pods. In the background, kubernetes then creates an Endpoint object bearing the same name as our service, which is then regularly updated depending on the type of the service and contains the ports and IPs of the, well, endpoints.

But we can also simply create our own Endpoint object. The following would create and Endpoint and a Service, allowing us to access the ips and named ports in the Endpoint via the service.

---
apiVersion: v1
kind: Endpoints
metadata:
  name: example
subsets:
  - addresses:
      - ip: 10.0.0.1
      - ip: 10.0.0.2
    ports:
      - port: 80
        name: http
      - port: 9100
        name: metrics

Now this endpoint would be created in the default namespace and point at the ips 10.0.0.1 and 10.0.0.2, exposing port 80 under the name http and 9100 under the name metrics. To have it accessible via a service, we now need a service with the same name in the same namespace. There is no magic using labels involved.

---
apiVersion: v1
kind: Service
metadata:
  name: example
spec:
  ports:
  - port: 80
    protocol: TCP
    targetPort: 80
    name: http
  - port: 9100
    protocol: TCP
    targetPort: 9100
    name: metrics

ExternalName Service

When we already have a DNS name we can use, we can use a Service of type ExternalName. This also could just be a service in another namespace, such as example.another-namespace.svc!

---
kind: Service
apiVersion: v1
metadata:
  name: external-example
spec:
  type: ExternalName
  externalName: example.org
  ports:
    - protocol: TCP
      port: 80
      targetPort: 80
      name: http
    - protocol: TCP
      port: 9100
      targetPort: 9100
      name: http

In both instances we now have a Service example in our default namespace, exposing port 80 and 9100 of some, possibly external, entity.

social