Docker (single-node)
Configure a single-node KubeMQ container — env vars, a mounted config.yaml, and the CONFIG variable; docker run and compose.
Docker runs one KubeMQ node for development and testing. One container runs the full server: every interface, every connector, the persistent store, and the embedded messaging engine — the same container that runs on Docker or Podman; there is no separate native binary install. This guide hosts the complete, runnable Docker configs; the reference pages show per-setting snippets and link back here.
Install KubeMQ first with Install with kmq or Install with Docker. This page changes the settings of a running server.
Every command on this page recreates the container kubemq on the kubemq-data volume,
so your messages stay. Remove the running container first with docker stop kubemq and
docker rm kubemq. If kmq created the server, remove it with kmq instead, as
Install with kmq shows; from then on you manage the container with
Docker commands. If you added a license, run each command from kubemq-private with
--env-file kubemq-license.env added, as Install with Docker
does: a server whose store already used its evaluation does not start without it. If kmq
saved your license, create kubemq-license.env first with the license step of
Install with Docker; kmq keeps the key in its own
store, not in that file.
| Port | Interface | Purpose |
|---|---|---|
50000 | gRPC | Primary SDK transport. |
9090 | REST / WebSocket | REST API, WebSocket, and the shared HTTP server (MCP · A2A · CloudEvents). |
8080 | API / Dashboard | Web dashboard, management API, health probes, and metrics. |
The store lives on the kubemq-data volume, mounted at /kubemq/store inside the
container. It is the same volume Try KubeMQ creates. Persistence is
required for the Events Store and Queues patterns.
Two things a persistent store needs.
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.
Keep the hostname fixed with --hostname. The store layout is
<storepath>/<host>/…, and Docker gives every new container a random hostname unless you
set one. A single server with no HOST set survives a change: it adopts the one server
directory it finds in the store and logs NOTICE: adopting existing store identity. That
rescue does not run when HOST is set, and it cannot choose when the store holds more than
one server directory. The server then starts on an empty directory beside the old one.
Every command on this page sets --hostname kubemq.
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 \ --pull always \ --platform linux/amd64 \ --name kubemq \ --hostname kubemq \ -p 127.0.0.1:50000:50000 \ -p 127.0.0.1:9090:9090 \ -p 127.0.0.1:8080:8080 \ -p 127.0.0.1:9092:9092 \ -e STORE_ENGINE=next \ -e STORE_NEXT_ACK_POLICY=strict \ -e STORE_STORE_PATH=/kubemq/store \ -e API_BIND_ADDRESS=0.0.0.0 \ -e LOG_LEVEL=1 \ -e STORE_MAX_RETENTION=2880 \ -e CONNECTORSCE_ENABLE=false \ -v kubemq-data:/kubemq/store \ europe-docker.pkg.dev/kubemq/images/kubemq-next:latestThe 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 set | Does it work? | Does the server say anything? |
|---|---|---|
CONNECTORS_MQTT_ENABLE (wrong twin of a collapsed name) | No | Yes — 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 forms | Yes — an IGNORED warning that is wrong; the value is applied anyway |
A typo in a correct collapsed name (CONNECTORSMQT_ENABLE) | No | Nothing 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.
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 is not a config.yaml setting. It comes only from environment variables; see
License. Keep the kubemq-data volume when you
recreate the container.
Mount the file and select it with --config. The flag goes after the image name and
after the binary path:
docker run -d \ --pull always \ --platform linux/amd64 \ --name kubemq \ --hostname kubemq \ -p 127.0.0.1:50000:50000 \ -p 127.0.0.1:9090:9090 \ -p 127.0.0.1:8080:8080 \ -p 127.0.0.1:9092:9092 \ -e STORE_ENGINE=next \ -e STORE_NEXT_ACK_POLICY=strict \ -e STORE_STORE_PATH=/kubemq/store \ -e API_BIND_ADDRESS=0.0.0.0 \ -v kubemq-data:/kubemq/store \ -v "$(pwd)/config.yaml:/kubemq/config.yaml:ro" \ europe-docker.pkg.dev/kubemq/images/kubemq-next:latest /kubemq/kubemq-run --config /kubemq/config.yamlYou 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. There are three
families. The interfaces and the HTTP-family connectors (gRPC, REST, API, MCP, A2A,
CloudEvents) ship on by default. The Kafka (9092/9093) and RabbitMQ / AMQP 0-9-1
(5672/5671) connectors also ship on by default — the image EXPOSEs 9092 and 5672
alongside the core ports — and you turn them off with CONNECTORS_KAFKA_ENABLE=false /
CONNECTORS_AMQP_ENABLE=false. The remaining wire-protocol connectors (MQTT, AMQP 1.0, STOMP,
AWS, GCP) are opt-in and ship off; you turn them on with enable: true
(env ..._ENABLE=true). On Docker every toggle is the same enable: true | false key. The
Helm/CRD surface splits them: the always-on interfaces use an opt-out disabled: true, while
the wire connectors use enabled: true | false (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:
docker run -d \ --pull always \ --platform linux/amd64 \ --name kubemq \ --hostname kubemq \ -p 127.0.0.1:50000:50000 \ -p 127.0.0.1:9090:9090 \ -p 127.0.0.1:8080:8080 \ -p 127.0.0.1:9092:9092 \ -e STORE_ENGINE=next \ -e STORE_NEXT_ACK_POLICY=strict \ -e STORE_STORE_PATH=/kubemq/store \ -e API_BIND_ADDRESS=0.0.0.0 \ -e CONFIG="$(cat config.yaml)" \ -v kubemq-data:/kubemq/store \ europe-docker.pkg.dev/kubemq/images/kubemq-next:latestCONFIG also accepts a base64-encoded payload, which avoids newline and quoting
issues when the value passes through a secret store or a templating layer:
docker run -d \ --pull always \ --platform linux/amd64 \ --name kubemq \ --hostname kubemq \ -p 127.0.0.1:50000:50000 \ -p 127.0.0.1:9090:9090 \ -p 127.0.0.1:8080:8080 \ -p 127.0.0.1:9092:9092 \ -e STORE_ENGINE=next \ -e STORE_NEXT_ACK_POLICY=strict \ -e STORE_STORE_PATH=/kubemq/store \ -e API_BIND_ADDRESS=0.0.0.0 \ -e CONFIG="$(base64 < config.yaml)" \ -v kubemq-data:/kubemq/store \ europe-docker.pkg.dev/kubemq/images/kubemq-next:latestdocker-compose
To run the same single server with Docker Compose, download the Compose file from
Install with Docker, then add a
docker-compose.override.yml next to it. Compose merges the override automatically, so
the downloaded file stays as published, with its kubemq-data volume.
services:
kubemq:
command: ["/kubemq/kubemq-run", "--config", "/kubemq/config.yaml"]
environment:
LOG_LEVEL: "1"
volumes:
- ./config.yaml:/kubemq/config.yaml:roCheck the merge:
docker compose configYou should see, under kubemq: a command list ending in --config and
/kubemq/config.yaml, LOG_LEVEL: "1" next to the published file's variables, and two
mounts, the kubemq-data volume at /kubemq/store and config.yaml at
/kubemq/config.yaml.
If you added a license, now add env_file: [./kubemq-license.env] under kubemq: in the
override, and keep the Compose file and the override in kubemq-private, next to
kubemq-license.env; run the next commands there. Add it after the check above, because
docker compose config prints the values of an environment file. Leave the line out if you
have no license: Compose stops when the file is missing. With a license but without the
line, a server whose store already used its evaluation does not start.
Get the latest image:
docker compose pullYou should see kubemq reported as pulled.
Start it:
docker compose up -dYou should see the container kubemq created or recreated, then started. docker compose ps
shows it Up.
To supply the config inline instead of mounting a file, drop command and the
config.yaml mount from the override and set CONFIG (or CONFIG as base64) under
environment.
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.
Core & Licensing
License key or file, licensing endpoint and drain settings, log level, and host/server identity.
Interfaces
gRPC, REST/WebSocket, the management API, and the shared HTTP server with CORS.
Connectors
MCP, A2A (agents), CloudEvents, MQTT, AMQP 0.9.1, AMQP 1.0, STOMP, Kafka, AWS, and GCP Pub/Sub.
Storage & Queues
Persistent store limits and retention plus queue delivery defaults and ceilings.
Storage Engines
The next and legacy persistence engines, engine selection, durability, and retention scope.
Security
JWT and OIDC authentication, policy-based authorization, and TLS/mTLS.
Observability
OpenTelemetry traces and metrics, audit logging, and notifications.
Deployment & High Availability
Kubernetes packaging — image, volume, resources, health, scheduling, Service exposure, and replicas.
Advanced
Message-broker engine, runtime tuning, and routing — config.yaml-only advanced knobs.
Verify
Confirm the node is up. Open the dashboard at
http://localhost:8080, then check the container logs:
docker logs kubemqA healthy start logs each interface binding to its port. The health and readiness probes on the API port confirm the server is accepting traffic:
curl http://localhost:8080/health
curl http://localhost:8080/readyRelated
- Install with Docker — install a licensed single server, with Docker or Docker Compose.
- Kubernetes (Helm) — the production target with replicas and
Serviceexposure. - Configuration overview — the two targets and the config model.
- Configuration reference — every setting, grouped by domain.
Was this page helpful?