Skip to content

2 · Bootstrap: local cluster

8 minutes · everyone runs this

This block assumes you did the prep

Eight minutes is enough to start a cluster whose images are already on disk. It is not enough to download Kubernetes. If you skipped Prerequisites, start make preflight now and pair up with a neighbour in the meantime.

Goal

Everyone has a running, isolated Kubernetes cluster in Docker, and knows where the agent configuration lives.

Start the cluster

Pick your environment. Everything after this point is identical whichever you choose — see Cluster environments.

make env-up ENV=codespaces   # recommended: nothing to install locally
make env-up ENV=k3d          # a local K3s cluster in Docker
make env-up ENV=byo I_UNDERSTAND_THIS_CLUSTER_IS_DISPOSABLE=yes
k3d cluster create agentic-ops \
  --agents 1 \
  --k3s-arg "--disable=traefik@server:0"
talosctl cluster create --name agentic-ops --workers 1

Talos defaults to ~2.1 GB of memory per node in Docker, which does not fit comfortably on an 8 GB laptop alongside everything else. See P3.

Verify

One command proves the whole environment contract, whichever environment you're in:

make verify
  OK    context reachable: k3d-agentic-ops
  OK    namespace 'agentic-ops' exists and is labelled as ours
  OK    service account agent-ro
  OK    service account agent-ns
  OK    service account agent-harden
  OK    agent-harden CAN patch deployments
  OK    agent-harden CANNOT delete deployments (the delete verb is absent)
  OK    no agent service account has cluster-scoped access
  OK    deployment shopfront has 2 ready replica(s)
  OK    deployment worker has 1 ready replica(s)

10 checks passed. The contract holds.

Wrong context?

make verify names the context it found. The agent inherits your active context, so this isn't pedantry — check it before giving anything write access.

Repo structure

agentic-cloud-ops/
├── Makefile              # env-up, verify, ladder, chaos, nuke
├── bootstrap/
│   ├── base/             # ONE kustomization, applied identically everywhere
│   └── env/              # codespaces.sh, k3d.sh, byo.sh — ~20 lines each
├── agents/
│   ├── prompts/          # system prompts per mode (deploy, harden, incident)
│   └── tools/            # MCP config and the agent's RBAC
├── manifests/
│   ├── insecure/         # deliberately bad deployments (Lab 2)
│   └── chaos/            # scenarios for `make chaos` (Lab 3)
├── docs/                 # this documentation
└── web/                  # the workshop landing page

The agent's access — the RBAC ladder

The agent never runs as you. It runs as one of four service accounts, each a rung:

make ladder
Rung Service account Can Cannot
0 agent-ro get, list, watch write anything
1 agent-ns + create, patch deployments/services/configmaps delete anything
2 agent-harden + NetworkPolicies, rollout control delete anything, read Secrets
3 agent-admin everything deliberately not bound to anyone

The point of the whole workshop, in one line

At rung 2 the delete verb is absent. Try it:

NS=agentic-ops
kubectl --as="system:serviceaccount:${NS}:agent-harden" -n $NS delete deploy/shopfront
Error from server (Forbidden): deployments.apps "shopfront" is forbidden:
  ... cannot delete resource "deployments" in API group "apps"

No prompt engineering. Nothing to trust the model about. The API server simply says no.

macOS: use ${NS}, not $NS

In zsh, $NS:agent-harden triggers the :a path modifier and silently mangles the username into something baffling. Braces avoid it. This bites everyone on a Mac.

Note also what rung 2 cannot do: read Secrets. In Lab 3 the agent will diagnose a missing Secret from events alone, without ever seeing its contents.

Checkpoint

  • make verify says the contract holds
  • make ladder shows three rungs with different permissions
  • make agent-check returns the node list