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.
  • kv: A data store that keeps the counter’s value.
 
flowchart LR
browser(browser)

subgraph mesh
edge-gateway(edge-gateway)
demo-app(demo-app :5050)
kv(kv :5050)
end
edge-gateway --> demo-app
demo-app --> kv
browser --> edge-gateway
  

Prerequisites

  1. 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).

  2. 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, application services, 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

  1. 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"
    
  2. Prepare a temporary directory

    Set up a temporary directory to store resources like data plane tokens, Dataplane templates, and logs. Ensure the path does not end with a trailing /.

    Important: If you are using Colima, make sure to adjust the path in the steps of this guide. Colima only allows shared paths from the HOME directory or /tmp/colima/. Instead of /tmp/kuma-demo, you can use /tmp/colima/kuma-demo.

    Check if the directory exists and is empty, and create it if necessary:

    mkdir -p /tmp/kuma-demo
    
  3. 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: http
      transparentProxying:
        redirectPortInbound: 15006
        redirectPortOutbound: 15001' > /tmp/kuma-demo/dataplane.yaml 
    

    This template simplifies creating Dataplane configurations for different services by replacing dynamic values during deployment.

  4. Prepare a transparent proxy configuration file

    echo 'kumaDPUser: kuma-data-plane-proxy
    redirect:
      dns:
        enabled: true
    verbose: true' > /tmp/kuma-demo/config-transparent-proxy.yaml
    
  5. 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

  1. Start the control plane

    Use the official Docker image to run the Kuma control plane. This image starts the control plane binary automatically, so no extra flags or configurations are needed for this guide. Simply use the run command:

    docker run \
      --detach \
      --name kuma-demo-control-plane \
      --hostname control-plane \
      --network kuma-demo \
      --ip 172.56.78.1 \
      --publish 25681:5681 \
      --volume /tmp/kuma-demo:/demo \
      kumahq/kuma-cp:2.9.1 run
    

    You can now access the Kuma user interface (GUI) at http://127.0.0.1:25681/gui.

  2. Configure kumactl

    To use kumactl with our Kuma deployment, we need to connect it to the control plane we set up earlier.

    1. 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://127.0.0.1:5681/global-secrets/admin-user-token \
          | jq --raw-output .data \
          | base64 --decode
      )"
      
    2. 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://127.0.0.1:25681 \
        --auth-type tokens \
        --auth-conf "token=$KUMA_DEMO_ADMIN_TOKEN" \
        --skip-verify
      
    3. 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.

  3. 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

Key/Value Store

