KubeMQ
DeployInstall

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-private
cd 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 storageclass

Replace: YOUR_KUBE_CONTEXT — your cluster's kubectl context, from kubectl config get-contexts.

You should see:

Output
HARNESS_OUTPUT_PENDING

Node 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.key

This file is a secret. Do not commit it, paste it into chat, or attach it to a support ticket.

kmq license import --file license.key

You should see:

Output
HARNESS_OUTPUT_PENDING

kmq 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:

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"
  }
}

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.json

Write 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.json

Prepare the resolved input:

kmq deploy prepare --input kubernetes.json --out prepared.json --deadline 10m

You should see:

Output
HARNESS_OUTPUT_PENDING

It creates the namespace, a license Secret and a management certificate Secret that kmq trusts.

kmq deploy plan --input prepared.json --out plan.json

You should see:

Output
HARNESS_OUTPUT_PENDING

Install the operator and the cluster

kmq deploy apply --plan plan.json --deadline 15m

You should see:

Output
HARNESS_OUTPUT_PENDING

After 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:

Output
HARNESS_OUTPUT_PENDING

Store 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.key

Replace: YOUR_LICENSE_REF — your license reference.

You should see:

Output
HARNESS_OUTPUT_PENDING

Create 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:

Output
HARNESS_OUTPUT_PENDING

Create 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-next
helm repo update kubemq-next
helm upgrade --install kubemq-operator kubemq-next/kubemq-next \
  --kube-context YOUR_KUBE_CONTEXT \
  -n kubemq \
  --set operator.enabled=true \
  --set cluster.enabled=false \
  --wait

You should see:

Output
HARNESS_OUTPUT_PENDING

Install the cluster

In kubemq-private:

cluster-values.yaml
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.yaml

You should see:

Output
HARNESS_OUTPUT_PENDING

Then wait until every server is ready:

kubectl --context YOUR_KUBE_CONTEXT -n kubemq wait --for=condition=Ready kubemqclusters.next.kubemq.io/messaging --timeout=10m

You should see:

Output
HARNESS_OUTPUT_PENDING

Check the license the operator reports:

kubectl --context YOUR_KUBE_CONTEXT -n kubemq describe kubemqclusters.next.kubemq.io messaging

You should see:

Output
HARNESS_OUTPUT_PENDING

Check 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

Terminal 2
kubectl --context YOUR_KUBE_CONTEXT -n kubemq port-forward pod/messaging-0 18080:8080

Replace: YOUR_KUBE_CONTEXT — your cluster's kubectl context.

You should see:

Output
HARNESS_OUTPUT_PENDING

Leave it running.

Sign in

kmq auth login --bootstrap --installation YOUR_INSTALLATION_ID --username admin --api-address https://127.0.0.1:18080

Replace: 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:

Output
HARNESS_OUTPUT_PENDING

Save 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-password
kmq auth login --username admin --api-address https://127.0.0.1:18080 --ca-file YOUR_CA_FILE --context-name messaging --service-name messaging-kmq-tls

Replace: 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:

Output
HARNESS_OUTPUT_PENDING

Security: 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 messaging

You should see:

Output
HARNESS_OUTPUT_PENDING

Confirm 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:

Output
HARNESS_OUTPUT_PENDING
kmq queue receive onboarding-check

You should see:

Output
HARNESS_OUTPUT_PENDING

Connect your applications

Applications inside the cluster use these Services, all ClusterIP:

InterfaceIn-cluster addressPort
gRPCmessaging-grpc.kubemq.svc.cluster.local50000
RESTmessaging-rest.kubemq.svc.cluster.local9090
Kafka-compatiblemessaging-kafka.kubemq.svc.cluster.local9092
RabbitMQ-compatible (AMQP 0-9-1)messaging-amqp.kubemq.svc.cluster.local5672

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=10m

Replace: 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:

Output
HARNESS_OUTPUT_PENDING

Put 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=10m

Replace: 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 15m

Replace: YOUR_INSTALLATION_ID — the installation_id value that kmq onboard or kmq deploy apply printed.

You should see:

Output
HARNESS_OUTPUT_PENDING

Helm keeps the cluster resource, so delete it first:

kubectl --context YOUR_KUBE_CONTEXT -n kubemq delete kubemqclusters.next.kubemq.io messaging --wait
helm uninstall messaging --kube-context YOUR_KUBE_CONTEXT -n kubemq

Both keep the volumes and the operator. Remove the operator once no cluster uses it:

helm uninstall kubemq-operator --kube-context YOUR_KUBE_CONTEXT -n kubemq

Replace: 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:

management-certificate.yaml
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_ISSUER
kubectl --context YOUR_KUBE_CONTEXT -n kubemq apply -f management-certificate.yaml

Replace: 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:

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-0 says 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 file to every kmq trial, kmq license, kmq deploy and kmq auth command.
  • A server stops with a licensing message. kubectl --context YOUR_KUBE_CONTEXT -n kubemq logs messaging-0 prints a Troubleshooting link, such as #cluster-over-cap.

Next steps

Was this page helpful?

On this page