KubeMQ
ConfigureDocker

Docker (single-node)

Configure a single-node KubeMQ container — env vars, a mounted config.yaml, and the CONFIG variable; docker run and compose.

Docker single-node is the standalone KubeMQ server, containerized. One container runs the full server: every interface, every connector, the persistent store, and the embedded messaging engine. There is no separate "bare-binary" target — the container is the binary. This guide hosts the complete, runnable Docker configs; the reference pages show per-setting snippets and link back here.

Install KubeMQ firstDocker install. This page covers how to configure a single node, not how to install one.

PortInterfacePurpose
50000gRPCPrimary SDK transport.
9090REST / WebSocketREST API, WebSocket, and the shared HTTP server (MCP · A2A · CloudEvents).
8080API / DashboardWeb dashboard, management API, health probes, and metrics.

The store is bind-mounted to /kubemq/store inside the container. Persistence is required for the Events Store and Queues patterns.

Two things a persistent store needs, and both are easy to miss.

Mount at /kubemq/store, not /store. The image's working directory is /kubemq and the default store.storepath is the relative ./store, so the server writes to /kubemq/store. A volume mounted at /store receives nothing and the data dies with the container — and every health check on this page still passes, because the server is running fine, just onto container-local disk.

Pin the hostname with --hostname. The store layout is <storepath>/<hostname>/…, and Docker assigns a fresh random hostname to every container. Recreate the container without --hostname and the server boots clean and healthy onto a new empty directory, with the old one sitting intact beside it. On the next engine the node's raft identity moves with it too. Setting KubeMQ's own HOST does not substitute — the directory name comes from the OS hostname.

Three ways to supply config

Every setting has a documented default, so a server runs with no overrides at all. To change a setting you have three delivery methods, in order of how much you are configuring:

Per-field environment variables

Pass each setting as -e GROUP_FIELD=value. The env var is the config.yaml key snake-cased, dotless, and uppercased — store.maxretention becomes STORE_MAX_RETENTION. This is the lightest method, best for a handful of overrides:

docker run -d \  --name kubemq \  -p 50000:50000 \  -p 9090:9090 \  -p 8080:8080 \  -e KUBEMQ_TOKEN=YOUR_LICENSE_KEY \  -e LOG_LEVEL=1 \  -e STORE_MAX_RETENTION=2880 \  -e CONNECTORSCE_ENABLE=false \  --hostname kubemq \  -v "$(pwd)/kubemq-store:/kubemq/store" \  europe-docker.pkg.dev/kubemq/images/kubemq:next

The connector acronym variables drop the underscore. The CloudEvents enable variable is CONNECTORSCE_ENABLE (no underscore between CONNECTORS and CE). The same collapse applies to CONNECTORSMCP_* and CONNECTORSMQTT_*, while the Title-case connectors keep the underscore (CONNECTORS_AMQP_*, CONNECTORS_STOMP_*, CONNECTORS_AWS_*), and A2A splits to CONNECTORSA2_A_*. The full rule is in the reference legend.

What happens when you get it wrong depends on which form you used, and the warning is not reliable in either direction:

You setDoes it work?Does the server say anything?
CONNECTORS_MQTT_ENABLE (wrong twin of a collapsed name)NoYes — an IGNORED warning, because the name is in the CONNECTORS_ namespace
CONNECTORS_CE_ENABLE (CloudEvents only)Yes — CE is the one connector that binds both formsYes — an IGNORED warning that is wrong; the value is applied anyway
A typo in a correct collapsed name (CONNECTORSMQT_ENABLE)NoNothing at all — collapsed names sit outside the warner's namespace list

So: an IGNORED warning for a CONNECTORS_CE_* variable is a false alarm — do not "fix" a working setting because of it. And the absence of a warning proves nothing about a collapsed-form name. Check the effective value in the dashboard rather than trusting the log either way.

A mounted config.yaml

Once you are setting more than a few fields, keep them in a config.yaml and mount it into the container. The server auto-detects YAML or TOML; point it at the file with the --config flag.

config.yaml
log:
  level: 1
store:
  storepath: ./store
  maxretention: 2880
connectors:
  grpc:
    enable: true
    port: "50000"
  rest:
    enable: true
    port: "9090"
  ce:
    enable: false
api:
  port: "8080"

The license key is not a config.yaml field. It is read straight from the environment as KUBEMQ_TOKEN (or passed as the --key flag) — there is no viper binding and no config-file key for it. A key: entry in config.yaml is the Helm spelling; put it here and the server ignores it and refuses to start unlicensed. Keep the token in the environment, as every docker run on this page does.

