It’s a pretty common requirement to connect with an external service inside your Kubernetes cluster.

For example, you might have an external API or a database running on another host. And you want your application deployed in Kubernetes to access the API or the database.

Here’s what it looks like in practice:

connect external service from inside kubernetes cluster
Kubernetes Connect External Service

There are a couple of ways you can connect with an external service in Kubernetes.

In this post, I will show you both ways.

But before that, let me introduce the concept of service endpoints in Kubernetes.

Service Endpoints in Kubernetes

In the post about Kubernetes services, I talked about how a service is backed by one or more pods running inside the cluster.

However, services don’t link to pods directly.

A resource known as Endpoints sits between the Kubernetes service and underlying pods. You can check it out if you describe the service using the kubectl describe svc command.

saurabhdashora@Saurabhs-MacBook-Air basic-pod-demo % kubectl describe svc demo
Name:              demo
Namespace:         default
Labels:            <none>
Annotations:       <none>
Selector:          app=hello-service
Type:              ClusterIP
IP Family Policy:  SingleStack
IP Families:       IPv4
IP:                10.100.68.216
IPs:               10.100.68.216
Port:              <unset>  80/TCP
TargetPort:        3000/TCP
Endpoints:         10.1.0.95:3000,10.1.0.96:3000,10.1.0.97:3000
Session Affinity:  None
Events:            <none>

The Endpoints resource is basically a list of IP addresses and ports exposing a particular service.

In fact, the Endpoints resource is just like any other Kubernetes resource. You can display it’s information with kubectl get command.

saurabhdashora@Saurabhs-MacBook-Air basic-pod-demo % kubectl get endpoints demo
NAME   ENDPOINTS                                      AGE
demo   10.1.0.95:3000,10.1.0.96:3000,10.1.0.97:3000   4d20h

The pod selector declared in the service spec is used to build a list of IPs and ports that is stored in the Endpoints resource. When a client connects to a service, the service proxy selects one of those IP and port pairs and redirects the incoming connection request to the appropriate server.

Approach 1 – External Service with Kubernetes Service Endpoints

With this knowledge of service endpoints, we can look at the first approach to connect to external service.

This approach involves manually configuring the Kubernetes Service Endpoints instead of relying on the pod selectors.

Yes, you read that correctly.

You can manually configure the service endpoint. Basically, it involves two steps:

  • Create a Kubernetes service resource without a selector. This won’t populate the endpoints.
  • Manually create the Endpoints resource.

Here’s the YAML file for the Kubernetes service without a selector.

apiVersion: v1
kind: Service
metadata:
  name: external-service
spec:
  ports:
  - port: 80

Basically, we are defining a service external-service that will accept connections on port 80.

Now, you can create an Endpoints resource as below:

apiVersion: v1
kind: Endpoints
metadata:
  name: external-service
subsets:
  - addresses:
    - ip: 44.44.44.44
    - ip: 33.33.33.33
    ports:
    - port: 80

Few things to keep in mind:

  • The Kubernetes Endpoints objects must have the same name as the service.
  • It must contain the list of target IP addresses and ports for the service.

After applying both the resources, you can use the service just like any regular Kubernetes service. Any container created after the service will include the environment variables for service.

Let’s now look at the 2nd approach.

Approach 2 – Connecting External Service with ExternalName Service

I like the 2nd approach better because it lets us refer to the external by its fully qualified domain name or FQDN.

This means that we don’t need to manually configure the Endpoints resource for the service.

In this approach, we basically create a Kubernetes service of type ExternalName.

For example, if I want to expose an external API like jsonplaceholder.typicode.com, here’s the YAML file for the service object.

apiVersion: v1
kind: Service
metadata:
  name: external-service
spec:
  type: ExternalName
  externalName: jsonplaceholder.typicode.com

Note that the type is ExternalName and not ClusterIP. If interested, you can read more about Kubernetes ClusterIP services.

After the service is created, pods can connect to the external service through the external-service.default.svc.cluster.local domain name.

In fact, you can also just use external-service.

This is a great feature as it hides the actual service name and its location from the pods consuming the service. In future, you can easily swap the actual service and point the Kubernetes service to different service without impacting the pods.

Also, ExternalName services are implemented at the DNS level. Basically, a simple CNAME DNS record is created for service. This means that any client connecting to the service will directly connect to the external service. It will bypass the service proxy completely and hence no need for a cluster IP.

You can check this out by inspecting the output of dnsutils as below:

saurabhdashora@Saurabhs-MacBook-Air basic-pod-demo % kubectl exec basic-rc-c8v7l -- nslookup external-service.default.svc.cluster.local
Server:		10.96.0.10
Address:	10.96.0.10:53

external-service.default.svc.cluster.local	canonical name = jsonplaceholder.typicode.com
Name:	jsonplaceholder.typicode.com
Address: 104.26.3.137
Name:	jsonplaceholder.typicode.com
Address: 104.26.2.137
Name:	jsonplaceholder.typicode.com
Address: 172.67.69.149

external-service.default.svc.cluster.local	canonical name = jsonplaceholder.typicode.com
Name:	jsonplaceholder.typicode.com
Address: 2606:4700:20::681a:389
Name:	jsonplaceholder.typicode.com
Address: 2606:4700:20::681a:289
Name:	jsonplaceholder.typicode.com
Address: 2606:4700:20::ac43:4595

As visible, the external-service is mapped to jsonplaceholder.typicode.com as per the DNS records.

Conclusion

That’s all for this post.

We saw both the approaches to connect to an external service from within your Kubernetes cluster.

  • By configuring the Endpoints resource
  • By creating an ExternalName service

If you have any comments or queries, please write them in the comments section below.

Categories: BlogKubernetes

Saurabh Dashora

Saurabh is a Software Architect with over 12 years of experience. He has worked on large-scale distributed systems across various domains and organizations. He is also a passionate Technical Writer and loves sharing knowledge in the community.

0 Comments

Leave a Reply

Your email address will not be published. Required fields are marked *