This great quote by Epictetus teaches us a lot about reliability. And it hits the nail on the head when it comes to DevOps. Case in point: setting up multi-regional clusters to safeguard reliability of your microservices. You can’t rely on one Google Kubernetes Cluster (GKE) running in one zone of a region, though you can create a regional (multi-zonal) cluster, where the master cluster and nodes are distributed in different zones of a region (read more about zones and regions here). That way, even if one zone is down, your services and nodes continue to run in the other zones, and you don’t have to lose any sleep over it. But what if the entire region goes down? Even a few seconds of downtime in a regional cluster can render your service entirely unavailable. I’ve scoured the internet for answers, and here’s what I found… There is documentation on how to route HTTP and HTTPS traffic to multi-regional clusters: with Google Cloud Platform’s (GCP) recently introduced command-line interface (CLI) tool, kubemci, you can automatically configure Ingress using Google Cloud Load Balancer (GCLB) for multi-cluster Kubernetes Engine environments. What you’ll have is something like this:“Neither should a ship rely on one small anchor nor should life rest on a single hope.”
GCP’s kubemci tool is useful for HTTP and HTTPS traffic, but not for TCP traffic. Image Source The beta release of kubemci is useful for creating the same services in multiple clusters (say, cluster-south and cluster-southeast) in multiple regions, and to access those services using a common IP of the Google Cloud Load Balancer (GCLB). This Setting Up A Multi-Cluster Ingress document by GCP helps achieve high availability in case of regional failure. According to the Kubernetes Ingress Documentation: “Ingress exposes HTTP and HTTPS routes from outside the cluster to services within the cluster.” But this doesn’t apply to TCP traffic. There’s also documentation on how to route TCP traffic to individual VMs. There’s surprisingly little documentation on how to route TCP traffic to two GKE clusters (i.e. groups of VMs) sitting in different regions. If you’ve tried to look this up, you know the struggle of finding any comprehensive tutorial. It took a bit of work but I finally figured it out, and I just had to share it with you.
# Cluster name: cluster-south
gcloud container clusters create cluster-south \
--num-nodes 2 \
--zone asia-south1-a
# Cluster name: cluster-southeast
gcloud container clusters create cluster-south \
--num-nodes 2 \
--zone asia-south1-a
Use kubectl to deploy services and applications on the cluster. Make your kubectl point to your clusters one by one using the following command:
gcloud container clusters get-credentials cluster-name \
--zone zone-name
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: sftp-claim
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: 100Mi
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
labels:
app: sftp
name: sftp
spec:
replicas: 1
strategy:
type: Recreate
template:
metadata:
labels:
app: sftp
spec:
containers:
- env:
- name: USER
value: user
- name: PASS
value: pass
image: writl/sftp:latest
name: sftp
ports:
- containerPort: 22
resources: {}
volumeMounts:
- mountPath: /data/incoming
name: sftp-claim
restartPolicy: Always
volumes:
- name: sftp-claim
persistentVolumeClaim:
claimName: sftp-claim
Put it in a file named “sftp.yaml” and run the kubectl apply -f sftp.yaml command for both the clusters (switching the context using the gcloud container clusters get-credentials command explained in Step 1). If you notice, a Persistent Volume Claim is also being created through “sftp.yaml”. We are using the writl/sftp docker image to set up an easy and simple sftp server.
Similarly, create a NodePort service that exposes port 30061 by putting the following manifest in an sftp-service.yaml file and run the kubectl apply -f sftp-service.yaml command:
apiVersion: v1
kind: Service
metadata:
name: sftp-service
spec:
type: NodePort
ports:
-
protocol: TCP
port: 80
targetPort: 22
nodePort: 30061
selector:
app: sftp
Next, run kubectl get services,pods to make sure the pods and services run on both the clusters. For both clusters, the output will be something like this:
NAME READY STATUS RESTARTS AGE
pod/sftp-hfs8v 1/1 Running 0 78s
pod/sftp-nqhb2 1/1 Running 0 78s
NAME TYPE CLUSTER-IP PORT(S)
service/kubernetes ClusterIP 14.52.232.1 443/TCP
service/sftp-svc NodePort 13.57.246.1 80:30061/TCP
NAME LOCATION INSTANCES
cluster-south..grp asia-south1-a 2
cluster-southeast..grp asia-southeast1-a 2
Set the named-ports for both groups by running the following command:
cloud compute instance-groups set-named-ports \
instance-group-name \
--named-ports np30061:30061
--zone zone-name
gcloud compute health-checks create tcp \
my-tcp-health-check --port 30061
gcloud compute backend-services create \
my-tcp-backend-service \
--global \
--protocol TCP \
--health-checks my-tcp-health-check \
--timeout 5m \
--port-name np30061
Add the instance groups created by GKE to this backend service. For both instance groups, run this command one by one by one for all the groups:
gcloud compute backend-services add-backend \
my-tcp-backend-service \
--global \
--instance-group instance-group-name \
--instance-group-zone zone-name \
--balancing-mode UTILIZATION \
--max-utilization 0.8
gcloud compute target-tcp-proxies create \
my-tcp-lb-target-proxy \
--backend-service my-tcp-backend-service \
--proxy-header NONE
gcloud compute addresses create tcp-lb-static-ipv4 \
--ip-version=IPV4 \
--global
Get the IPv4 address IP using the gcloud compute addresses list command.
gcloud beta compute forwarding-rules create \
tcp-lb-forwarding-rule \
--global \
--target-tcp-proxy my-tcp-lb-target-proxy \
--address xx.xxx.xxx.xx \
--ports 195
Select any of the ports supported by GCP’s TCP load balancer: 25, 43, 110, 143, 195, 443, 465, 587, 700, 993, 995, 1883, 5222. (I randomly selected port 195.)
gcloud compute instances list
NAME ZONE
gke-cluster-south-default-pool-67r asia-south1-a
gke-cluster-south-default-pool-53q asia-south1-a
gke-cluster-southeast-default-pool-86a asia-southeast1-a
gke-cluster-southeast-default-pool-22g asia-southeast1-a
# Now run the below command to see the tags
gcloud compute instances describe instance-name \
--zone zone
...output...
tags:
fingerprint: H7326hhI3qU=
items:
- "gke-cluster-south-12345b67-node"
Note: This command produces a large output; you will find the tag in the last four lines.
There will be two unique tags here – one per group. Use those tags to create the required firewall rule to open ports 195 and 30061:
gcloud compute firewall-rules create \
allow-tcplb-and-health \
--source-ranges 130.211.0.0/22,35.191.0.0/16 \
--target-tags tag-instance-group-1,tag-instance-group-2 \
--allow tcp:195,tcp:30061
That’s it! You’re all set. Just wait a few minutes to let the load balancer set up completely, then connect to the sftp server by running the following command:
sftp -P 195 user@xx.xxx.xxx.xx
You should successfully be able to log in to the sftp server. You can try deleting the server from one cluster using kubectl delete -f sftp.yaml.You’ll notice that if you login again, the load balancer will route traffic to another server.
What are the benefits of this setup?
You can add and delete instances in the GKE cluster without affecting the sftp server, because you use a tag and a daemonset.
In some cases, if GKE updates or recreates the VMs with new IPs, it won’t affect the setup since it doesn’t use the IPs of the nodes directly.
It’s really easy to scale up and down. In case you add a nodepool (one more group of VMs in the GKE), all you’ll need to do is:
Let’s work together to build your game-changing digital products
Want to build cool things?
Let’s work together to build your game-changing digital products
Want to build cool things?
© 2024 – Ignite Solutions India Private Limited