Deploy Kuma on Docker
This quick start guide demonstrates how to run Kuma in Universal mode using Docker containers.
You’ll set up and secure a simple demo application to explore how Kuma works. The application consists of two services:
demo-app
: A web application that lets you increment a numeric counter.redis
: A data store that keeps the counter’s value.
--- title: service graph of the demo app --- flowchart LR demo-app(demo-app :5000) redis(redis :6379) demo-app --> redis
Prerequisites
-
Make sure the following tools are installed and ready to use:
docker
curl
jq
base64
Note: This guide has been tested with Docker Engine, Docker Desktop, OrbStack, and Colima. For Colima, a small adjustment is required (explained later).
-
If you previously followed the Deploy Kuma on Universal quickstart on the same machine, we recommend cleaning up your environment to ensure no control plane, Redis, demo-app, or their data plane proxies are still running.
This isn’t mandatory, but it’s easy to accidentally mix up ports when typing commands manually, leading to unexpected results. If you copy the commands from this guide exactly or know what you’re doing and want to compare results between guides, you can skip this step.
Prepare the environment
-
Install Kuma
You can download and install Kuma using the official installer. The installer automatically detects your operating system (Amazon Linux, CentOS, RedHat, Debian, Ubuntu, macOS) and downloads the appropriate binaries:
curl --location https://kuma.io/installer.sh | VERSION="2.9.1" sh -
To finalize the installation add the Kuma binaries to your system’s PATH so the commands are easily accessible:
export PATH="$(pwd)/kuma-2.9.1/bin:$PATH"
-
Prepare a temporary directory
Set up a temporary directory to store resources like data plane tokens, Dataplane templates, and logs. Export its path to the
KUMA_DEMO_TMP
environment variable for use in later steps. Ensure the path does not end with a trailing/
.Important: If you are using Colima, you need to adjust the path. Colima only allows sharing paths from the
HOME
directory or/tmp/colima/
. Instead of/tmp/kuma-demo
, you can use/tmp/colima/kuma-demo
.export KUMA_DEMO_TMP="/tmp/kuma-demo"
Check if the directory exists and is empty, and create it if necessary:
mkdir -p "$KUMA_DEMO_TMP"
-
Prepare a Dataplane resource template
Create a reusable Dataplane resource template for services:
echo 'type: Dataplane mesh: default name: {{ name }} networking: address: {{ address }} inbound: - port: {{ port }} tags: kuma.io/service: {{ name }} kuma.io/protocol: {{ protocol }} transparentProxying: redirectPortInbound: 15006 redirectPortOutbound: 15001' > $KUMA_DEMO_TMP/dataplane.yaml
This template simplifies creating Dataplane configurations for different services by replacing dynamic values during deployment.
-
Prepare a transparent proxy configuration file
echo 'kumaDPUser: kuma-data-plane-proxy redirect: dns: enabled: true verbose: true' > $KUMA_DEMO_TMP/config-transparent-proxy.yaml
-
Create a Docker network
Set up a separate Docker network for the containers. Use IP addresses in the
172.56.78.0/24
range or customize as needed:docker network create \ --subnet 172.56.0.0/16 \ --ip-range 172.56.78.0/24 \ --gateway 172.56.78.254 \ kuma-demo
Set up the control plane
-
Start the control plane
Run the Kuma control plane in a Docker container:
docker run \ --detach \ --name kuma-demo-control-plane \ --hostname control-plane \ --network kuma-demo \ --ip 172.56.78.1 \ --publish 25681:5681 \ --volume $KUMA_DEMO_TMP:/demo \ kumahq/kuma-cp:2.9.1 run
You can now access the Kuma user interface (GUI) at http://localhost:25681/gui
-
Configure kumactl
To use kumactl with our Kuma deployment, we need to connect it to the control plane we set up earlier.
-
Retrieve the admin token
Run the following command to get the admin token from the control plane:
export KUMA_DEMO_ADMIN_TOKEN="$( docker exec --tty --interactive kuma-demo-control-plane \ wget --quiet --output-document - \ http://localhost:5681/global-secrets/admin-user-token \ | jq --raw-output .data \ | base64 --decode )"
-
Connect to the control plane
Use the retrieved token to link kumactl to the control plane:
kumactl config control-planes add \ --name kuma-demo \ --address http://localhost:25681 \ --auth-type tokens \ --auth-conf "token=$KUMA_DEMO_ADMIN_TOKEN" \ --skip-verify
-
Verify the connection
Run this command to check if the connection is working:
kumactl get meshes
You should see a list of meshes with one entry:
default
. This confirms the configuration is successful.
-
-
Configure the default mesh
Set the default mesh to use MeshServices in exclusive mode. MeshServices are explicit resources that represent destinations for traffic in the mesh. They define which Dataplanes serve the traffic, as well as the available ports, IPs, and hostnames. This configuration ensures a clearer and more precise way to manage services and traffic routing in the mesh.
echo 'type: Mesh name: default meshServices: mode: Exclusive' | kumactl apply --file -
Set up services
Redis
-
Generate a data plane token
Generate a token that the Redis data plane proxy will use to authenticate with the control plane.
kumactl generate dataplane-token \ --tag "kuma.io/service=redis" \ --valid-for 720h \ > $KUMA_DEMO_TMP/token-redis
-
Start the Redis container
docker run \ --detach \ --name kuma-demo-redis \ --hostname redis \ --network kuma-demo \ --ip 172.56.78.2 \ --volume $KUMA_DEMO_TMP:/demo \ redis:7.4.1 redis-server --protected-mode no
-
Prepare the Redis container
Enter the container to run further commands.
docker exec --tty --interactive --privileged kuma-demo-redis bash
Important: The following steps must be executed inside the container.
-
Set a zone name
Give the Redis instance a zone name. The demo application will use this name to show which Redis instance is being accessed.
redis-cli set zone local-demo-zone
-
Install required tools
Install the necessary tools for downloading Kuma binaries and setting up the transparent proxy:
curl
: Needed to download the Kuma binaries.iptables
: Required to configure the transparent proxy.
Run the following command:
apt-get update && \ apt-get install --yes curl iptables
-
Install Kuma
Now, install Kuma and move its binaries to
/usr/local/bin/
so they are accessible to all users:curl --location https://kuma.io/installer.sh | VERSION="2.9.1" sh - mv kuma-2.9.1/bin/* /usr/local/bin/
-
Create a separate user for the data plane proxy
useradd --uid 5678 --user-group kuma-data-plane-proxy
-
Start the data plane proxy
runuser --user kuma-data-plane-proxy -- \ /usr/local/bin/kuma-dp run \ --cp-address https://control-plane:5678 \ --dataplane-token-file /demo/token-redis \ --dataplane-file /demo/dataplane.yaml \ --dataplane-var "name=redis" \ --dataplane-var "address=172.56.78.2" \ --dataplane-var "port=6379" \ --dataplane-var "protocol=tcp" \ > /demo/logs-data-plane-proxy-redis.log 2>&1 &
-
Install the transparent proxy
Important: Make sure this command is executed inside the container. It changes iptables rules to redirect all traffic to the data plane proxy. Running it on your computer or a virtual machine without the data plane proxy can disrupt network connectivity. On a virtual machine, this might lock you out until you restart it.
kumactl install transparent-proxy \ --config-file /demo/config-transparent-proxy.yaml \ > /demo/logs-transparent-proxy-install-redis.log 2>&1
-
Exit the container
Redis is now set up and running. You can safely exit the container as the configuration is complete:
exit
-
-
Check if service is running
To confirm the service is set up correctly and running, use the kumactl to inspect the services:
kumactl inspect services
The output should show a single service,
redis
, with the statusOnline
.You can also open the Kuma GUI at http://localhost:25681/gui/meshes/default/services/mesh-services. Look for the
redis
service, and verify that its state isAvailable
.
Demo Application
The steps are the same as those explained earlier, with only the names changed. We won’t repeat the explanations here, but you can refer to the Redis service instructions if needed.
-
Generate a data plane token
kumactl generate dataplane-token \ --tag "kuma.io/service=demo-app" \ --valid-for 720h \ > $KUMA_DEMO_TMP/token-demo-app
-
Start the application container
docker run \ --detach \ --name kuma-demo-app \ --hostname demo-app \ --network kuma-demo \ --ip 172.56.78.3 \ --publish 25000:5000 \ --volume $KUMA_DEMO_TMP:/demo \ --env "REDIS_HOST=redis.svc.mesh.local" \ kumahq/kuma-demo
-
Prepare the application container
Enter the container to run further commands.
docker exec \ --tty \ --interactive \ --privileged \ --workdir /root \ kuma-demo-app bash
Important: The following steps must be executed inside the container.
-
Install required tools
apt-get update && \ apt-get install --yes curl iptables
-
Install Kuma
curl --location https://kuma.io/installer.sh | VERSION="2.9.1" sh - mv kuma-2.9.1/bin/* /usr/local/bin/
-
Create a separate user for the data plane proxy
useradd --uid 5678 --user-group kuma-data-plane-proxy
-
Start the data plane proxy
runuser --user kuma-data-plane-proxy -- \ /usr/local/bin/kuma-dp run \ --cp-address https://control-plane:5678 \ --dataplane-token-file /demo/token-demo-app \ --dataplane-file /demo/dataplane.yaml \ --dataplane-var "name=demo-app" \ --dataplane-var "address=172.56.78.3" \ --dataplane-var "port=5000" \ --dataplane-var "protocol=http" \ > /demo/logs-data-plane-proxy-demo-app.log 2>&1 &
-
Install the transparent proxy
Important: Make sure this command is executed inside the container. It changes iptables rules to redirect all traffic to the data plane proxy. Running it on your computer or a virtual machine without the data plane proxy can disrupt network connectivity. On a virtual machine, this might lock you out until you restart it.
kumactl install transparent-proxy \ --config-file /demo/config-transparent-proxy.yaml \ > /demo/logs-transparent-proxy-install-demo-app.log 2>&1
-
Exit the container
Demo application is now set up and running. You can safely exit the container as the configuration is complete:
exit
-
-
Verify the application
Open http://localhost:25000 in your browser and use the demo application to increment the counter. The demo application is now fully set up and running.
Introduction to zero-trust security
By default, the network is insecure and unencrypted. With Kuma, you can enable the Mutual TLS (mTLS) policy to secure the network. This works by setting up a Certificate Authority (CA) that automatically provides TLS certificates to your services (specifically to the data plane proxies running next to each service).
To enable Mutual TLS using a builtin
CA backend, run the following command:
echo 'type: Mesh
name: default
meshServices:
mode: Exclusive
mtls:
enabledBackend: ca-1
backends:
- name: ca-1
type: builtin' | kumactl apply --file -
After enabling mTLS, all traffic is encrypted and secure. However, you can no longer access the demo-app
directly, meaning http://localhost:25000 will no longer work. This happens for two reasons:
-
When mTLS is enabled, Kuma doesn’t create traffic permissions by default. This means no traffic will flow until you define a MeshTrafficPermission policy to allow
demo-app
to communicate withredis
. -
When you try to call
demo-app
using a browser or other HTTP client, you are essentially acting as an external client without a valid TLS certificate. Since all services are now required to present a certificate signed by theca-1
Certificate Authority, the connection is rejected. Only services within thedefault
mesh, which are assigned valid certificates, can communicate with each other.
To address the first issue, you need to apply an appropriate MeshTrafficPermission policy:
echo 'type: MeshTrafficPermission
name: allow-redis-from-demo-app
mesh: default
spec:
targetRef:
kind: MeshSubset
tags:
kuma.io/service: redis
from:
- targetRef:
kind: MeshSubset
tags:
kuma.io/service: demo-app
default:
action: Allow' | kumactl apply --file -
The second issue is a bit more challenging. You can’t just get the necessary certificate and set up your web browser to act as part of the mesh. To handle traffic from outside the mesh, you need a gateway proxy. You can use tools like Kong, or you can use the Built-in Gateway that Kuma provides.
Note: For more information, see the Managing incoming traffic with gateways section in the documentation.
In this guide, we’ll use the built-in gateway. It allows you to configure a data plane proxy to act as a gateway and manage external traffic securely.
Setting up the built-in gateway
The built-in gateway works like the data plane proxy for a regular service, but it requires its own configuration. Here’s how to set it up step by step.
-
Create a Dataplane resource
For regular services, we reused a single Dataplane configuration file and provided dynamic values (like names and addresses) when starting the data plane proxy. This made it easier to scale or deploy multiple instances. However, since we’re deploying only one instance of the gateway, we can simplify things by hardcoding all the values directly into the file, as shown below:
echo 'type: Dataplane mesh: default name: gateway-instance-1 networking: address: 172.56.78.4 gateway: type: BUILTIN tags: kuma.io/service: gateway' > $KUMA_DEMO_TMP/dataplane-gateway.yaml
If you prefer to keep the flexibility of dynamic values, you can use the same template mechanisms for the gateway’s Dataplane configuration as you did for regular services.
-
Generate a data plane token
The gateway proxy requires a data plane token to securely register with the control plane. You can generate the token using the following command:
kumactl generate dataplane-token \ --tag "kuma.io/service=gateway" \ --valid-for 720h \ > $KUMA_DEMO_TMP/token-gateway
-
Start the gateway container
With the configuration and token in place, you can start the gateway proxy as a container:
docker run \ --detach \ --name kuma-demo-gateway \ --hostname gateway \ --network kuma-demo \ --ip 172.56.78.4 \ --publish 25001:5000 \ --volume $KUMA_DEMO_TMP:/demo \ kumahq/kuma-dp:2.9.1 run \ --cp-address https://control-plane:5678 \ --dataplane-token-file /demo/token-gateway \ --dataplane-file /demo/dataplane-gateway.yaml \ --dns-enabled="false"
This command starts the gateway proxy and registers it with the control plane. However, the gateway is not yet ready to route traffic.
-
Configure the gateway with MeshGateway
To enable the gateway to accept external traffic, configure it with a MeshGateway. This setup defines listeners that specify the port, protocol, and tags for incoming traffic, allowing policies like MeshHTTPRoute or MeshTCPRoute to route traffic to services.
Apply the configuration:
echo 'type: MeshGateway mesh: default name: gateway selectors: - match: kuma.io/service: gateway conf: listeners: - port: 5000 protocol: HTTP tags: port: http-5000' | kumactl apply --file -
This sets up the gateway to listen on port
5000
using the HTTP protocol and adds a tag (port: http-5000
) to identify this listener in routing policies.You can test the gateway by visiting http://localhost:25001. You should see a message saying no routes match this MeshGateway. This means the gateway is running, but no routes are set up yet to handle traffic.
-
Create a route to connect the gateway to
demo-app
To route traffic from the gateway to the service, create a MeshHTTPRoute policy:
echo 'type: MeshHTTPRoute name: gateway-demo-app-route mesh: default spec: targetRef: kind: MeshGateway name: gateway tags: port: http-5000 to: - targetRef: kind: Mesh rules: - matches: - path: type: PathPrefix value: "/" default: backendRefs: - kind: MeshService name: demo-app' | kumactl apply --file -
This route connects the gateway and its listener (
port: http-5000
) to thedemo-app
service. It forwards any requests with the path prefix/
todemo-app
.After setting up this route, the gateway will try to send traffic to
demo-app
. However, if you test it by visiting http://localhost:25001, you’ll see:RBAC: access denied
This happens because there is no MeshTrafficPermission policy allowing traffic from the gateway to
demo-app
. You’ll need to create one in the next step. -
Allow traffic from the gateway to
demo-app
To fix the
RBAC: access denied
error, create a MeshTrafficPermission policy to allow the gateway to send traffic todemo-app
:echo 'type: MeshTrafficPermission name: allow-demo-app-from-gateway mesh: default spec: targetRef: kind: MeshSubset tags: kuma.io/service: demo-app from: - targetRef: kind: MeshSubset tags: kuma.io/service: gateway default: action: Allow' | kumactl apply --file -
This policy allows traffic from the gateway to
demo-app
. After applying it, you can access http://localhost:25001, and the traffic will reach thedemo-app
service successfully.
Cleanup
To clean up your environment, remove the Docker containers, network, temporary directory, and the control plane configuration from kumactl. Run the following commands:
kumactl config control-planes remove --name kuma-demo
docker rm --force \
kuma-demo-control-plane \
kuma-demo-redis \
kuma-demo-app \
kuma-demo-gateway
docker network rm kuma-demo
rm -rf "$KUMA_DEMO_TMP"