Install KubeMQ with Docker
Run KubeMQ under Docker in depth — Compose, configuration, connectors, persistence, health checks, upgrade and backup.
Docker is recommended for development and testing only. For production, deploy on Kubernetes with Helm and the operator.
New here? Start with the Quickstart — it runs KubeMQ, opens the dashboard, and round-trips your first message in about 5 minutes. This page is the in-depth Docker reference: Compose, configuration, connectors, persistence, health checks, and standalone upgrade/rollback/backup.
Docker Compose
For a more structured setup, use Docker Compose. This configuration includes persistent storage and environment variable support.
services:
kubemq:
image: europe-docker.pkg.dev/kubemq/images/kubemq:next
container_name: kubemq
hostname: kubemq
ports:
- "50000:50000" # gRPC
- "9090:9090" # REST
- "8080:8080" # API & Dashboard
environment:
- KUBEMQ_TOKEN=${KUBEMQ_TOKEN:-}
volumes:
- kubemq-data:/kubemq/store
restart: unless-stopped
volumes:
kubemq-data:Save this file and start KubeMQ:
docker compose up -dA downloadable version of this file is available at /docker-compose.yml.
Stop and remove
docker compose downTo also remove persistent data:
docker compose down -vConfiguration
KubeMQ is configured through environment variables. Pass them using the -e flag with docker run or the environment section in Docker Compose.
Common environment variables
| Variable | Default | Description |
|---|---|---|
KUBEMQ_TOKEN | — | License key (required for standalone mode outside Kubernetes) |
LOG_LEVEL | 2 | Log verbosity: 0=Trace 1=Debug 2=Info 3=Warn 4=Error 5=Fatal |
API_PORT | 8080 | Dashboard and management API port |
CONNECTORS_GRPC_PORT | 50000 | gRPC transport port |
CONNECTORS_REST_PORT | 9090 | REST transport port |
STORE_CLEAN_STORE | false | Remove stored data on startup |
STORE_MAX_RETENTION | 1440 | Max message retention in minutes (default: 24 hours) |
STORE_MAX_MESSAGES | 0 | Max messages per channel (0 = unlimited) |
STORE_MAX_QUEUE_SIZE | 0 | Max queue size in bytes (0 = unlimited) |
QUEUE_MAX_NUMBER_OF_MESSAGES | 1024 | Max messages per receive request |
QUEUE_MAX_WAIT_TIMEOUT_SECONDS | 3600 | Max polling wait timeout in seconds |
Example with configuration
docker run -d \ --name kubemq \ -p 50000:50000 \ -p 9090:9090 \ -p 8080:8080 \ -e KUBEMQ_TOKEN=YOUR_LICENSE_KEY \ -e LOG_LEVEL=2 \ -e STORE_MAX_RETENTION=2880 \ europe-docker.pkg.dev/kubemq/images/kubemq:nextSizing for local eval: a single container is light — 1-2 vCPU and 2 GB RAM is enough for local development and evaluation traffic on any of the four patterns. Scale up only if you drive sustained high-throughput persistence (Events Store, Queues, or the Kafka connector) with a large STORE_MAX_RETENTION. Production/cluster sizing lives in the Helm production checklist.
Ports
KubeMQ exposes three core network ports by default. Wire-protocol connectors are opt-in — they open additional ports only when you enable them.
| Port | Protocol | Service | Description |
|---|---|---|---|
50000 | gRPC (HTTP/2) | Transport | Primary SDK transport. All SDKs connect here by default. |
9090 | HTTP | REST / WebSocket | REST API and WebSocket connections for subscriptions. |
8080 | HTTP | Dashboard / API | Web dashboard, health probes (/health, /ready), and Prometheus metrics (/metrics). |
The gRPC port (50000) is the primary transport used by all KubeMQ SDKs. The REST port (9090) is useful for testing with cURL or when gRPC is not available. The dashboard port (8080) provides a management UI and health endpoints.
Enabling wire-protocol connectors
The seven wire-protocol connectors (MQTT, AMQP 0-9-1, AMQP 1.0, STOMP, Kafka, AWS, GCP Pub/Sub) are disabled by default. Each opens a new network port and must be explicitly enabled. Enable them with environment variables:
| Connector | Env var | Ports opened |
|---|---|---|
| MQTT | CONNECTORSMQTT_ENABLE=true | 1883 / 8883 / 8083 |
| AMQP 0-9-1 (RabbitMQ) | CONNECTORS_AMQP_ENABLE=true | 5672 / 5671 |
| AMQP 1.0 | CONNECTORS_AMQP10_ENABLE=true | 5672 / 5671 (shared mux) |
| STOMP | CONNECTORS_STOMP_ENABLE=true | 61613 / 61614 |
| Kafka | CONNECTORS_KAFKA_ENABLE=true | 9092 / 9093 |
| AWS (SQS & SNS) | CONNECTORS_AWS_ENABLE=true | 4566 |
| GCP Pub/Sub | CONNECTORS_GCP_ENABLE=true | 8085 |
Example — start KubeMQ with MQTT and the AWS connector enabled:
docker run -d \ --name kubemq \ -p 50000:50000 \ -p 9090:9090 \ -p 8080:8080 \ -p 1883:1883 \ -p 4566:4566 \ -e KUBEMQ_TOKEN=YOUR_LICENSE_KEY \ -e CONNECTORSMQTT_ENABLE=true \ -e CONNECTORS_AWS_ENABLE=true \ europe-docker.pkg.dev/kubemq/images/kubemq:nextEnv var spelling matters. The MQTT enable variable is CONNECTORSMQTT_ENABLE — no
underscore between CONNECTORS and MQTT. Other connectors use an underscore:
CONNECTORS_AMQP_ENABLE, CONNECTORS_STOMP_ENABLE, etc. See the
connectors reference for all variable names.
Kafka single-node (Docker)
KubeMQ can expose a Kafka wire-protocol endpoint for single-node Docker development.
Kafka runs on the next storage engine — which is auto-selected with zero
configuration on a fresh store when the Kafka connector is enabled. You do not set
the engine first; see Storage Engines for
the full selection rules. Enable Kafka with CONNECTORS_KAFKA_ENABLE=true.
User-defined network
Docker's default bridge network has no DNS, so a Kafka client resolving the advertised
container name will not be able to connect there. Create a user-defined network first,
then attach KubeMQ to it with a stable --hostname:
docker network create mynet
docker run -d \
--network mynet \
--name kubemq \
--hostname kubemq \
-e KUBEMQ_TOKEN=YOUR_LICENSE_KEY \
-e CONNECTORS_KAFKA_ENABLE=true \
europe-docker.pkg.dev/kubemq/images/kubemq:nextOther containers attached to mynet reach Kafka at kubemq:9092.
Port-mapped host access
To connect from a Kafka client running on the host (outside Docker), advertise
localhost and publish the Kafka port. The published host port must equal
CONNECTORS_KAFKA_PORT (9092 by default):
docker run -d \ --name kubemq \ -p 9092:9092 \ -e KUBEMQ_TOKEN=YOUR_LICENSE_KEY \ -e CONNECTORS_KAFKA_ENABLE=true \ -e CONNECTORS_KAFKA_ADVERTISED_HOST=localhost \ europe-docker.pkg.dev/kubemq/images/kubemq:nextA Kafka client on the host can now connect at localhost:9092.
Persistent volume
Give the container a stable --name/--hostname so the advertised name and the
store's host-subdir stay stable across restarts, and mount a volume for /store:
docker run -d \
--name kubemq \
--hostname kubemq \
-e KUBEMQ_TOKEN=YOUR_LICENSE_KEY \
-e CONNECTORS_KAFKA_ENABLE=true \
-v kubemq-kafka-data:/kubemq/store \
europe-docker.pkg.dev/kubemq/images/kubemq:nextThe user-defined-network and port-mapped-host recipes above are mutually exclusive per deployment. A single advertised endpoint means you pick either user-defined-network reachability or port-mapped host reachability — not both. See the Kafka connector overview and the Kafka settings reference for the full set of options (TLS port, SASL mechanisms, OAUTHBEARER, and more).
Persistence
By default, KubeMQ stores data inside the container at /store. This data is lost when the container is removed. To persist data across container restarts, mount a volume.
Named volume
docker run -d \ --name kubemq \ -p 50000:50000 \ -p 9090:9090 \ -p 8080:8080 \ -e KUBEMQ_TOKEN=YOUR_LICENSE_KEY \ --hostname kubemq \ -v kubemq-data:/kubemq/store \ europe-docker.pkg.dev/kubemq/images/kubemq:nextBind mount
Mount a host directory for easier access to the stored data:
docker run -d \ --name kubemq \ -p 50000:50000 \ -p 9090:9090 \ -p 8080:8080 \ -e KUBEMQ_TOKEN=YOUR_LICENSE_KEY \ --hostname kubemq \ -v $(pwd)/kubemq-store:/kubemq/store \ europe-docker.pkg.dev/kubemq/images/kubemq:nextPersistence is required for Events Store and Queues patterns. Events (fire-and-forget) and RPC patterns do not require persistence, but the store is still used for internal metadata.
Health checks
KubeMQ exposes health endpoints on the API port:
# Liveness check — is the process running?
curl http://localhost:8080/health
# Readiness check — is the broker ready to accept traffic?
curl http://localhost:8080/readyAdd a Docker health check to your docker run command:
docker run -d \
--name kubemq \
-p 50000:50000 \
-p 9090:9090 \
-p 8080:8080 \
-e KUBEMQ_TOKEN=YOUR_LICENSE_KEY \
--health-cmd="curl -f http://localhost:8080/health || exit 1" \
--health-interval=10s \
--health-timeout=5s \
--health-retries=3 \
europe-docker.pkg.dev/kubemq/images/kubemq:nextUpgrade, rollback & backup
KubeMQ ships on the mandatory :next tag — there's no version number to bump. "Upgrading" means re-pulling :next and recreating the container underneath the same name; "rolling back" means restarting from an image you deliberately kept on disk, not from a pinned digest. :next is the only supported channel — see the Helm image-tag policy for why pinning by digest or semver isn't the model.
Upgrade
Re-pull the image and recreate the container:
docker pull europe-docker.pkg.dev/kubemq/images/kubemq:next
docker stop kubemq
docker rm kubemqThen start it again with the same command you used originally (same name, same volume) — Docker resolves :next to the image you just pulled:
docker run -d \ --name kubemq \ -p 50000:50000 \ -p 9090:9090 \ -p 8080:8080 \ -e KUBEMQ_TOKEN=YOUR_LICENSE_KEY \ --hostname kubemq \ -v kubemq-data:/kubemq/store \ europe-docker.pkg.dev/kubemq/images/kubemq:nextRoll back
Because :next is a moving tag, "rolling back" means restarting from a local image you retained before upgrading — not re-pulling an older digest. Do one of these before you upgrade:
# Option A — tag the currently-running image under a name you control
docker tag europe-docker.pkg.dev/kubemq/images/kubemq:next kubemq-known-good
# Option B — or just record its image ID
docker inspect --format='{{.Image}}' kubemqIf the upgrade goes wrong, stop and remove the new container, then start a container from the retained local image (or ID) instead of :next:
docker stop kubemq
docker rm kubemq
docker run -d \
--name kubemq \
--hostname kubemq \
-p 50000:50000 \
-p 9090:9090 \
-p 8080:8080 \
-e KUBEMQ_TOKEN=YOUR_LICENSE_KEY \
-v kubemq-data:/kubemq/store \
kubemq-known-goodThis is local image retention, not registry pinning. :next stays the only image reference you pull from the registry — the rollback target lives only on this host, which is why you must tag or record it before you re-pull.
Back up the store
The kubemq-data volume — mounted at /kubemq/store in the server container — holds everything Events Store and Queues persist. Back it up with a throwaway container that mounts the same volume (the path inside the throwaway container is arbitrary):
docker run --rm -v kubemq-data:/store -v "$(pwd)":/backup alpine \
tar czf /backup/kubemq-store-backup.tar.gz -C /store .Restore it the same way, in reverse, onto a fresh volume before starting KubeMQ:
docker run --rm -v kubemq-data:/store -v "$(pwd)":/backup alpine \
sh -c "cd /store && tar xzf /backup/kubemq-store-backup.tar.gz"Related
Quickstart
Run KubeMQ and send your first message in about 5 minutes.
Install with Helm
Deploy KubeMQ to Kubernetes for production use.
Configure KubeMQ
Env vars, a mounted config.yaml, the CONFIG variable, and docker-compose.
Kafka connector
Adopt KubeMQ as a drop-in Kafka broker — what works and how to migrate.
Was this page helpful?