Deploy a multi-zone global Kong Mesh control plane in Universal mode with Docker

Uses: Kong Mesh
Incompatible with
konnect
Related Documentation
Minimum Version
Kong Mesh - 2.10
TL;DR

Run PostgreSQL, a global control plane, and a zone control plane as Docker containers, then attach a zone ingress so the zone can join the global mesh and exchange traffic with other zones.

Prerequisites

This guide requires Docker installed on your system.

This guide requires jq installed on your system.

This guide walks you through running a multi-zone Kong Mesh deployment in Universal mode using Docker containers. We’ll start a PostgreSQL database to back the control planes, deploy a global control plane, register a zone control plane against it, and run a zone ingress so cross-zone traffic can flow.

Install Kong Mesh

  1. Run the following command to install the Kong Mesh binaries:

    curl -L https://developer.konghq.com/mesh/installer.sh | VERSION=2.13.6 sh -
  2. Add the binaries to your system’s path:

    export PATH="$(pwd)/kong-mesh-2.13.6/bin:$PATH"
  3. Run the following command to confirm that Kong Mesh is installed correctly:

    kumactl version 2>/dev/null

    You should see the following output:

    Client: Kong Mesh 2.13.6

Create a temporary directory

Set up a temporary directory to store the zone token and the ZoneIngress resource file. Ensure the path doesn’t end with a trailing /.

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/kong-mesh-multi-zone, you can use /tmp/colima/kong-mesh-multi-zone.

Create the directory if it doesn’t exist:

export KONG_MESH_MULTI_ZONE_TMP="/tmp/kong-mesh-multi-zone"
mkdir -p "$KONG_MESH_MULTI_ZONE_TMP"

Create a Docker network

Set up a separate Docker network for the containers. In this example we’ll use IP addresses in the 172.18.78.0/24 range:

docker network create \
  --subnet 172.18.0.0/16 \
  --ip-range 172.18.78.0/24 \
  --gateway 172.18.78.254 \
  kong-mesh-multi-zone

Start PostgreSQL

The global and zone control planes both need a database to persist state in Universal mode. Run a single PostgreSQL container and create one database per control plane.

  1. Run PostgreSQL:

    docker run \
      --detach \
      --name kong-mesh-multi-zone-postgres \
      --hostname postgres \
      --network kong-mesh-multi-zone \
      --ip 172.18.78.10 \
      --env POSTGRES_USER=kong \
      --env POSTGRES_PASSWORD=pass123 \
      postgres:16
  2. Create a database for each control plane:

    until docker exec kong-mesh-multi-zone-postgres pg_isready -U kong -d postgres >/dev/null 2>&1; do
      sleep 1
    done
    docker exec --interactive kong-mesh-multi-zone-postgres \
      psql -U kong -d postgres <<'SQL'
    CREATE DATABASE global;
    CREATE DATABASE zone1;
    SQL

Start the global control plane

The global control plane accepts connections from zone control planes, distributes policies, and keeps an inventory of all data plane proxies across zones.

  1. Run the database migrations for the global database:

    docker run --rm \
      --network kong-mesh-multi-zone \
      --env KUMA_STORE_TYPE=postgres \
      --env KUMA_STORE_POSTGRES_HOST=postgres \
      --env KUMA_STORE_POSTGRES_PORT=5432 \
      --env KUMA_STORE_POSTGRES_USER=kong \
      --env KUMA_STORE_POSTGRES_PASSWORD=pass123 \
      --env KUMA_STORE_POSTGRES_DB_NAME=global \
      kong/kuma-cp:2.13.6 migrate up
  2. Run the global control plane:

    docker run \
      --detach \
      --name kong-mesh-multi-zone-global-control-plane \
      --hostname global-control-plane \
      --network kong-mesh-multi-zone \
      --ip 172.18.78.1 \
      --publish 5681:5681 \
      --publish 5685:5685 \
      --env KUMA_MODE=global \
      --env KUMA_ENVIRONMENT=universal \
      --env KUMA_STORE_TYPE=postgres \
      --env KUMA_STORE_POSTGRES_HOST=postgres \
      --env KUMA_STORE_POSTGRES_PORT=5432 \
      --env KUMA_STORE_POSTGRES_USER=kong \
      --env KUMA_STORE_POSTGRES_PASSWORD=pass123 \
      --env KUMA_STORE_POSTGRES_DB_NAME=global \
      kong/kuma-cp:2.13.6 run

    The global control plane exposes:

    • Port 5681: the HTTP API and GUI.
    • Port 5685: the Kong Mesh Discovery Service (KDS) endpoint that zone control planes connect to.

Configure kumactl

To manage the deployment with kumactl, connect it to the global control plane.

  1. Run the following command to get the admin token from the global control plane:

    export KONG_MESH_MULTI_ZONE_ADMIN_TOKEN="$(
      docker exec kong-mesh-multi-zone-global-control-plane \
        wget --quiet --output-document - \
        http://127.0.0.1:5681/global-secrets/admin-user-token \
        | jq --raw-output .data \
        | base64 --decode
    )"
  2. Use the retrieved token to link kumactl to the global control plane:

    kumactl config control-planes add \
      --name kong-mesh-multi-zone-global \
      --address http://127.0.0.1:5681 \
      --auth-type tokens \
      --auth-conf "token=$KONG_MESH_MULTI_ZONE_ADMIN_TOKEN" \
      --skip-verify
  3. Run the following command to verify the connection. No zones are registered yet:

    kumactl get zones

    You should see an empty list.

Configure the default mesh