Mount the file and select it with --config. The flag goes after the image name and after the binary path:

Terminal
docker run -d \
  --name kubemq \
  --hostname kubemq \
  -p 50000:50000 \
  -p 9090:9090 \
  -p 8080:8080 \
  -e KUBEMQ_TOKEN=YOUR_LICENSE_KEY \
  -v "$(pwd)/kubemq-store:/kubemq/store" \
  -v "$(pwd)/config.yaml:/kubemq/config.yaml:ro" \
  europe-docker.pkg.dev/kubemq/images/kubemq:next \
  /kubemq/kubemq-run --config /kubemq/config.yaml

You must repeat /kubemq/kubemq-run. The image declares no ENTRYPOINT — only CMD ["/kubemq/kubemq-run"] — so anything you put after the image name replaces the command rather than appending to it. Passing just --config /kubemq/config.yaml makes Docker try to execute --config as the binary, and the container never starts.

enable is the Docker toggle — but the default differs by family. The interfaces and the HTTP-family connectors (gRPC, REST, API, MCP, A2A, CloudEvents) ship on by default; the wire-protocol connectors (MQTT, AMQP, STOMP, Kafka, AWS, GCP) are opt-in and ship off. On Docker you flip either with enable: true | false (env ..._ENABLE) — turn an always-on interface off with enable: false, or turn a wire connector on with enable: true. The Helm/CRD surface splits the two: the always-on interfaces use an opt-out disabled: true, while the wire connectors use an opt-in enabled: true (see Kubernetes). Same toggles, inverted boolean.

The CONFIG environment variable

When mounting a file is awkward — orchestrators that inject env vars, CI runners, secret managers — supply the whole config inline through the CONFIG environment variable. The server writes the value to a file and loads it, exactly as if you had passed --config:

Terminal
docker run -d \
  --name kubemq \
  --hostname kubemq \
  -p 50000:50000 \
  -p 9090:9090 \
  -p 8080:8080 \
  -e KUBEMQ_TOKEN=YOUR_LICENSE_KEY \
  -v "$(pwd)/kubemq-store:/kubemq/store" \
  -e CONFIG="$(cat config.yaml)" \
  europe-docker.pkg.dev/kubemq/images/kubemq:next

CONFIG also accepts a base64-encoded payload, which avoids newline and quoting issues when the value passes through a secret store or a templating layer:

Terminal
docker run -d \
  --name kubemq \
  --hostname kubemq \
  -p 50000:50000 \
  -p 9090:9090 \
  -p 8080:8080 \
  -e KUBEMQ_TOKEN=YOUR_LICENSE_KEY \
  -v "$(pwd)/kubemq-store:/kubemq/store" \
  -e CONFIG="$(base64 < config.yaml)" \
  europe-docker.pkg.dev/kubemq/images/kubemq:next

docker-compose

The same single node as a docker-compose.yaml, combining a mounted config.yaml with a couple of per-field environment overrides:

docker-compose.yaml
services:
  kubemq:
    image: europe-docker.pkg.dev/kubemq/images/kubemq:next
    container_name: kubemq
    hostname: kubemq
    command: ["/kubemq/kubemq-run", "--config", "/kubemq/config.yaml"]
    ports:
      - "50000:50000"  # gRPC
      - "9090:9090"    # REST / WebSocket
      - "8080:8080"    # API / Dashboard
    environment:
      - KUBEMQ_TOKEN=${KUBEMQ_TOKEN:-}
      - LOG_LEVEL=1
    volumes:
      - kubemq-store:/kubemq/store
      - ./config.yaml:/kubemq/config.yaml:ro
    restart: unless-stopped

volumes:
  kubemq-store:

Start it:

Terminal
docker compose up -d

To supply the config inline instead of mounting a file, drop the command and config.yaml volume and set CONFIG (or CONFIG as base64) in the environment block.

Configure by domain

Every setting in the configs above is documented in the reference, grouped by domain. Each page lists the config.yaml key, the environment variable, the type, the default, and the valid values.

Verify

Confirm the node is up. Open the dashboard at http://localhost:8080, then check the container logs:

Terminal
docker logs kubemq

A healthy start logs each interface binding to its port. The health and readiness probes on the API port confirm the server is accepting traffic:

Terminal
curl http://localhost:8080/health
curl http://localhost:8080/ready

Was this page helpful?

On this page