Skip to content

Evaluate Brokkr Locally

This page gets you from zero to a working Brokkr deployment fast, so you can decide whether it fits your needs. It offers two paths — pick one:

  • Path A — Fastest look — one command builds the stack from source and bundles its own Kubernetes (k3s); nothing to install but Docker.
  • Path B — Realistic evaluation — Helm installs the published images onto a local cluster you bring yourself (kind or k3d); no source build.

Both paths end with an agent reconciling a real Kubernetes resource onto a cluster.

Along the way you will meet Brokkr’s five nouns — generator, agent, stack, deployment object, and target. You can follow either path without knowing them, since every command below says what it is doing, but if you would rather have the model first, read Core Concepts — it takes a few minutes and makes the rest of the book easier to navigate.


Path A — Fastest look (angreal local up)

Section titled “Path A — Fastest look (angreal local up)”

This path builds Brokkr from source and runs the full broker + agent + k3s + local registry stack in Docker. It is the quickest way to a working playground, building container images from the repo.

Install the tools in Prerequisites: To evaluate with angreal local up.

The first angreal local up compiles the broker and agent from source — usually 5–15 minutes depending on your machine and Docker cache. Docker streams the build output to your terminal as it works, so you can watch it make progress (subsequent runs are much faster once layers are cached).

One command brings up every backing service.

Terminal window
git clone https://github.com/colliery-io/brokkr.git
cd brokkr
angreal local up

This starts the brokkr-dev Docker Compose project: PostgreSQL, a local container registry, the broker, a k3s cluster (with Tekton + Shipwright), a pre-created agent, and a couple of demo containers. The first run builds images from your working tree, so give it a few minutes.

