How do I call another kubernetes service inside the same cluster
Let's say you have a nodejs backend deployed in Kubernetes, and wanted to call another service inside your Kubernetes cluster. How do you do it? (Skip to answer by scrolling down to the bottom) Read more about DNS in kubernetes here: https://basantakharel.com/dns-in-kubernetes-more-than-just-name-resolution
const axios = require('axios');
//DONOT use in production without error handling
const {data} = await axios.get('some-service');
Assuming you have some knowledge of Kubernetes(K8s), you know that you need a deployment and a service
To give basic info here is some description of deployment and service
Deployment
A Deployment provides declarative updates for Pods and ReplicaSets.
You describe a desired state in a Deployment, and the Deployment Controller changes the actual state to the desired state at a controlled rate. You can define Deployments to create new ReplicaSets or to remove existing Deployments and adopt all their resources with new Deployments.
You don't want to be creating pods manually or even replica sets but use deployment which handles rollout/rollback of your pods(not useful if you have only one replica as in the example below but good practice nonetheless)
Check out the K8s deployment official documentation for more info
And here is a sample YAML file for a deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: some-service-dpl
spec:
replicas: 1
selector:
matchLabels:
app: some-service-dpl
template:
metadata:
labels:
app: some-service-dpl
spec:
containers:
- name: some-service-dpl
image: yourdockerregistry/some-service-dpl-image
ports:
- containerPort: 8080
Service
A Kubernetes Service is an abstraction that defines a logical set of Pods running somewhere in your cluster, that all provide the same functionality. When created, each Service is assigned a unique IP address (also called clusterIP). This address is tied to the lifespan of the Service, and will not change while the Service is alive.
Service by default is of type ClusterIP which exposes the service on cluster-internal IP which will not change while the service is alive. But it will if it is killed and a new one spins up so an IP address is not a full proof way to talk to a service
Check out the K8s service official documentation for more info
Here is YAML file for a service that is exposing the previous deployment
kind: Service
apiVersion: v1
metadata:
name: some-service-svc
spec:
selector:
app: some-service-svc
ports:
- name: some-service-api
targetPort: 8080
port: 8080
protocol: TCP
So how do we talk to this service backend? The whole point of creating the service was to get a stable IP for the pods managed by replica sets managed by some-service-dpl. So we don't want to talk to the pods directly
We also don't want to talk to the service directly using an IP address which can be found by this simple kubectl command. Especially not if we are deploying both services at the same time and there is no way to know the IP address beforehand
kubectl get svc some-service-svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
some-service-svc ClusterIP 10.0.15.149 <none> 8080/TCP 21s
What we do want to use is the name of the service itself and that's it!
This works because K8s uses DNS for services and pods and internally resolves some-service-svc:8080 to http://10.0.15.149:8080. Below you can see the fully qualified DNS name for a service
{{service_name}}.{{namespace}}.svc.cluster.local
const axios = require('axios');
//DONOT use in production without error handling
const {data} = await axios.get('http://some-service-svc:8080');
//if the service was in some other namespace
const {data} = await axios.get('http://some-service-svc.otherNamespace.svc.cluster.local:8080');
Just make sure that you keep track of the name of your service or add the service and port exposed by the service in your environment from config variables (from Helm values if you use Helm for example)