Apply an mTLS-enabled Mesh to the global control plane. mTLS is required for cross-zone communication because Kong Mesh uses the Server Name Indication field of the TLS handshake to pass routing information between zones. The mesh syncs down to every zone once registered:

echo 'type: Mesh
name: default
meshServices:
  mode: Exclusive
mtls:
  enabledBackend: ca-1
  backends:
    - name: ca-1
      type: builtin' | kumactl apply -f -

Start the zone control plane

Each zone runs its own control plane. The zone control plane connects to the global control plane over KDS and serves XDS configuration to local data plane proxies.

  1. Run the database migrations for the zone1 database:

    docker run --rm \
      --network kong-mesh-multi-zone \
      --env KUMA_STORE_TYPE=postgres \
      --env KUMA_STORE_POSTGRES_HOST=postgres \
      --env KUMA_STORE_POSTGRES_PORT=5432 \
      --env KUMA_STORE_POSTGRES_USER=kong \
      --env KUMA_STORE_POSTGRES_PASSWORD=pass123 \
      --env KUMA_STORE_POSTGRES_DB_NAME=zone1 \
      kong/kuma-cp:2.13.6 migrate up
  2. Run the zone control plane:

    docker run \
      --detach \
      --name kong-mesh-multi-zone-zone1-control-plane \
      --hostname zone1-control-plane \
      --network kong-mesh-multi-zone \
      --ip 172.18.78.2 \
      --publish 25681:5681 \
      --publish 25678:5678 \
      --env KUMA_MODE=zone \
      --env KUMA_MULTIZONE_ZONE_NAME=zone1 \
      --env KUMA_ENVIRONMENT=universal \
      --env KUMA_STORE_TYPE=postgres \
      --env KUMA_STORE_POSTGRES_HOST=postgres \
      --env KUMA_STORE_POSTGRES_PORT=5432 \
      --env KUMA_STORE_POSTGRES_USER=kong \
      --env KUMA_STORE_POSTGRES_PASSWORD=pass123 \
      --env KUMA_STORE_POSTGRES_DB_NAME=zone1 \
      --env KUMA_MULTIZONE_ZONE_GLOBAL_ADDRESS=grpcs://global-control-plane:5685 \
      --env KUMA_MULTIZONE_ZONE_KDS_TLS_SKIP_VERIFY=true \
      kong/kuma-cp:2.13.6 run

    The zone control plane exposes:

    • Port 25681: the local HTTP API and GUI.
    • Port 25678: the local XDS endpoint that data plane proxies inside the zone connect to.

    KUMA_MULTIZONE_ZONE_KDS_TLS_SKIP_VERIFY=true is required because the global control plane’s certificate is self-signed in this demo. For production, use a certificate signed by a trusted CA. See Secure access across services for more information.

  3. Confirm the zone registered against the global control plane:

    kumactl get zones

    You should see zone1 listed as Online.

Start the zone ingress

A zone ingress is the entry point for cross-zone traffic. Without it, other zones have no way to reach services in zone1.

  1. Generate a zone token scoped to ingress and egress for zone1:

    kumactl generate zone-token \
      --zone=zone1 \
      --valid-for 720h \
      --scope ingress \
      --scope egress \
      > "$KONG_MESH_MULTI_ZONE_TMP/token-zone1"
  2. Create a ZoneIngress resource definition:

    echo 'type: ZoneIngress
    name: zone1-ingress
    networking:
      address: 172.18.78.3
      port: 10000
      advertisedAddress: zone1-ingress
      advertisedPort: 10000' > "$KONG_MESH_MULTI_ZONE_TMP/zone1-ingress.yaml"

    networking.address is the address kuma-dp binds to inside the ingress container. It must be a real address. In this example, we’ll use the static IP we’ll assign to the ingress container in the next step: 172.18.78.3.

    advertisedAddress and advertisedPort are the values other zones use to reach this ingress. On this single-host Docker network, the container hostname zone1-ingress resolves via Docker’s embedded DNS and works for both directions.

  3. Run the zone ingress data plane proxy:

    docker run \
      --detach \
      --name kong-mesh-multi-zone-zone1-ingress \
      --hostname zone1-ingress \
      --network kong-mesh-multi-zone \
      --ip 172.18.78.3 \
      --publish 10000:10000 \
      --volume "$KONG_MESH_MULTI_ZONE_TMP:/demo" \
      kong/kuma-dp:2.13.6 run \
        --proxy-type=ingress \
        --cp-address=https://zone1-control-plane:5678 \
        --dataplane-token-file=/demo/token-zone1 \
        --dataplane-file=/demo/zone1-ingress.yaml
  4. Confirm the zone ingress registered with the zone control plane:

    kumactl get zone-ingresses

    You should see zone1-ingress listed.

Verify the deployment

  1. Confirm the zone is healthy and online:

    kumactl inspect zones

    You should see zone1 reporting Online with its ingress listed.

  2. Open the global control plane UI at http://127.0.0.1:5681/gui and check that:

    • zone1 displays in the Zones view.
    • zone1-ingress displays in the zone’s Ingresses tab.
    • The default mesh has mTLS enabled.

Cleanup

docker rm --force \
  kong-mesh-multi-zone-zone1-ingress \
  kong-mesh-multi-zone-zone1-control-plane \
  kong-mesh-multi-zone-global-control-plane \
  kong-mesh-multi-zone-postgres
docker network rm kong-mesh-multi-zone
rm -rf "${KONG_MESH_MULTI_ZONE_TMP:-/tmp/kong-mesh-multi-zone}"
kumactl config control-planes remove --name kong-mesh-multi-zone-global

Help us make these docs great!

Kong Developer docs are open source. If you find these useful and want to make them better, contribute today!