Install on Kubernetes
Install the KubeMQ operator and a three-server cluster with kmq or Helm, add your license, check it, send a test message and connect your apps.
This page shows how to install the KubeMQ operator and a cluster of three servers on Kubernetes, with kmq or with Helm. When you finish, kmq license reports the license on every server, a test message round-trips, and you know the address your applications use. Time: about 30 minutes.
Hardening for production traffic is on the Production checklist.
These commands are for bash on macOS and Linux. On Windows, run them in WSL (Windows Subsystem for Linux), or use the kmq tab of Try KubeMQ, which runs natively on Windows.
The cluster messaging, as the operator runs it:
Before you start
Create a private folder, readable only by you, and work inside it:
mkdir -p -m 700 kubemq-privatecd kubemq-private- kubectl, Helm, curl and jq, with a context for the target cluster. The kmq tab runs kubectl and Helm for you.
- kmq, installed as in Try KubeMQ. Both tabs use it.
- Permission to create custom resource definitions and cluster roles.
- A storage class that creates volumes on demand. Note its name:
kubectl --context YOUR_KUBE_CONTEXT get storageclassReplace: YOUR_KUBE_CONTEXT — your cluster's kubectl context, from kubectl config get-contexts.
You should see:
HARNESS_OUTPUT_PENDINGNode and network needs: Requirements and supported setups.
Add your license
A trial key for Kubernetes is not self-serve yet: KubeMQ issues it after a request. Ask for one through Plans compared, naming Kubernetes and 3 servers. The key arrives by email as license.key; then follow the License key tab. The key covers one cluster of 3 servers and binds to the first cluster it starts on.
Use the key from your KubeMQ order email. It must cover at least 3 servers.
Save the license key as license.key in this folder. The file holds only the key, on one line, with no quotes and no KUBEMQ_LICENSE_KEY= prefix. Then make it readable by you alone:
chmod 600 license.keyThis file is a secret. Do not commit it, paste it into chat, or attach it to a support ticket.
kmq license import --file license.keyYou should see:
HARNESS_OUTPUT_PENDINGkmq printed a license reference, credential or reference. The kmq tab uses it and creates its own license Secret; Helm step 2 stores license.key as the Secret messaging-license, exporting a trial key first.
Steps
Write the install file
In kubemq-private:
{
"schema_version": 1,
"goal": "production",
"target": "kubernetes",
"name": "messaging",
"credential": "YOUR_LICENSE_REF",
"kubernetes": {
"context": "YOUR_KUBE_CONTEXT",
"namespace": "kubemq",
"operator_release": "kubemq-operator",
"cluster_release": "messaging",
"server_count": 3,
"storage_class": "YOUR_STORAGE_CLASS",
"volume_size": "20Gi"
}
}Replace: YOUR_LICENSE_REF — your license reference; YOUR_KUBE_CONTEXT — your cluster's kubectl context; YOUR_STORAGE_CLASS — the storage class you noted.
Check the cluster and save a plan
Download the current public release recipe:
curl -fsSL https://docs.kubemq.io/recipes/onboarding-v1.json -o onboarding-v1.jsonWrite its independently released server image, chart and operator image into the deployment input. When --input is used, the input file supplies these values:
jq -e --slurpfile recipe onboarding-v1.json '
$recipe[0] as $r |
if (($r.server_image // "") != "" and
($r.chart_version // "") != "" and
($r.operator_image // "") != "")
then .image = $r.server_image |
.kubernetes.chart_version = $r.chart_version |
.kubernetes.operator_image = $r.operator_image
else error("release recipe is missing a required Kubernetes artifact")
end
' kubernetes.json > kubernetes.resolved.json &&
mv kubernetes.resolved.json kubernetes.jsonPrepare the resolved input:
kmq deploy prepare --input kubernetes.json --out prepared.json --deadline 10mYou should see:
HARNESS_OUTPUT_PENDINGIt creates the namespace, a license Secret and a management certificate Secret that kmq trusts.
kmq deploy plan --input prepared.json --out plan.jsonYou should see:
HARNESS_OUTPUT_PENDINGInstall the operator and the cluster
kmq deploy apply --plan plan.json --deadline 15mYou should see:
HARNESS_OUTPUT_PENDINGAfter an interruption, run it again; it resumes.
Create the namespace
kubectl --context YOUR_KUBE_CONTEXT create namespace kubemq --dry-run=client -o yaml | kubectl --context YOUR_KUBE_CONTEXT apply -f -You should see:
HARNESS_OUTPUT_PENDINGStore the license as a Secret
With a trial key, export it first (delete an old license.key; kmq never overwrites):
kmq license export --credential YOUR_LICENSE_REF --out license.keyReplace: YOUR_LICENSE_REF — your license reference.
You should see:
HARNESS_OUTPUT_PENDINGCreate the Secret; the same command replaces it:
kubectl --context YOUR_KUBE_CONTEXT -n kubemq create secret generic messaging-license --from-file=licenseKey=license.key --dry-run=client -o yaml | kubectl --context YOUR_KUBE_CONTEXT apply -f -You should see:
HARNESS_OUTPUT_PENDINGCreate the management TLS Secret before installing the cluster. The certificate must cover messaging-api.kubemq.svc, messaging-api.kubemq.svc.cluster.local and 127.0.0.1:
kubectl --context YOUR_KUBE_CONTEXT -n kubemq create secret tls messaging-api-tls --cert=YOUR_TLS_CERT_FILE --key=YOUR_TLS_KEY_FILE --dry-run=client -o yaml | kubectl --context YOUR_KUBE_CONTEXT apply -f -Replace: YOUR_TLS_CERT_FILE — the certificate; YOUR_TLS_KEY_FILE — its key; YOUR_KUBE_CONTEXT — your cluster's kubectl context. Keep the issuing authority certificate as YOUR_CA_FILE for sign-in.
Security: keep the key out of Helm values
Never use --set licenseKey=, --from-literal or a key in cluster-values.yaml: Helm stores values in the cluster.
Install the operator
helm repo add kubemq-next https://kubemq-io.github.io/charts-nexthelm repo update kubemq-nexthelm upgrade --install kubemq-operator kubemq-next/kubemq-next \
--kube-context YOUR_KUBE_CONTEXT \
-n kubemq \
--set operator.enabled=true \
--set cluster.enabled=false \
--waitYou should see:
HARNESS_OUTPUT_PENDINGInstall the cluster
In kubemq-private:
operator:
enabled: false
cluster:
enabled: true
fullnameOverride: messaging
replicas: 3
licenseKeySecretRef:
name: messaging-license
key: licenseKey
volume:
size: 20Gi
storageClass: YOUR_STORAGE_CLASS
api:
tlsSecret: messaging-api-tls
expose: ClusterIP
auth:
enable: true
adminUsername: admin
env:
STORE_NEXT_ACK_POLICY: "strict"Replace: YOUR_STORAGE_CLASS — the storage class you noted.
License fields, resources and node spread: Deployment & High Availability.
helm upgrade --install messaging kubemq-next/kubemq-next \
--kube-context YOUR_KUBE_CONTEXT \
-n kubemq \
-f cluster-values.yamlYou should see:
HARNESS_OUTPUT_PENDINGThen wait until every server is ready:
kubectl --context YOUR_KUBE_CONTEXT -n kubemq wait --for=condition=Ready kubemqclusters.next.kubemq.io/messaging --timeout=10mYou should see:
HARNESS_OUTPUT_PENDINGCheck the license the operator reports:
kubectl --context YOUR_KUBE_CONTEXT -n kubemq describe kubemqclusters.next.kubemq.io messagingYou should see:
HARNESS_OUTPUT_PENDINGCheck that the conditions include neither LicenseInvalid nor ReplicasOverLicenseCap. Per-server detail comes from kmq license once you sign in below; it shows the server behind the open management port, and any state other than active needs attention: How licensing works.
Send a test message
Open the management port
kubectl --context YOUR_KUBE_CONTEXT -n kubemq port-forward pod/messaging-0 18080:8080Replace: YOUR_KUBE_CONTEXT — your cluster's kubectl context.
You should see:
HARNESS_OUTPUT_PENDINGLeave it running.
Sign in
kmq auth login --bootstrap --installation YOUR_INSTALLATION_ID --username admin --api-address https://127.0.0.1:18080Replace: YOUR_INSTALLATION_ID — the installation_id value that kmq onboard or kmq deploy apply printed.
kmq reads the first password from the cluster and asks for a new one. You should see:
HARNESS_OUTPUT_PENDINGSave the first password in kubemq-private:
kubectl --context YOUR_KUBE_CONTEXT -n kubemq get secret messaging-api-admin -o jsonpath='{.data.admin-password}' | base64 -d > admin-passwordkmq auth login --username admin --api-address https://127.0.0.1:18080 --ca-file YOUR_CA_FILE --context-name messaging --service-name messaging-kmq-tlsReplace: YOUR_CA_FILE — the certificate authority that issued the management certificate. Paste the contents of admin-password when kmq asks, then set a new password. You should see:
HARNESS_OUTPUT_PENDINGSecurity: use the admin password only
The Secret's operator-token key belongs to the operator. Never use it.
Repeat the login only when its output explicitly says that no account was created and nothing changed. If it reports account_created: true, do not repeat the login because the service account already exists. When it also reports that the credential and context were saved, select that context in the next step and wait for the credential to verify. If either was not saved, follow the printed next_action to repair the selected store or context; if the key is unavailable, ask support to remove the orphaned account before another login.
Point kmq at the cluster
kmq context use messagingYou should see:
HARNESS_OUTPUT_PENDINGConfirm the saved service credential without creating another account:
verified=false
for attempt in $(seq 1 30); do
if kmq whoami; then
verified=true
break
fi
sleep 2
done
[ "$verified" = true ] || { echo "The saved service credential did not become ready." >&2; exit 1; }Send and receive
kmq queue send onboarding-check '{"id":1}'You should see:
HARNESS_OUTPUT_PENDINGkmq queue receive onboarding-checkYou should see:
HARNESS_OUTPUT_PENDINGConnect your applications
Applications inside the cluster use these Services, all ClusterIP:
| Interface | In-cluster address | Port |
|---|---|---|
| gRPC | messaging-grpc.kubemq.svc.cluster.local | 50000 |
| REST | messaging-rest.kubemq.svc.cluster.local | 9090 |
| Kafka-compatible | messaging-kafka.kubemq.svc.cluster.local | 9092 |
| RabbitMQ-compatible (AMQP 0-9-1) | messaging-amqp.kubemq.svc.cluster.local | 5672 |
From outside Kubernetes: Interfaces (gRPC · REST · API · HTTP). Client code: Client SDKs.
Replace the license later
Get the new license as in Add your license.
OLD_REVISION="$(kubectl --context YOUR_KUBE_CONTEXT -n kubemq get statefulset messaging -o jsonpath='{.status.currentRevision}')"
kmq deploy update --installation YOUR_INSTALLATION_ID --credential YOUR_LICENSE_REF --deadline 15m
for attempt in $(seq 1 150); do
NEW_REVISION="$(kubectl --context YOUR_KUBE_CONTEXT -n kubemq get statefulset messaging -o jsonpath='{.status.updateRevision}')"
[ -n "$NEW_REVISION" ] && [ "$NEW_REVISION" != "$OLD_REVISION" ] && break
sleep 2
done
[ -n "$NEW_REVISION" ] && [ "$NEW_REVISION" != "$OLD_REVISION" ] || { echo "The license replacement did not start a new StatefulSet revision." >&2; exit 1; }
kubectl --context YOUR_KUBE_CONTEXT -n kubemq rollout status statefulset/messaging --timeout=10mReplace: YOUR_INSTALLATION_ID — the installation_id value that kmq onboard or kmq deploy apply printed; YOUR_LICENSE_REF — the new reference; YOUR_KUBE_CONTEXT — your cluster's kubectl context.
You should see:
HARNESS_OUTPUT_PENDINGPut the new key in license.key. Record the current StatefulSet revision, replace the Secret and wait for the new revision to finish rolling out:
OLD_REVISION="$(kubectl --context YOUR_KUBE_CONTEXT -n kubemq get statefulset messaging -o jsonpath='{.status.currentRevision}')"
kubectl --context YOUR_KUBE_CONTEXT -n kubemq create secret generic messaging-license --from-file=licenseKey=license.key --dry-run=client -o yaml | kubectl --context YOUR_KUBE_CONTEXT apply -f -
for attempt in $(seq 1 150); do
NEW_REVISION="$(kubectl --context YOUR_KUBE_CONTEXT -n kubemq get statefulset messaging -o jsonpath='{.status.updateRevision}')"
[ -n "$NEW_REVISION" ] && [ "$NEW_REVISION" != "$OLD_REVISION" ] && break
sleep 2
done
[ -n "$NEW_REVISION" ] && [ "$NEW_REVISION" != "$OLD_REVISION" ] || { echo "The license replacement did not start a new StatefulSet revision." >&2; exit 1; }
kubectl --context YOUR_KUBE_CONTEXT -n kubemq rollout status statefulset/messaging --timeout=10mReplace: YOUR_KUBE_CONTEXT — your cluster's kubectl context.
The operator restarts the servers one at a time, keeping their data; an online key needs internet access meanwhile. Then run the kmq license command again. If a server does not become ready, put the previous license back and see Troubleshooting.
Remove the cluster
kmq deploy remove --installation YOUR_INSTALLATION_ID --deadline 15mReplace: YOUR_INSTALLATION_ID — the installation_id value that kmq onboard or kmq deploy apply printed.
You should see:
HARNESS_OUTPUT_PENDINGHelm keeps the cluster resource, so delete it first:
kubectl --context YOUR_KUBE_CONTEXT -n kubemq delete kubemqclusters.next.kubemq.io messaging --waithelm uninstall messaging --kube-context YOUR_KUBE_CONTEXT -n kubemqBoth keep the volumes and the operator. Remove the operator once no cluster uses it:
helm uninstall kubemq-operator --kube-context YOUR_KUBE_CONTEXT -n kubemqReplace: YOUR_KUBE_CONTEXT — your cluster's kubectl context.
Data loss: volumes and namespace
Deleting the volume claims or the namespace deletes every message and the cluster's identity. Keep your administrator password; a cluster on these volumes needs it.
Use your own management certificate
For production, use a management certificate your organization issues. The Helm steps above create the required Secret from certificate files before installing the cluster. With cert-manager, apply this after creating the namespace and before installing the cluster instead:
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: messaging-api
namespace: kubemq
spec:
secretName: messaging-api-tls
dnsNames:
- messaging-api.kubemq.svc
- messaging-api.kubemq.svc.cluster.local
ipAddresses:
- 127.0.0.1
issuerRef:
name: YOUR_ISSUERkubectl --context YOUR_KUBE_CONTEXT -n kubemq apply -f management-certificate.yamlReplace: YOUR_ISSUER — a cert-manager issuer in kubemq (for a cluster issuer, add kind: ClusterIssuer); YOUR_KUBE_CONTEXT — your cluster's kubectl context.
At first install only, before kmq step 2, add two fields to kubernetes.json:
{
"schema_version": 1,
"goal": "production",
"target": "kubernetes",
"name": "messaging",
"credential": "YOUR_LICENSE_REF",
"kubernetes": {
"context": "YOUR_KUBE_CONTEXT",
"namespace": "kubemq",
"operator_release": "kubemq-operator",
"cluster_release": "messaging",
"server_count": 3,
"storage_class": "YOUR_STORAGE_CLASS",
"volume_size": "20Gi",
"tls_secret": "messaging-api-tls",
"ca_file": "YOUR_CA_FILE"
}
}Replace: YOUR_CA_FILE — your issuing authority's certificate; YOUR_LICENSE_REF, YOUR_KUBE_CONTEXT, YOUR_STORAGE_CLASS — as in kmq step 1.
On a cluster kmq already installed, contact support.
The Helm install already sets tlsSecret: messaging-api-tls. To rotate the certificate, replace the certificate, key and authority file at the same paths. Then replace the Secret, explicitly restart the StatefulSet and verify that the new revision finishes rolling out:
OLD_REVISION="$(kubectl --context YOUR_KUBE_CONTEXT -n kubemq get statefulset messaging -o jsonpath='{.status.currentRevision}')"
kubectl --context YOUR_KUBE_CONTEXT -n kubemq create secret tls messaging-api-tls --cert=YOUR_TLS_CERT_FILE --key=YOUR_TLS_KEY_FILE --dry-run=client -o yaml | kubectl --context YOUR_KUBE_CONTEXT apply -f -
kubectl --context YOUR_KUBE_CONTEXT -n kubemq rollout restart statefulset/messaging
kubectl --context YOUR_KUBE_CONTEXT -n kubemq rollout status statefulset/messaging --timeout=10m
NEW_REVISION="$(kubectl --context YOUR_KUBE_CONTEXT -n kubemq get statefulset messaging -o jsonpath='{.status.currentRevision}')"
[ -n "$NEW_REVISION" ] && [ "$NEW_REVISION" != "$OLD_REVISION" ] || { echo "The certificate restart did not finish a new StatefulSet revision." >&2; exit 1; }Replace: YOUR_TLS_CERT_FILE — the replacement certificate; YOUR_TLS_KEY_FILE — its key; YOUR_KUBE_CONTEXT — your cluster's kubectl context. Restart the Terminal 2 port-forward after the rollout. The saved context verifies the new authority file on its next request.
If something goes wrong
Replace: YOUR_KUBE_CONTEXT — your cluster's kubectl context.
- Pods stay
Pending.kubectl --context YOUR_KUBE_CONTEXT -n kubemq describe pod messaging-0says why: usually storage or too few nodes; see Requirements and supported setups. ImagePullBackOff. The nodes cannot reach the registry; see Requirements and supported setups or Install air-gapped.credential_storage_unavailable. On Linux with no keyring, add--credential-backend fileto everykmq trial,kmq license,kmq deployandkmq authcommand.- A server stops with a licensing message.
kubectl --context YOUR_KUBE_CONTEXT -n kubemq logs messaging-0prints a Troubleshooting link, such as#cluster-over-cap.
Next steps
Was this page helpful?
Install with Docker
Keep the KubeMQ server you started with Docker: add a license key with docker run, Compose or Podman, check the license and remove it safely.
Install air-gapped
Install a KubeMQ cluster on Kubernetes with no internet access: request and apply an offline license file, then install from the KubeMQ support bundle.