Services

Open source

EN

MULTICLUSTER WITH LINKERD – PART 4 AND 5 (bonus)

Practical guide: Configuring Kubernetes pods to test applications across different clusters. Learn how!

SRE/Kubernetes Admin

Adonai Costa

Let's install podinfo, a test application to see things working.

A very important detail here.

- since we are using kind, the cluster DNS service is `kube-dns.kube-system.svc.cluster.local`; if you are using K8s Managed by a cloud or kubespray, check the service name and edit the `configMap` in `multicluster/base/frontend.yml`

- make sure if you change the name of the clusters, it is also necessary to change the name of the folders in `multicluster/kind-demo`

If needed, fork or clone and change the names and content, but study the repository, see what it does, and be curious.


for ctx in kind-demo kind-demo3; do

echo "Adding test services on cluster: ${ctx} ........."

kubectl --context=${ctx} create ns test

kubectl --context=${ctx} apply \

-n test -k "github.com/adonaicosta/linkerd-multicluster/multicluster/${ctx}/"

kubectl --context=${ctx} -n test \

rollout status deploy/podinfo || break

echo "-------------"

done


Check if the pods are up and running:


for ctx in kind-demo kind-demo3; do

echo "Check pods on cluster: ${ctx} ........."

kubectl get pod -n test --context=${ctx}

done


Let's access the application and validate if the frontend can hit both pods, still separately for each cluster, we are not in multicluster yet, okay!


kubectl port-forward -n test svc/frontend 8080:8080 --context=kind-demo


Open your browser http://localhost:8080 

See?!



Now do the same for the other cluster

kubectl port-forward -n test svc/frontend 8080:8080 --context=kind-demo3

Open your browser http://localhost:8080

See?!



The time has come to see the crosscluster function work

In order for the frontend pods in each cluster to access the podinfo in the other cluster, it is necessary to mirror the podinfo service between the clusters.  

The frontend application already makes calls to each cluster, as it was pre-configured.  

So let's label the podinfo service in each cluster and then create a trafficsplit for each one.

Labeling...

for ctx in kind-demo kind-demo3; do

echo -en "\n\nLabel svc podinfo on cluster: ${ctx} .........\n"

kubectl label svc -n test podinfo mirror.linkerd.io/exported=true --context=${ctx}

sleep 4

echo "Check services transConnected (if word exists )....on cluster ${ctx}"

kubectl get svc -n test --context=${ctx}

done




Now, in each cluster, there will be a podinfo-(CONTEXT) service that points to the other cluster at the IP of the service linkerd-multicluster/linkerd-gateway.


kubectl get svc --context=kind-demo -n linkerd-multicluster linkerd-gateway -o \

jsonpath='{.status.loadBalancer.ingress[0].ip}'

172.17.0.61

kubectl get endpoints --context=kind-demo3 -n test podinfo-kind-demo -o \

jsonpath='{.subsets[*].addresses[*].ip}'

172.17.0.61

They are the same, right? This means that the endpoint of the service test/podinfo-kind-demo3 points to the LoadBalancer service of linkerd-multicluster/linkerd-gateway of the kind-demo cluster.

Do the same for the other cluster:

kubectl get svc --context=kind-demo3 -n linkerd-multicluster linkerd-gateway -o \

jsonpath='{.status.loadBalancer.ingress[0].ip}'

172.17.0.71

kubectl get endpoints --context=kind-demo -n test podinfo-kind-demo3 -o \

jsonpath='{.subsets[*].addresses[*].ip}'

172.17.0.71


Distributing the load between clusters

Creating the trafficsplit…

kubectl --context=kind-demo apply -f - <<EOF

apiVersion: split.smi-spec.io/v1alpha1

kind: TrafficSplit

metadata:

name: podinfo

namespace: test

spec:

service: podinfo

backends:

- service: podinfo

weight: 50

- service: podinfo-kind-demo3

weight: 50

EOF

kubectl --context=kind-demo3 apply -f - <<EOF

apiVersion: split.smi-spec.io/v1alpha1

kind: TrafficSplit

metadata:

name: podinfo

namespace: test

spec:

service: podinfo

backends:

- service: podinfo

weight: 50

- service: podinfo-kind-demo

weight: 50

EOF

We split the podinfo load 50/50 for each cluster, for each one, so we have `cross access` between them.  


Port-forward again (if you canceled previously) to a frontend and follow along.

kubectl port-forward -n test --context=kind-demo svc/frontend 8080

Open your browser again http://localhost:8080

Voila…

If you port-forward to the same frontend service of the other cluster, the result will be the same.


Part 5 — BONUS

Installing ingress controller, creating an ingress, and simulating real life as it is

Here we can and will go beyond Kubernetes clusters. With an ingress in each cluster, we can; at a DNS layer, for example; distribute requests between clusters that will be balancing those same requests among themselves.

Broadly speaking, this means you can balance requests externally via DNS between services that will be cross-accessed, ensuring high availability. Let's look at a diagram to explain it better:

So now let's get to practice and demonstration.

Install ingress-nginx on each of the clusters.


helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx

helm repo update

for ctx in kind-demo kind-demo3; do

echo "Installing ingress-nginx - ${ctx}"

helm install ingress-nginx -n ingress-nginx --create-namespace ingress-nginx/ingress-nginx --set controller.podAnnotations.linkerd.io/inject=enabled --kube-context=${ctx}

echo "Wait for the ingress-nginx installation to finish, 30s, I guess"

kubectl rollout status deploy -n ingress-nginx ingress-nginx-controller --context=${ctx}

echo "Creating an ingress for the podinfo - ${ctx}"

kubectl --context=${ctx} -n test create ingress frontend --class nginx --rule="frontend-${ctx}.domain.com/*=frontend:8080" -–annotation=”nginx.ingress.kubernetes.io/service-upstream=true”

done


Get the fqdn of your pod info application in each cluster and add it to your /etc/hosts:


for ctx in kind-demo kind-demo3; do

echo "Add the hostname and IP to your /etc/hosts and wait for ingress-nginx to assign an IP to the ingress, about 30s"

kubectl --context=${ctx} get ingress -n test

done

> Don't forget to put the created host IP in your /etc/hosts file as shown above.



Conclusion

We saw here that a secure, easy, and unplugged multicluster with mesh doesn't have much of a secret. Just many steps to stay mindful of:

  • Check if linkerd on the clusters has the same TLS key, created with openssl

  • Install linkerd-multicluster to establish connectivity between them

  • Install linkerd-smi to create traffic distribution

  • Create trafficsplit objects to distribute this access

  • Remember, each cluster in the example has a URL; it's time to put your DNS to work not only with round-robin, but with health-checks and failover.

  • Linkerd also has an extension for multicluster failover, which will further increase application availability among clusters, which is the ultimate goal. 


References


**Getup:** https://blog.getup.io

**ServiceMesh:** https://smi-spec.io/

**A Really Service Mesh:** https://linkerd.io 😙


Newsletter Getup.

Atualizações sobre Kubernetes e Software Supply Chain Security todos os meses.

Operating Kubernetes in production for more than 13 years. With Quor, this experience extends to software supply chain security as well.