Service mesh emerged as a response to the growing popularity of cloud-native environments, microservices architecture, and Kubernetes. It has its roots in the three-tiered model of application architecture. While Kubernetes helped resolve deployment challenges, the communication between microservices remained a source of unreliability. Under a heavy load, the application could break if the traffic routing, load balancing, etc., were not optimized. This led to the growth of service mesh. With the existing service mesh hard to scale due to too many moving parts, configure and manage, Kong built a service mesh tool called Kuma.
In this blog post, we will discuss the open-source service mesh Kuma, its architecture, and its easy-to-implement policies like traffic control, metrics, circuit breaking, etc. We will also discuss how Kuma provides better observability of services.
What Is Kuma?
Kuma is an open-source service mesh for Kubernetes, VM, and bare metal environments. It offers horizontal scalability support and multi-zone, multi-cluster, and multi-cloud support. It is enterprise-ready and supports multiple individual meshes, as shown in the image below, that help lower the operating costs of keeping the entire organization.
For the services that need to receive traffic from the external network, Kuma Gateway routes those requests inside the mesh for the service to accept it via the proxy. To do that, Kuma sets up a pod dedicated to the gateway once configured. Kuma supports two types of gateway:
delegated: It allows the user to use any existing gateway like Kong.
builtin: It requires configuring the DPP to expose external listeners to drive traffic inside the mesh.
You can understand the comparison between delegated and built-in from the documentation.
We are going to create and configure the gateway with a built-in type that listens for the traffic from the outside of the mesh and forwards it to the sock-shop front-end. Here are the 3 things that we need to set up:
MeshGatewayInstance: Kuma comes with a built-in type, MesGatewayInstance that manages and deploys the proxy to serve gateway traffic. Here is the configuration:
In this configuration, we have defined to setup an instance of the specified kind with 1 replica and load balancer type. With the instance configured, we need to enable listeners for the gateway.
MeshGateway: This helps us configure the listeners. Here is the configuration:
Here we have defined the backend destination as the front-end service for the prefix match at /. Weight is the proportion of requests this backend will receive when a forwarding rule specifies multiple backends. We have set it to 1. Also, the listener is set to sock-shop_gateway to identify incoming requests.
We have kept all three above-defined configurations in the same file. Once this is applied, Kuma will launch a create and configure a built-in type gateway that will route the incoming requests on / to the front-end service.
Let us go ahead and apply the gateway configurations.
$ kubectl apply -f gateway.yaml
meshgateway.kuma.io/sock-shop created
meshgatewayroute.kuma.io/sock-shop created
meshgatewayinstance.kuma.io/sock-shop-gateway created
Verify if the pod is up:
$ kubectl get pods -A | grep gateway
sock-shop sock-shop-gateway-84f7fb5687-phsvl 1/1 Running 0 2m
As we can see, the pod is running. Let us get the IP of the gateway to send the external traffic to the service:
$ minikube service list | grep gateway
| sock-shop | sock-shop-gateway | 80/80 | http://192.168.49.2:30526 |
Finally, let’s verify in the browser:
The application is accessible via the gateway. This is how you can easily set up a gateway for your application using Kuma’s built-in gateway.
In the coming section, we will be discussing policies that can be enabled in Kuma. Kuma Gateway provides the policy support for some of the policies on the built-in gateway.
Policy Features of Kuma
Kuma provides policies that are combined with the data plane configuration to generate the proxy configuration.
Mutual TLS
The communication across services is not encrypted by default in the Kuma service mesh. Mutual TLS policy helps to encrypt traffic for all the services in a mesh and assign an identity to every data plane. Kuma supports both built-in and provided CA backends.
Before enabling, let us check if plain text traffic which is not encrypted is allowed by accessing the front-end service from the catalog service’s proxy servers using the following command.
kubectl exec $(kubectl get pod -l name=catalogue -n sock-shop -o jsonpath={.items..metadata.name}) -c kuma-sidecar -n sock-shop - wget - spider -S http://front-end/
Connecting to front-end (10.102.50.169:80)
HTTP/1.1 200 OK
X-Powered-By: Express
Accept-Ranges: bytes
Cache-Control: public, max-age=0
Last-Modified: Tue, 21 Mar 2017 11:31:47 GMT
ETag: W/"21f0–15af0a320b8"
Content-Type: text/html; charset=UTF-8
Content-Length: 8688
Date: Thu, 22 Jun 2023 11:59:52 GMT
Connection: close
remote file exists
When mTLS is enabled, all traffic is denied unless a TrafficPermission policy is configured to explicitly allow traffic across proxies with encryption. So we need to verify that the TrafficPermission policy is enabled. In the Kuma service mesh, this policy is enabled by default.
$ kumactl get traffic-permissions
MESH NAME AGE
default allow-all-default 2h
Use the following yaml to enable mTLS with a built-in backend.
Kuma assigns a certificate to each data plane proxy. We have set the value as 1 day for the data plane cert expiration so that the cert gets rotated every day.
Verify using the same command that we executed before enabling mTLS:
kubectl exec $(kubectl get pod -l name=catalogue -n sock-shop -o jsonpath={.items..metadata.name}) -c kuma-sidecar -n sock-shop - wget - spider -S http://front-end/
Connecting to front-end (10.102.50.169:80)
wget: error getting response: Resource temporarily unavailable
command terminated with exit code 1
This is how with Kuma you can implement zero trust security in an automated way for all data plane proxies and secure all your services within the mesh.
Rate Limiting
By default, there is no limit on the inbound traffic. Using this policy, a limit can be imposed on the service on how many requests are allowed in a specified time and the response when the threshold is reached.
From Kuma’s doc, All HTTP/HTTP2 based requests are supported. So we need to ensure that the app supports HTTP-based requests. You can set appProtocol as HTTP for the application deployment to allow HTTP requests. You can verify it from Kuma’s dashboard.