# DPs and Data Model
When Kuma (
kuma-cp) runs, it will be waiting for the data-planes to connect and register themselves. In order for a data-plane to successfully run, two things have to happen before being executed:
- There must exist at least one
Meshin Kuma. By default the system auto-generates a
defaultMesh when the control-plane is run for the first time.
- There must exist a
Dataplaneentity in Kuma before the actual data-plane tries to connect to it via
On Universal the
Dataplane entity must be manually created before starting
kuma-dp, on Kubernetes it is automatically created.
# Dataplane Entity
Dataplane entity must be created on the CP
kuma-cp before a
kuma-dp instance attempts to connect to the control-plane. On Kubernetes, this operation is fully automated. On Universal, it must be executed manually.
To understand why the
Dataplane entity is required, we must take a step back. As we have explained already, Kuma follow a sidecar proxy model for the data-planes, where we have an instance of a data-plane for every instance of our services. Each Service and DP will communicate with each other on the same machine, therefore on
For example, if we have 6 replicas of a "Redis" service, then we must have one instances of
kuma-dp running alongside each replica of the service, therefore 6 replicas of
kuma-dp as well.
Many DPs! The number of data-planes that we have running can quickly add up, since we have one replica of
kuma-dp for every replica of every service. That's why it's important for the DP process to be lightweight and consume a few resources, otherwise we would quickly run out of memory, especially on platforms like Kubernetes where multiple services are running on the same underlying host machine. And that's one of the reasons why Kuma leverages Envoy for this task.
When we start a new data-plane in Kuma, two things have to happen:
- The data-plane needs to advertise what service it is responsible for. This is what the
- The data-plane process needs to start accepting incoming and outgoing requests.
These steps are being executed in two separate commands:
- We register the
Dataplaneobject via the
kumactlor HTTP API.
- Once we have registered the DP, we can start it by running
Remember: this is all automated if you are running Kuma on Kubernetes!
The registration of the
Dataplane includes two main sections that are described below in the Dataplane Specification:
inboundnetworking configuration, to configure on what port the DP will listen to accept external requests, specify on what port the service is listening on the same machine (for internal DP <> Service communication), and the Tags that belong to the service.
outboundnetworking configuration, to enable the local service to consume other services.
For example, this is how we register a
Dataplane for an hypotetical Redis service and then start the
echo "type: Dataplane mesh: default name: redis-1 networking: inbound: - interface: 127.0.0.1:9000:6379 tags: service: redis" | kumactl apply -f - KUMA_CONTROL_PLANE_BOOTSTRAP_SERVER_URL=http://control-plane:5682 \ KUMA_DATAPLANE_MESH=default \ KUMA_DATAPLANE_NAME=redis-1 \ kuma-dp run
In the example above, any external client who wants to consume Redis will have to make a request to the DP on port
9000, which internally will be redirected to the Redis service listening on port
Now let's assume that we have another service called "Backend" that internally listens on port
80, and that makes outgoing requests to the
echo "type: Dataplane mesh: default name: backend-1 networking: inbound: - interface: 127.0.0.1:8000:80 tags: service: backend outbound: - interface: :10000 service: redis" | kumactl apply -f - KUMA_CONTROL_PLANE_BOOTSTRAP_SERVER_URL=http://control-plane:5682 \ KUMA_DATAPLANE_MESH=default \ KUMA_DATAPLANE_NAME=redis-1 \ kuma-dp run
In order for the
backend service to successfully consume
redis, we specify an
outbound networking section in the
Dataplane configuration instructing the DP to listen on a new port
10000 and to proxy any outgoing request on port
10000 to the
redis service. For this to work, we must update our application to consume
As mentioned before, this is only required in Universal. In Kubernetes no change to our applications are required thanks to automated transparent proxying.
kuma-dp is built on top of Envoy, you can enable the Envoy HTTP API by starting
kuma-dp with an additional
KUMA_DATAPLANE_ADMIN_PORT=9901 environment variable (or by setting the
--admin-port=9901 argument). This can be very useful for debugging purposes.
A data-plane can have many labels that define its role within your architecture. It is obviously associated to a service, but can also have some other properties that we might want to define. For example, if it runs in a specific world region, or a specific cloud vendor. In Kuma these labels are called
tags and they are being set in the
There is one special tag, the
service tag, that must always be set.
Tags are important because can be used later on by any Policy that Kuma supports now and in the future. For example, it will be possible to route requests from one region to another assuming there is a
region tag associated to the data-planes.
# Dataplane Specification
Dataplane entity includes the networking and naming configuration that a data-plane proxy (
kuma-dp) must have attempting to connect to the control-plane (
In Universal mode we must manually create the
Dataplane entity before running
Dataplane entity can be created with
kumactl or by using the HTTP API. When using
kumactl, the entity definition will look like:
type: Dataplane mesh: default name: web-01 networking: inbound: - interface: 127.0.0.1:11011:11012 tags: service: backend outbound: - interface: :33033 service: redis
Dataplane entity includes a few sections:
type: must be
Meshname we want to associate the data-plane with.
name: this is the name of the data-plane instance, and it must be unique for any given
Mesh. We might have multiple instances of a Service, and therefore multiple instances of the sidecar data-plane proxy. Each one of those sidecar proxy instances must have a unique
networking: this is the meaty part of the configuration. It determines the behavior of the data-plane on incoming (
inbound) and outgoing (
inbound: an array of
interfaceobjects that determines what services are being exposed via the data-plane. Each
interfaceobject only supports one port at a time, and you can specify more than one
interfacein case the service opens up more than one port.
interface: determines the routing logic for incoming requests in the format of
tags: each data-plane can include any arbitrary number of tags, with the only requirement that
serviceis mandatory and it identifies the name of service. You can include tags like
region, and so on to give more attributes to the
Dataplane(attributes that can later on be used to apply policies).
outbound: every outgoing request made by the service must also go thorugh the DP. This object specifies ports that the DP will have to listen to when accepting outgoing requests by the service:
interface: the address inclusive of the port that the service needs to consume locally to make a request to the external service
service: the name of the service associated with the interface.
On Kubernetes this whole process is automated via transparent proxying and without changing your application's code. On Universal Kuma doesn't support transparent proxying yet, and the outbound service dependencies have to be manually specified in the
Dataplane entity. This also means that in Universal you must update your codebases to consume those external services on
127.0.0.1 on the port specified in the
On Kubernetes the data-planes are automatically injected via the
kuma-injector executable as long as the K8s Namespace includes the following label:
On Kubernetes the
Dataplane entity is also automatically created for you, and because transparent proxying is being used to communicate between the service and the sidecar proxy, no code changes are required in your applications.