This section explains how to start the kv service, which mimics key/value store database.

  1. Generate a data plane token

    Create a token for the kv data plane proxy to authenticate with the control plane:

    kumactl generate dataplane-token \
      --tag kuma.io/service=kv \
      --valid-for 720h \
      > /tmp/kuma-demo/token-kv
    
  2. Start the container

    docker run \
      --detach \
      --name kuma-demo-kv \
      --hostname kv \
      --network kuma-demo \
      --ip 172.56.78.2 \
      --volume /tmp/kuma-demo:/demo \
      ghcr.io/kumahq/kuma-counter-demo:debian-slim
    
  3. Prepare the container

    Enter the container to run further commands.

    docker exec --tty --interactive --privileged kuma-demo-kv bash
    

    Important: The following steps must be executed inside the container.

    1. Install tools and create data plane proxy user

      Install the required tools for downloading Kuma binaries, setting up the transparent proxy, and create a dedicated user for the data plane proxy:

      • curl: Needed to download the Kuma binaries.
      • iptables: Required to configure the transparent proxy.

      Run the following commands:

      # install necessary packages
      apt-get update && \
        apt-get install --yes curl iptables
            
      # download and install Kuma
      curl --location https://kuma.io/installer.sh | VERSION="2.9.1" sh -
            
      # move Kuma binaries to /usr/local/bin/ for global availability
      mv kuma-2.9.1/bin/* /usr/local/bin/
            
      # create a dedicated user for the data plane proxy
      useradd --uid 5678 --user-group kuma-data-plane-proxy
      
    2. Set the zone name

      Give the kv instance a name. The demo application will use this name to show which kv instance is being accessed.

      curl localhost:5050/api/key-value/zone \
        --header 'Content-Type: application/json' \
        --data '{"value":"local-demo-zone"}'
      
    3. 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-kv \
        --dataplane-file /demo/dataplane.yaml \
        --dataplane-var name=kv \
        --dataplane-var address=172.56.78.2 \
        --dataplane-var port=5050 \
        > /demo/logs-data-plane-proxy-kv.log 2>&1 &
      
    4. 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-kv.log 2>&1
      
    5. Exit the container

      Key/Value Store is now set up and running. You can safely exit the container as the configuration is complete:

      exit
      
  4. 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, kv, with the status Online.

    You can also open the Kuma GUI at http://127.0.0.1:25681/gui/meshes/default/services/mesh-services. Look for the kv service, and verify that its state is Available.

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 Key/Value Store service instructions if needed.

  1. Generate a data plane token

    kumactl generate dataplane-token \
      --tag kuma.io/service=demo-app \
      --valid-for 720h \
      > /tmp/kuma-demo/token-demo-app
    
  2. Start the application container

    docker run \
      --detach \
      --name kuma-demo-app \
      --hostname demo-app \
      --network kuma-demo \
      --ip 172.56.78.3 \
      --publish 25050:5050 \
      --volume /tmp/kuma-demo:/demo \
      --env KV_URL=http://kv.svc.mesh.local:5050 \
      --env APP_VERSION=v1 \
       ghcr.io/kumahq/kuma-counter-demo:debian-slim
    
  3. Prepare the application container

    Enter the container to run further commands.

    docker exec --tty --interactive --privileged kuma-demo-app bash
    

    Important: The following steps must be executed inside the container.

    1. Install tools and create data plane proxy user

      # install necessary packages
      apt-get update && \
        apt-get install --yes curl iptables
            
      # download and install Kuma
      curl --location https://kuma.io/installer.sh | VERSION="2.9.1" sh -
            
      # move Kuma binaries to /usr/local/bin/ for global availability
      mv kuma-2.9.1/bin/* /usr/local/bin/
            
      # create a dedicated user for the data plane proxy
      useradd --uid 5678 --user-group kuma-data-plane-proxy
      
    2. 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=5050 \
        > /demo/logs-data-plane-proxy-demo-app.log 2>&1 &     
      
    3. 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
      
    4. Exit the container

      Demo application is now set up and running. You can safely exit the container as the configuration is complete:

      exit
      
  4. Verify the application

    Open http://127.0.0.1:25050 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://127.0.0.1:25050 will no longer work. This happens for two reasons:

  1. 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 with kv.

  2. 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 the ca-1 Certificate Authority, the connection is rejected. Only services within the default 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-kv-from-demo-app
mesh: default 
spec: 
  targetRef: 
    kind: MeshSubset
    tags:
      kuma.io/service: kv
  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.

  1. 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: edge-gateway-instance-1
    networking:
      gateway:
        type: BUILTIN
        tags:
          kuma.io/service: edge-gateway
      address: 172.56.78.4' > /tmp/kuma-demo/dataplane-edge-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.

  2. 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=edge-gateway \
      --valid-for 720h \
      > /tmp/kuma-demo/token-edge-gateway
    
  3. 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-edge-gateway \
      --hostname gateway \
      --network kuma-demo \
      --ip 172.56.78.4 \
      --publish 28080:8080 \
      --volume /tmp/kuma-demo:/demo \
      kumahq/kuma-dp:2.9.1 run \
        --cp-address https://control-plane:5678 \
        --dataplane-token-file /demo/token-edge-gateway \
        --dataplane-file /demo/dataplane-edge-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.

  4. 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: edge-gateway
    selectors:
    - match:
        kuma.io/service: edge-gateway
    conf:
      listeners:
      - port: 8080
        protocol: HTTP
        tags:
          port: http-8080' | kumactl apply --file -
    

    This sets up the gateway to listen on port 8080 using the HTTP protocol and adds a tag (port: http-8080) to identify this listener in routing policies.

    You can test the gateway by visiting http://127.0.0.1:28080. 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.

  5. 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: edge-gateway-demo-app-route
    mesh: default
    spec:
      targetRef:
        kind: MeshGateway
        name: edge-gateway
        tags:
          port: http-8080
      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-8080) to the demo-app service. It forwards any requests with the path prefix / to demo-app.

    After setting up this route, the gateway will try to send traffic to demo-app. However, if you test it by visiting http://127.0.0.1:28080, 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.

  6. 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 to demo-app:

    echo 'type: MeshTrafficPermission
    name: allow-demo-app-from-edge-gateway
    mesh: default
    spec:
      targetRef:
        kind: MeshSubset
        tags:
          kuma.io/service: demo-app
      from:
      - targetRef:
          kind: MeshSubset
          tags:
            kuma.io/service: edge-gateway
        default:
          action: Allow' | kumactl apply --file -
    

    This policy allows traffic from the gateway to demo-app. After applying it, you can access http://127.0.0.1:28080, and the traffic will reach the demo-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-kv \
   kuma-demo-app \
   kuma-demo-edge-gateway

docker network rm kuma-demo

rm -rf /tmp/kuma-demo