Service to Service call patterns — Multi-cluster Services

Biju Kunjummen
3 min readDec 21, 2021

This is third blog post as part of a series exploring service to service call patterns in different application runtimes in Google Cloud.

The first post explored Service to Service call pattern in a GKE runtime using a Kubernetes Service abstraction

The second post explored Service to Service call pattern in a GKE runtime with Anthos Service mesh.

This post will explore the call pattern across multiple GKE runtimes with Multi-Cluster Services providing a way for calls to be made across clusters.

Mind you, the preferred way for service to service call ACROSS clusters is using Anthos Service Mesh, which will be covered in the next blog post, however Multi-Cluster service is also a perfectly valid approach in the absence of Anthos Service Mesh.

Target Architecture

A target architecture that I am aiming for is the following:

Here two different applications are hosted on two separate Kubernetes clusters in different availability zones and the Service(called “Caller”) in one cluster invokes the Service(called “Producer”) in another cluster.

Creating the Cluster with Multi-cluster services

The details on bringing up 2 clusters and enabling Multi-cluster services is detailed in this document

Services Installation

Assuming that the 2 GKE clusters are now available, the first cluster holds the Caller and an Ingress Gateway to enable the UI of the caller to be accessible to the user. This is through a deployment descriptor which looks something like this for the caller:

apiVersion: apps/v1
kind: Deployment
metadata:
name: sample-caller-v1
labels:
app: sample-caller
version: v1
spec:
replicas: 1
selector:
matchLabels:
app: sample-caller
version: v1
template:
metadata:
labels:
app: sample-caller
version: v1
spec:
serviceAccountName: sample-caller-sa
containers:
- name: sample-caller
image: us-docker.pkg.dev/sample/docker-repo/sample-caller:latest
imagePullPolicy: IfNotPresent
ports:
- containerPort: 8080
securityContext:
runAsUser: 1000
resources:
requests:
memory: "256Mi"
livenessProbe:
httpGet:
path: /actuator/health/liveness
port: 8080
initialDelaySeconds: 3
periodSeconds: 3
readinessProbe:
httpGet:
path: /actuator/health/readiness
port: 8080

I have reproduced the entire yaml just for demonstration, there is nothing that should stand out in the file.

Along the same lines the Producer application is deployed to the second cluster.

Caller to Producer call — Using Multi-Cluster Services

Multi-cluster service is described in detail in this blog post and this how to post

The short of it is that if a “ServiceExport” resource is defined in cluster 2 and if the same namespace exists in Cluster 1 then the Service is resolved using a host name of the form “service-name.namespace.svc.clusterset.local” and in my case this maps to “sample-producer.istio-apps.svc.clusterset.local”!. The ServiceExport resource looks something like this:

kind: ServiceExport
apiVersion: net.gke.io/v1
metadata:
namespace: istio-apps
name: sample-producer

This is the only change that I have to make to the caller, instead of calling Producer using “sample-producer”, now it uses the host name of “sample-producer.istio-apps.svc.clusterset.local” and everything resolves cleanly and the call continues to work across the cluster.

From the Callers perspective:

From the Producers perspective:

Conclusion

I hope this clarifies to some extent how service to service call can be enable across multiple clusters, even across regions.

There are a few catches, for eg, to get the Mutual TLS to work across clusters is not easy, this is where Anthos Service mesh really shines and will be the topic of the next blog post.

Originally published at http://www.java-allandsundry.com.

--

--

Biju Kunjummen

Sharing knowledge about Java, Cloud and general software engineering practices