Installing Brokkr
This guide will help you install Brokkr using Helm, the recommended installation method.
Prerequisites
Section titled “Prerequisites”Install the tools in Prerequisites: To evaluate or install with Helm.
Verifying Prerequisites
Section titled “Verifying Prerequisites”# Check Kubernetes versionkubectl version
# Check Helm versionhelm version --short
# Verify cluster accesskubectl cluster-infoQuick Start
Section titled “Quick Start”Get a broker and agent running in your cluster in under 10 minutes.
This walkthrough passes credentials as plaintext --set values, which is the fastest way to see Brokkr working on a throwaway cluster. Values set that way are rendered into ConfigMaps in cleartext, so for anything you intend to keep, use Production Install: Credentials from Kubernetes Secrets instead — the steps are the same shape, with each credential read from a Secret you create first.
1. Generate the Admin PAK
Section titled “1. Generate the Admin PAK”Every /api/v1 request must carry a PAK (Prefixed API Key) in the Authorization header. The broker stores the hash of the admin PAK on its first startup. Generate the PAK and its hash before you install the broker.
brokkr-broker generate-pakYou do not need a source checkout or a Rust toolchain for this. brokkr-broker is the same binary the broker image runs as its entrypoint, so if you are installing by Helm alone, run the command straight from the published image:
docker run --rm ghcr.io/colliery-io/brokkr-broker:latest generate-pakSubstitute the release tag you intend to deploy if you are pinning the image rather than tracking latest. The command is entirely offline — no database, no cluster, no keyfile — so it is safe to run on a laptop before the broker exists. Everywhere this guide says brokkr-broker generate-pak, either form works.
The command prints the PAK and its SHA-256 hash. Keep the PAK secret. You cannot get the PAK back from the hash. Export both values for the steps below:
export ADMIN_PAK="<pak-from-generate-pak>"export ADMIN_PAK_HASH="<hash-from-generate-pak>"Warning: Do not install the broker without a hash. If you omit
broker.pakHashandbroker.pakHashExistingSecret, the broker uses the hash in its embedded default configuration. The matching admin PAK,brokkr_BR3rVsDa_GK3QN7CDUzYc6iKgMkJ98M2WSimM5t6U8, is public. A restart does not replace that hash, because the broker runs the admin bootstrap only on its first startup. An emptybroker.pakHashis the same as no value: the chart renders the variable only when the value is not empty.
2. Install the Broker
Section titled “2. Install the Broker”Install the broker with bundled PostgreSQL for development. Give it the hash from step 1:
# Install broker with bundled PostgreSQL and your admin PAK hashhelm install brokkr-broker oci://ghcr.io/colliery-io/charts/brokkr-broker \ --set postgresql.enabled=true \ --set broker.pakHash="$ADMIN_PAK_HASH" \ --wait
# Verify broker is runningkubectl get pods -l app.kubernetes.io/name=brokkr-brokerExpected output:
NAME READY STATUS RESTARTS AGEbrokkr-broker-xxxxxxxxxx-xxxxx 1/1 Running 0 2mOn its first startup the broker stores the hash on the admin role. The PAK in $ADMIN_PAK is now your admin credential.
3. Get Broker URL
Section titled “3. Get Broker URL”# Port forward to access the broker locallykubectl port-forward svc/brokkr-broker 3000:3000 &
# The broker is now accessible at http://localhost:3000Make sure that your admin PAK works:
curl -s http://localhost:3000/api/v1/agents -H "Authorization: Bearer $ADMIN_PAK"The command prints a JSON list. A 401 response tells you that the broker did not get your hash. To see the hash that the broker got, run kubectl exec deploy/brokkr-broker -- printenv BROKKR__BROKER__PAK_HASH.
If you lose the admin PAK, you cannot recover it from the stored hash. Mint a replacement with brokkr-broker generate-pak, update broker.pakHash (or the Secret behind broker.pakHashExistingSecret), and run brokkr-broker rotate admin against the broker’s database to store the new hash. Restarting the broker does not re-run the admin bootstrap. See Managing PAKs.
4. Create an Agent and Get Its PAK
Section titled “4. Create an Agent and Get Its PAK”Create an agent registration and retrieve its PAK:
# Create a new agentcurl -X POST http://localhost:3000/api/v1/agents \ -H "Authorization: Bearer $ADMIN_PAK" \ -H "Content-Type: application/json" \ -d '{ "name": "my-agent", "cluster_name": "development" }'You can optionally pre-register the agent with application generators at creation by adding "generator_ids": ["<uuid>", ...] to the request body. If omitted, the agent is registered only with the system/fleet generator and must be registered with an application generator separately before stacks owned by that generator can be targeted at it. See Registering Agents with Generators.
The response wraps the agent record and the one-time PAK in initial_pak:
{ "agent": { "id": "550e8400-e29b-41d4-a716-446655440000", "name": "my-agent", "cluster_name": "development", "status": "INACTIVE" }, "initial_pak": "brokkr_BRxxxxxxxx_yyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyyy"}Save the initial_pak value (jq -r '.initial_pak') — it is shown only once; you’ll need it to install the agent.
Note the "status": "INACTIVE" in the response: every new agent starts inactive. The agent reads its own status and applies nothing until you activate it. The broker does not stop the work; the agent does (see Agent Status Is Not an Access Control). You’ll activate this agent in the Test Deployment section before deploying anything through it.
5. Install the Agent
Section titled “5. Install the Agent”Install the agent using the initial_pak from step 4. The broker.agentName and broker.clusterName values must exactly match the name and cluster you registered in step 4 — at startup the agent looks up its own registration by that pair, and a mismatch leaves the pod crashlooping with “Agent not found”.
Warning: the default agent install changes the whole cluster. With the chart defaults, a pre-install hook Job installs Tekton Pipelines and Shipwright Build cluster-wide. The Job runs under a ServiceAccount with a
cluster-adminClusterRoleBinding.helm uninstalldoes not remove Tekton or Shipwright. If you do not use build work orders, add--set shipwright.enabled=false. If Tekton and Shipwright are already in the cluster, add--set shipwright.install.tekton=false --set shipwright.install.shipwright=false. For the full list of effects, see What a Default Install Does to Your Cluster.
# Install agent (replace <PAK> with the initial_pak from step 4)helm install brokkr-agent oci://ghcr.io/colliery-io/charts/brokkr-agent \ --set broker.url=http://brokkr-broker:3000 \ --set broker.pak="<PAK>" \ --set broker.agentName=my-agent \ --set broker.clusterName=development \ --wait
# Verify agent is runningkubectl get pods -l app.kubernetes.io/name=brokkr-agentExpected output:
NAME READY STATUS RESTARTS AGEbrokkr-agent-xxxxxxxxxxx-xxxxx 1/1 Running 0 1m6. Verify Installation
Section titled “6. Verify Installation”Check that both components are healthy:
# Check broker healthkubectl exec deploy/brokkr-broker -- curl -fsS http://localhost:3000/healthz
# Check agent healthkubectl exec deploy/brokkr-agent -- curl -fsS http://localhost:8080/healthz
# View agent registration in broker logskubectl logs deploy/brokkr-broker | grep -i agentYou should see “OK” from both health checks and agent registration messages in the broker logs.
Both images are debian:bookworm-slim with curl installed and no wget, so curl is the tool to reach for in any in-pod check.
Production Install: Credentials from Kubernetes Secrets
Section titled “Production Install: Credentials from Kubernetes Secrets”Four values the charts accept are credentials: the database connection URL, the admin PAK hash, the webhook encryption key, and the agent’s PAK. Set as plaintext Helm values, each one is rendered into a ConfigMap — readable by anything with get configmap in the namespace, and preserved in your values files, in helm get values, and in git history if the values file is committed.
Both charts can instead read each credential from a Kubernetes Secret you create beforehand. When you set the matching existingSecret value, the chart leaves the credential out of the ConfigMap and injects it into the pod with a secretKeyRef. That omission is the observable difference, and it is worth checking after the install. This is the recommended path for any install you intend to keep, and the natural fit for GitOps: your values carry only the name of the Secret. It also pairs with tools like external-secrets-operator, which vend the credential from Vault, 1Password, or a cloud secret manager into the Secret at deploy time.
Create the Secrets before installing. A Secret or key that does not exist leaves the pod stuck in CreateContainerConfigError — Kubernetes cannot start a container whose environment it cannot resolve.
Install a recent enough chart. Most of these
existingSecretvalues are new, and Helm silently ignores values a chart does not know about: pin an older chart and the install appears to succeed while the credential goes into the ConfigMap in plaintext anyway. Thehelm installcommands on this page carry no--version, so Helm resolves the newest published chart and you are fine. If you pin versions, check the minimum in Chart Versions and theexistingSecretValues first, and verify the ConfigMap afterwards as shown below — that check is what catches the mistake.
1. Create the Broker Secrets
Section titled “1. Create the Broker Secrets”# Database connection URL — the full postgres:// URL, not its partskubectl create secret generic brokkr-broker-db \ --from-literal=database-url='postgres://brokkr:<password>@postgres.example.com:5432/brokkr'
# Admin PAK hash, from `brokkr-broker generate-pak` (see Quick Start step 1)kubectl create secret generic brokkr-broker-admin-pak-hash \ --from-literal=BROKKR__BROKER__PAK_HASH='<hash-from-generate-pak>'
# Webhook encryption key — 64 hex characters (32 bytes)kubectl create secret generic brokkr-broker-webhook-key \ --from-literal=BROKKR__BROKER__WEBHOOK_ENCRYPTION_KEY="$(openssl rand -hex 32)"The key names above are the chart defaults, so nothing else is needed to point at them. If your secret manager writes different key names, set the matching *ExistingSecretKey value instead of renaming the key.
2. Install the Broker
Section titled “2. Install the Broker”helm install brokkr-broker oci://ghcr.io/colliery-io/charts/brokkr-broker \ --set postgresql.enabled=false \ --set postgresql.existingSecret=brokkr-broker-db \ --set broker.pakHashExistingSecret=brokkr-broker-admin-pak-hash \ --set broker.webhookEncryptionKeyExistingSecret=brokkr-broker-webhook-key \ --waitConfirm no credential reached the ConfigMap:
kubectl get configmap brokkr-broker -o yamlBROKKR__DATABASE__URL, BROKKR__BROKER__PAK_HASH, and BROKKR__BROKER__WEBHOOK_ENCRYPTION_KEY should all be absent from the output. Each is present in the pod’s environment instead:
kubectl exec deploy/brokkr-broker -- printenv BROKKR__BROKER__PAK_HASHSourcing the webhook encryption key this way also heads off a hard failure later. With no key configured, the broker generates a fresh random key on every start and warns about it; once at least one webhook subscription exists, a broker that starts with the key unset refuses to start rather than come up unable to decrypt those subscriptions’ stored URLs and auth headers. See Configuring Webhooks.
3. Create the Agent Secret and Install
Section titled “3. Create the Agent Secret and Install”Register the agent through the broker API first (Quick Start step 4), then put the returned initial_pak in a Secret rather than on the helm install command line, where it would be visible in your shell history and in the agent’s ConfigMap:
kubectl create secret generic brokkr-agent-credentials \ --from-literal=BROKKR__AGENT__PAK='<initial_pak>'
helm install brokkr-agent oci://ghcr.io/colliery-io/charts/brokkr-agent \ --set broker.url=http://brokkr-broker:3000 \ --set broker.existingSecret=brokkr-agent-credentials \ --set broker.agentName=my-agent \ --set broker.clusterName=development \ --waitWith broker.existingSecret set, the agent ConfigMap’s BROKKR__AGENT__PAK renders as an empty string and the secretKeyRef in the Deployment supplies the real value, so the PAK itself never appears in the ConfigMap or in your values.
Existing-Secret Values Reference
Section titled “Existing-Secret Values Reference”| Chart | Values | Credential | Default key in the Secret |
|---|---|---|---|
| Broker | postgresql.existingSecret / postgresql.existingSecretKey |
Full PostgreSQL connection URL (BROKKR__DATABASE__URL) |
database-url |
| Broker | broker.pakHashExistingSecret / broker.pakHashExistingSecretKey |
Admin PAK hash (BROKKR__BROKER__PAK_HASH) |
BROKKR__BROKER__PAK_HASH |
| Broker | broker.webhookEncryptionKeyExistingSecret / broker.webhookEncryptionKeyExistingSecretKey |
Webhook encryption key (BROKKR__BROKER__WEBHOOK_ENCRYPTION_KEY) |
BROKKR__BROKER__WEBHOOK_ENCRYPTION_KEY |
| Agent | broker.existingSecret / broker.existingSecretKey |
Agent PAK (BROKKR__AGENT__PAK) |
BROKKR__AGENT__PAK |
In every case the existingSecret value wins. When it is set, the plaintext value it replaces — the connection URL the chart would otherwise assemble from postgresql.external.* or the bundled database’s credentials, broker.pakHash, broker.webhookEncryptionKey, or the agent’s broker.pak — is ignored, the credential is left out of the ConfigMap, and the pod receives it through secretKeyRef. postgresql.existingSecret applies whether the database is bundled or external.
You can mix the two: source the admin PAK hash from a Secret while leaving a development database URL as a plain value, for example. Each pair is independent.
Detailed Installation
Section titled “Detailed Installation”Broker Installation
Section titled “Broker Installation”The broker is the central management service that coordinates deployments across your Kubernetes clusters.
Development Setup (Bundled PostgreSQL)
Section titled “Development Setup (Bundled PostgreSQL)”For development and testing, use the bundled PostgreSQL. The password below is rendered into the broker’s ConfigMap as part of BROKKR__DATABASE__URL, so keep this form to dev and test clusters and use postgresql.existingSecret elsewhere:
helm install brokkr-broker oci://ghcr.io/colliery-io/charts/brokkr-broker \ --set postgresql.enabled=true \ --set postgresql.auth.password=brokkr \ --set broker.pakHash="$ADMIN_PAK_HASH" \ --waitEvery broker install on this page sets the admin PAK hash. Get the hash from brokkr-broker generate-pak, as in Quick Start step 1. The values files do not set a hash.
Using Provided Values Files
Section titled “Using Provided Values Files”Brokkr includes pre-configured values files for different environments — development (bundled PostgreSQL, minimal resources), staging (external PostgreSQL, moderate resources), and production (external PostgreSQL, production-grade resources). Install with the one for your environment:
helm install brokkr-broker oci://ghcr.io/colliery-io/charts/brokkr-broker \ --set broker.pakHash="$ADMIN_PAK_HASH" \ -f https://raw.githubusercontent.com/colliery-io/brokkr/main/charts/brokkr-broker/values/<environment>.yamlFor staging and production, use --set broker.pakHashExistingSecret=<secret-name> instead of broker.pakHash. See Production Install.
You can also download these files and customize them:
# Download development valuescurl -O https://raw.githubusercontent.com/colliery-io/brokkr/main/charts/brokkr-broker/values/development.yaml
# Edit as neededvi development.yaml
# Install with custom valueshelm install brokkr-broker oci://ghcr.io/colliery-io/charts/brokkr-broker \ --set broker.pakHash="$ADMIN_PAK_HASH" \ -f development.yamlView all available values files:
Agent Installation
Section titled “Agent Installation”The agent runs in each Kubernetes cluster you want to manage and communicates with the broker.
Basic Agent Installation
Section titled “Basic Agent Installation”Passing the PAK with --set broker.pak renders it into the agent’s ConfigMap in plaintext — acceptable for dev and test, but for anything longer-lived source it from a Secret with broker.existingSecret as shown in Production Install.
# Create agent via broker API (see Quick Start step 4)# Then install with the returned initial_pak.# agentName and clusterName must match the created agent exactly,# or the agent's startup self-lookup fails and the pod crashloops.
helm install brokkr-agent oci://ghcr.io/colliery-io/charts/brokkr-agent \ --set broker.url=http://brokkr-broker:3000 \ --set broker.pak="<PAK_FROM_BROKER>" \ --set broker.agentName=<AGENT_NAME> \ --set broker.clusterName=<CLUSTER_NAME> \ --waitThis install and the values-file install below keep the chart default shipwright.enabled=true. Thus they also install Tekton and Shipwright cluster-wide with a cluster-admin binding, as the warning in Quick Start step 5 tells. Add --set shipwright.enabled=false if you do not use build work orders.
Using Provided Values Files
Section titled “Using Provided Values Files”Brokkr includes pre-configured values files for agents — development (minimal resources, cluster-wide RBAC), staging (moderate resources), and production (production-grade resources). Install with the one for your environment:
helm install brokkr-agent oci://ghcr.io/colliery-io/charts/brokkr-agent \ --set broker.url=http://brokkr-broker:3000 \ --set broker.pak="<PAK>" \ --set broker.agentName=<AGENT_NAME> \ --set broker.clusterName=<CLUSTER_NAME> \ -f https://raw.githubusercontent.com/colliery-io/brokkr/main/charts/brokkr-agent/values/<environment>.yamlView all available agent values files:
Chart Versions, Upgrades, and Uninstallation
Section titled “Chart Versions, Upgrades, and Uninstallation”Every helm install on this page is unpinned, so Helm pulls the newest published chart — the right default, and the one that supports everything documented here. For pinning to a specific version (and the minimum version the existingSecret values need), installing development builds, upgrading, and uninstalling, see Installing, Upgrading, and Uninstalling with Helm.
Verifying the Installation
Section titled “Verifying the Installation”For the broker/agent health checks and connectivity verification, see Quick Start step 6.
Test Deployment
Section titled “Test Deployment”Create a test namespace to verify end-to-end functionality:
# Port forward to brokerkubectl port-forward svc/brokkr-broker 3000:3000 &
# Stacks require an owning generator. Look up the admin-generator the broker# created at first startup (it is linked to the admin PAK):GEN_ID=$(curl -s http://localhost:3000/api/v1/generators \ -H "Authorization: Bearer $ADMIN_PAK" \ | jq -r '.[] | select(.name=="admin-generator") | .id')
# Create a stackSTACK_ID=$(curl -s -X POST http://localhost:3000/api/v1/stacks \ -H "Authorization: Bearer $ADMIN_PAK" \ -H "Content-Type: application/json" \ -d "{\"name\": \"test-stack\", \"description\": \"Test stack\", \"generator_id\": \"$GEN_ID\"}" \ | jq -r '.id')
# Target your agent to the stack so it receives the deploymentAGENT_ID=$(curl -s http://localhost:3000/api/v1/agents \ -H "Authorization: Bearer $ADMIN_PAK" | jq -r '.[0].id')
# New agents start INACTIVE and skip all deployment work until activated.# Activate yours so it will pull and reconcile deployment objects:curl -X PUT http://localhost:3000/api/v1/agents/$AGENT_ID \ -H "Authorization: Bearer $ADMIN_PAK" \ -H "Content-Type: application/json" \ -d '{"status": "ACTIVE"}'
# Register the agent with the admin-generator first. Targeting a stack at an# agent that is not registered with the stack's owning generator returns# 403 agent_not_registered. (Skip this if you passed generator_ids at# agent creation.) See ../how-to/agent-registration.md.curl -X POST http://localhost:3000/api/v1/generators/$GEN_ID/register \ -H "Authorization: Bearer $ADMIN_PAK" \ -H "Content-Type: application/json" \ -d "{\"agent_id\": \"$AGENT_ID\"}"
curl -X POST http://localhost:3000/api/v1/agents/$AGENT_ID/targets \ -H "Authorization: Bearer $ADMIN_PAK" \ -H "Content-Type: application/json" \ -d "{\"agent_id\": \"$AGENT_ID\", \"stack_id\": \"$STACK_ID\"}"
# Deploy a test namespacecurl -X POST http://localhost:3000/api/v1/stacks/$STACK_ID/deployment-objects \ -H "Authorization: Bearer $ADMIN_PAK" \ -H "Content-Type: application/json" \ -d '{ "yaml_content": "apiVersion: v1\nkind: Namespace\nmetadata:\n name: brokkr-test", "is_deletion_marker": false }'
# Allow one poll cycle (the chart's default agent.pollingInterval is 30s),# then verify the namespace was createdkubectl get namespace brokkr-test
# Clean upcurl -X POST http://localhost:3000/api/v1/stacks/$STACK_ID/deployment-objects \ -H "Authorization: Bearer $ADMIN_PAK" \ -H "Content-Type: application/json" \ -d '{ "yaml_content": "apiVersion: v1\nkind: Namespace\nmetadata:\n name: brokkr-test", "is_deletion_marker": true }'
kubectl get namespace brokkr-test # After the next poll cycle: Terminating/NotFoundConfiguration Reference
Section titled “Configuration Reference”Broker Values
Section titled “Broker Values”Key configuration options for the broker chart:
| Parameter | Description | Default |
|---|---|---|
postgresql.enabled |
Enable bundled PostgreSQL | true |
postgresql.auth.password |
PostgreSQL password (bundled) | brokkr |
postgresql.external.host |
External database host | "" |
postgresql.external.port |
External database port | 5432 |
postgresql.external.database |
Database name | brokkr |
postgresql.external.username |
Database username | brokkr |
postgresql.external.password |
Database password | brokkr |
postgresql.external.schema |
PostgreSQL schema (multi-tenant) | "" |
replicaCount |
Number of broker replicas | 1 |
image.tag |
Image tag to use | latest |
broker.logLevel |
Log level | info |
broker.webhookEncryptionKey |
Hex-encoded 32-byte key for webhook secrets at rest; a random key is generated on every boot if unset. Rendered into the ConfigMap in plaintext — prefer broker.webhookEncryptionKeyExistingSecret |
unset |
configReload.enabled |
Mount the hot-reload settings (broker.logLevel, broker.diagnostic*, broker.webhookDelivery*, broker.webhookCleanupRetentionDays) as a file and watch it, so they apply without a pod restart. broker.logLevel does not reload when RUST_LOG is set in extraEnv. All other values need a restart. See Hot-Reload Configuration |
true |
configReload.debounceSeconds |
Time the broker waits after a file change before it reloads, in seconds | 5 |
serviceAccount.create |
Create a ServiceAccount for the broker pod. When false, the pod uses serviceAccount.name, or the namespace default account when the name is empty. The chart creates no Role or RoleBinding: the broker does not call the Kubernetes API |
true |
serviceAccount.name |
ServiceAccount name. When empty, the chart makes a name from the release name | "" |
serviceAccount.annotations |
Annotations for the ServiceAccount, for example a cloud IAM role binding | {} |
resources.limits.cpu |
CPU limit | 500m |
resources.limits.memory |
Memory limit | 512Mi |
ingress.tls |
TLS termination for the ingress — the broker itself serves plain HTTP and cannot terminate TLS | unset |
The credential values that can be sourced from a pre-created Secret instead — the database URL, the admin PAK hash, and the webhook encryption key — are listed in the Existing-Secret Values Reference.
Agent Values
Section titled “Agent Values”Key configuration options for the agent chart:
| Parameter | Description | Default |
|---|---|---|
broker.url |
Broker URL | http://brokkr-broker:3000 |
broker.pak |
Agent PAK (Prefixed API Key). Rendered into the ConfigMap in plaintext (dev/test); ignored when broker.existingSecret is set |
Required unless broker.existingSecret is set |
broker.existingSecret |
Name of a pre-created Secret to read the agent PAK from; injected via secretKeyRef and kept out of the ConfigMap. See the Existing-Secret Values Reference |
"" |
broker.existingSecretKey |
Key within that Secret holding the PAK | BROKKR__AGENT__PAK |
broker.generatorIds |
Generator UUIDs (YAML list or comma string) this agent self-registers with at startup. The agent is always auto-registered with the system/fleet generator; application generators must be listed here to serve their stacks. See Registering Agents with Generators | [] |
broker.agentName |
Agent name. Required. Must match the name of the agent record on the broker |
"" |
broker.clusterName |
Cluster name. Required. Must match the cluster_name of the agent record on the broker |
"" |
agent.pollingInterval |
Seconds between broker polls (the agent binary’s own default is 10) |
30 |
agent.deploymentHealth.enabled |
Enable deployment health checks | true |
agent.deploymentHealth.intervalSeconds |
Health check interval | 60 |
rbac.create |
Create RBAC resources | true |
rbac.clusterWide |
Cluster-wide RBAC (vs namespaced) | true |
rbac.secretAccess.enabled |
Enable secret access | false |
resources.limits.cpu |
CPU limit | 200m |
resources.limits.memory |
Memory limit | 256Mi |
image.tag |
Image tag to use | latest |
Note on rbac.clusterWide: Namespace-scoped mode (rbac.clusterWide: false) deploys within its namespace, and the chart automatically sets BROKKR__AGENT__WATCH_NAMESPACE so telemetry streaming and health discovery operate in-namespace too. Remaining constraints: reconciliation pruning skips resource types it cannot list, and stacks containing cluster-scoped resources (Namespaces, CRDs) fail to apply. See the agent chart’s RBAC documentation.
For complete configuration options, see the chart values files:
Production Checklist
Section titled “Production Checklist”These defaults and shortcuts are safe for development but dangerous in production:
- Replace the default admin PAK. The default configuration embeds a publicly known
broker.pak_hash— leaving it in place means anyone can use the development admin credential against your broker. Runbrokkr-broker generate-pak— from the broker image if you have no binary,docker run --rm ghcr.io/colliery-io/brokkr-broker:latest generate-pak(see Generate the Admin PAK) — and set the printed hash viabroker.pakHashExistingSecret(or, on a dev cluster, as the plaintextbroker.pakHash) before first startup. Leaving the chart value empty does not generate a fresh key; it silently keeps the publicly known default active. - Set a persistent webhook encryption key. If
broker.webhook_encryption_key(BROKKR__BROKER__WEBHOOK_ENCRYPTION_KEY, 64 hex chars / 32 bytes) is unset, the broker generates a random key on every startup — webhook URLs and auth headers encrypted under the previous key become unreadable after a restart, and once subscriptions exist the broker refuses to start with the key unset. Source it from a Secret withbroker.webhookEncryptionKeyExistingSecret. - Keep credentials out of ConfigMaps. The database URL, admin PAK hash, webhook encryption key, and agent PAK all land in a ConfigMap in cleartext when set as plaintext Helm values. Source each from a pre-created Secret instead — see Production Install: Credentials from Kubernetes Secrets.
- Lower the log level. The binary default is
debug; the Helm chart setsbroker.logLevel: info. If you run the binary outside the chart, setBROKKR__LOG__LEVEL=info(orwarn).
See the Configuration Guide for details on each setting.
Next Steps
Section titled “Next Steps”- Follow the Deploy Your First Application tutorial to deploy your first application
- Learn about Basic Concepts in Brokkr
- Explore Configuration Guide
Troubleshooting
Section titled “Troubleshooting”Common Issues
Section titled “Common Issues”Broker pod not starting:
# Check pod statuskubectl describe pod -l app.kubernetes.io/name=brokkr-broker
# Check logskubectl logs -l app.kubernetes.io/name=brokkr-brokerAgent not connecting to broker:
# Verify broker URL is accessible from agentkubectl exec deploy/brokkr-agent -- curl -fsS http://brokkr-broker:3000/healthz
# Check agent logs for connection errorskubectl logs -l app.kubernetes.io/name=brokkr-agentPod stuck in CreateContainerConfigError:
A pod that never starts a container is usually missing a Secret it was told to read. Kubernetes cannot resolve the environment, so it never gets as far as running the image.
# The event names the missing Secret or keykubectl describe pod -l app.kubernetes.io/name=brokkr-broker | tail -20
# Confirm the Secret exists and holds the expected keykubectl get secret <secret-name> -o jsonpath='{.data}' | jq 'keys'Check the key name against the defaults in the Existing-Secret Values Reference, and set the matching *ExistingSecretKey value if your Secret uses a different one.
Database connection errors:
# Check PostgreSQL is runningkubectl get pods -l app.kubernetes.io/name=postgresql
# Check database credentialskubectl get secret brokkr-broker-postgresql -o yamlPAK authentication failures:
- Verify the PAK is correct. PAKs have no expiry — a key that used to work has been rotated or revoked (its agent or generator was deleted)
- Check that the agent name matches the registration
- Ensure the broker URL is accessible
Getting Help
Section titled “Getting Help”- Check our GitHub Issues for known issues and solutions
Building from Source
Section titled “Building from Source”For contributors or anyone building Brokkr from source and running it locally, see the Local Development Environment guide.