When it finishes, the command prints the URLs (the broker API and the operator console on http://localhost:3000), the dev admin PAK, and the path of the dev agent’s key. The stack has already created an agent named brokkr-integration-test-agent (cluster brokkr-dev-integration-cluster) and started an agent container for it. A second angreal local up keeps that agent, its PAK and its registrations.

If angreal local up fails: make sure Docker is running and you have enough free disk for the source build, and that ports 3000, 3001, 5050, 5433, 6443, 8474 and 18090 aren’t already in use (angreal local up names the service that could not bind; for the webhook catcher, set BROKKR_DEV_WEBHOOK_PORT to a free port). To start clean, run angreal local down --hard (removes volumes) and try again. The same stack is documented in more depth in Local Development Environment.

2. Set your admin key and confirm the broker is up

Section titled “2. Set your admin key and confirm the broker is up”

The dev broker runs with the default configuration, so the publicly known dev admin PAK (Prefixed API Key) works against it — fine for this throwaway environment, never for production.

Terminal window
export ADMIN_PAK="brokkr_BR3rVsDa_GK3QN7CDUzYc6iKgMkJ98M2WSimM5t6U8"
# The brokkr CLI reads its connection from these two variables
export BROKKR_BROKER_URL=http://localhost:3000
export BROKKR_PAK=$ADMIN_PAK
# Confirm the broker is healthy
curl http://localhost:3000/healthz

List registered agents — the pre-created agent should already be there.

Terminal window
brokkr agent list

You should see brokkr-integration-test-agent. A freshly registered agent starts with status INACTIVE. While it is INACTIVE, the agent does not ask the broker for deployment objects. The agent checks its own status: the broker does not stop the work (see Agent Status Is Not an Access Control). Until you mark it ACTIVE, the agent log says so on each poll. Activate it:

Terminal window
# Activate the agent so it will pull and reconcile deployment objects
brokkr agent activate brokkr-integration-test-agent

The output should say that the agent is ACTIVE, meaning the agent will pull and reconcile what you target to it.

The same step with curl
Terminal window
curl -s http://localhost:3000/api/v1/agents \
-H "Authorization: Bearer $ADMIN_PAK" | jq '.[] | {id, name, cluster_name, status}'
export AGENT_ID=$(curl -s http://localhost:3000/api/v1/agents \
-H "Authorization: Bearer $ADMIN_PAK" \
| jq -r '.[] | select(.name=="brokkr-integration-test-agent") | .id')
curl -s -X PUT http://localhost:3000/api/v1/agents/$AGENT_ID \
-H "Authorization: Bearer $ADMIN_PAK" \
-H "Content-Type: application/json" \
-d '{"status": "ACTIVE"}' | jq '{name, status}'

4. Deploy something and watch it reconcile

Section titled “4. Deploy something and watch it reconcile”

Create a stack, target your agent to it, and push a namespace. Stacks are owned by a generator; the broker creates an admin-generator at first startup.

Terminal window
# Look up the admin generator and create a stack owned by it
GEN_ID=$(curl -s http://localhost:3000/api/v1/generators \
-H "Authorization: Bearer $ADMIN_PAK" \
| jq -r '.[] | select(.name=="admin-generator") | .id')
STACK_ID=$(curl -s -X POST http://localhost:3000/api/v1/stacks \
-H "Authorization: Bearer $ADMIN_PAK" \
-H "Content-Type: application/json" \
-d "{\"name\": \"evaluate\", \"description\": \"Evaluation stack\", \"generator_id\": \"$GEN_ID\"}" \
| jq -r '.id')
# Register the agent with the admin-generator. An agent must be registered with a
# generator before any stack that generator owns can be targeted at it — without
# this, the next command fails with agent_not_registered. Give each one by name.
brokkr register --agent brokkr-integration-test-agent --generator admin-generator
# Now target the stack at the agent so the agent receives the deployment.
brokkr stack target evaluate brokkr-integration-test-agent
# Push a deployment object (a single namespace)
curl -s -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-evaluate", "is_deletion_marker": false}'
The register and target steps with curl
Terminal window
curl -s -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\"}"
# The body `agent_id` must match the agent id in the path. The broker rejects a mismatch with 400.
curl -s -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\"}"

The agent polls the broker on its next cycle and applies the namespace — allow one full poll cycle (about 10 seconds in this stack). Point kubectl at the bundled k3s cluster (its host kubeconfig is written to /tmp/brokkr-keys/) and verify:

Terminal window
export KUBECONFIG=/tmp/brokkr-keys/kubeconfig.local.yaml
# Visible result: the namespace your agent reconciled onto the cluster
kubectl get namespace brokkr-evaluate

Once brokkr-evaluate shows up, you have seen the full loop: an API call to the broker, an agent picking it up, and a real resource on a cluster.

The stack also serves a demo admin UI at http://localhost:3001 (from examples/ui-slim) — a demonstration of what a consumer could build on the API, not a supported product. Open it for a visual feel, but drive your actual evaluation through the API or the brokkr CLI.

Terminal window
angreal local down # stop the stack
angreal local down --hard # stop and remove volumes

Path B — Realistic evaluation (Helm on a local cluster)

Section titled “Path B — Realistic evaluation (Helm on a local cluster)”

This path installs the published images with Helm onto a local Kubernetes cluster — no source build. It mirrors a real install closely enough to evaluate operational behavior.

Install the tools in Prerequisites: To evaluate or install with Helm. You create the local cluster in the next step.

Use whichever tool you have. For example, with kind:

Terminal window
kind create cluster --name brokkr-eval

Or with k3d:

Terminal window
k3d cluster create brokkr-eval

Confirm kubectl is pointed at it:

Terminal window
kubectl cluster-info

Install the broker chart with bundled PostgreSQL. The chart pulls the published brokkr-broker image.

Warning: This evaluation install does not set an admin PAK hash. Thus the broker uses the publicly known development admin PAK. Anyone who can reach this broker can use that PAK as admin. Use this install only on a local cluster that nobody else can reach. Do not expose the broker with an Ingress, a LoadBalancer, or a port-forward on a shared host. A restart does not replace the development PAK. For any other install, follow Installing Brokkr, which sets your own hash before the first startup.

Terminal window
helm install brokkr-broker oci://ghcr.io/colliery-io/charts/brokkr-broker \
--set postgresql.enabled=true \
--wait
# Verify the broker is running
kubectl get pods -l app.kubernetes.io/name=brokkr-broker

3. Reach the broker and set your admin key

Section titled “3. Reach the broker and set your admin key”

Port-forward the broker, then export the publicly known development admin PAK. It works because the install in step 2 set no hash. It is acceptable only for this throwaway evaluation cluster, never for production.

This port-forward must stay running for every remaining step — leave it in this shell (or its own terminal) until teardown.

Terminal window
kubectl port-forward svc/brokkr-broker 3000:3000 &
export ADMIN_PAK="brokkr_BR3rVsDa_GK3QN7CDUzYc6iKgMkJ98M2WSimM5t6U8"
# The brokkr CLI reads its connection from these two variables
export BROKKR_BROKER_URL=http://localhost:3000
export BROKKR_PAK=$ADMIN_PAK
# Confirm the broker answers
curl http://localhost:3000/api/v1/agents -H "Authorization: Bearer $ADMIN_PAK"

The agent authenticates to the broker with its own one-time PAK.

Terminal window
export AGENT_PAK=$(curl -s -X POST http://localhost:3000/api/v1/agents \
-H "Authorization: Bearer $ADMIN_PAK" \
-H "Content-Type: application/json" \
-d '{"name": "eval-agent", "cluster_name": "evaluation"}' \
| jq -r '.initial_pak')
echo "$AGENT_PAK" # shown only once

Install the agent chart with the PAK from the previous step. The broker.agentName and broker.clusterName values must exactly match the agent you created in step 4 (eval-agent / evaluation) — 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-admin ClusterRoleBinding. helm uninstall does not remove Tekton or Shipwright. This evaluation does not use build work orders, so the command below sets shipwright.enabled=false. To try builds, remove that line. If Tekton and Shipwright are already in the cluster, use --set shipwright.install.tekton=false --set shipwright.install.shipwright=false instead. For the full list of effects, see What a Default Install Does to Your Cluster.

Terminal window
helm install brokkr-agent oci://ghcr.io/colliery-io/charts/brokkr-agent \
--set broker.url=http://brokkr-broker:3000 \
--set broker.pak="$AGENT_PAK" \
--set broker.agentName=eval-agent \
--set broker.clusterName=evaluation \
--set shipwright.enabled=false \
--wait
# Visible result: the agent pod is Running and the agent has registered
kubectl get pods -l app.kubernetes.io/name=brokkr-agent
curl -s http://localhost:3000/api/v1/agents \
-H "Authorization: Bearer $ADMIN_PAK" | jq '.[] | {name, cluster_name, status}'

When the agent pod is Running and eval-agent appears in the broker’s agent list, the broker and agent are talking. The agent registers as INACTIVE; you activate it in the next step before deploying.

Pre-register at creation (optional): This walkthrough registers the agent with the admin-generator as a separate step below. You can instead register at creation time by passing generator_ids to POST /agents (e.g. -d '{"name": "eval-agent", "cluster_name": "evaluation", "generator_ids": ["'$GEN_ID'"]}') or --set broker.generatorIds={$GEN_ID} on the agent helm install — then the separate register call is unnecessary. Every agent is always auto-registered with the system generator for fleet-wide stacks regardless. See Registering an Agent with a Generator.

6. Deploy a test resource and watch it reconcile

Section titled “6. Deploy a test resource and watch it reconcile”

Create a stack, target the agent, and push a namespace through the broker.

Terminal window
# Activate the agent so it will pull and reconcile deployment objects
brokkr agent activate eval-agent
GEN_ID=$(curl -s http://localhost:3000/api/v1/generators \
-H "Authorization: Bearer $ADMIN_PAK" \
| jq -r '.[] | select(.name=="admin-generator") | .id')
STACK_ID=$(curl -s -X POST http://localhost:3000/api/v1/stacks \
-H "Authorization: Bearer $ADMIN_PAK" \
-H "Content-Type: application/json" \
-d "{\"name\": \"evaluate\", \"description\": \"Evaluation stack\", \"generator_id\": \"$GEN_ID\"}" \
| jq -r '.id')
# Register the agent with the admin-generator before targeting it. Targeting a stack
# at an agent that is not registered with the stack's generator fails with agent_not_registered.
brokkr register --agent eval-agent --generator admin-generator
brokkr stack target evaluate eval-agent
curl -s -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-evaluate", "is_deletion_marker": false}'
The activate, register and target steps with curl
Terminal window
export AGENT_ID=$(curl -s http://localhost:3000/api/v1/agents \
-H "Authorization: Bearer $ADMIN_PAK" \
| jq -r '.[] | select(.name=="eval-agent") | .id')
curl -s -X PUT http://localhost:3000/api/v1/agents/$AGENT_ID \
-H "Authorization: Bearer $ADMIN_PAK" \
-H "Content-Type: application/json" \
-d '{"status": "ACTIVE"}' | jq '{name, status}'
curl -s -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\"}"
# The body `agent_id` must match the agent id in the path. The broker rejects a mismatch with 400.
curl -s -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\"}"

After the agent’s next poll, the namespace appears on your cluster — allow one full poll cycle (the chart’s default polling interval is 30 seconds):

Terminal window
# Visible result: the namespace your agent reconciled
kubectl get namespace brokkr-evaluate
Terminal window
# Stop the port-forward first (or just close the shell it runs in)
kill %1 2>/dev/null
helm uninstall brokkr-agent
helm uninstall brokkr-broker
kind delete cluster --name brokkr-eval # or: k3d cluster delete brokkr-eval

Once you have seen Brokkr work, go deeper: