Skip to content
This repository was archived by the owner on Jun 6, 2026. It is now read-only.

mwiget/kindbnkctl

Repository files navigation

kindbnkctl

BNK Kubernetes kind Go License Last commit Release

Single-binary CLI that deploys F5 BIG-IP Next for Kubernetes (BNK) 2.3.0 on a two-node kind cluster — one combined control-plane + worker, one worker dedicated to TMM running in demo mode (virtio inside the pod netns; no DPU, no SR-IOV, no Multus).

Aimed at low-spec corporate laptops where dpubnkctl's bare-metal + DPU pipeline is overkill. Same poc.yaml-driven, resume-safe shape; much shorter pipeline.

What this tool does

Drives a BNK deployment in three phases:

  1. cluster upkind create cluster, install Calico (acts as a simulator for larger SR-IOV deployments), create internal + external docker bridge networks and attach both to every kind node container, label the worker for TMM, fetch kubeconfig.
  2. deploy prereqs — namespaces, FAR pull secret, cert-manager.
  3. deploy flo + cne — FLO from the release-manifest chart at repo.f5.com, License CR with the operator's JWT, CNEInstance with advanced.demoMode.enabled: true and TMM pinned via nodeSelector: app=f5-tmm.

Symmetric destroy unwinds it: bnk-forge unregister → kind delete cluster → docker network rm.

Pinned versions

Component Version
BNK 2.3.0
CNE release manifest 2.3.0-3.2598.3-0.0.170
Kubernetes (kind node image) 1.30.8 (kind v0.26 ships this)
Calico v3.28.2
cert-manager v1.16.2
FLO chart resolved at deploy time from the release manifest

Minimum host resources

Cluster floor With bnk-forge Free disk
Linux (host docker) 12 cores · 24 GB 14 cores · 26 GB ~10 GB
macOS / Windows Docker Desktop 12 CPUs · 24 GB allocated to the VM 14 CPUs · 26 GB ~10 GB

(Configured in Docker Desktop → Settings → Resources. Rancher Desktop / Colima use the same numbers — same underlying Linux VM model.)

Why so much for a "demo"

In the two-node shape every F5 pod lands on demo-workerdemo-control-plane holds the standard node-role.kubernetes.io/control-plane taint and the BNK 2.3.0 charts don't tolerate it. The Kubernetes scheduler admits pods against their requests, not their actual RSS, and the chart reserves heavily:

Pod (on the worker) Memory request CPU request
f5-tmm 9204 Mi 4100m
f5-cne-controller (4 containers) 1600 Mi 1080m
f5-downloader 1000 Mi 500m
f5-spk-csrc 1024 Mi 500m
f5-crdconversion 1024 Mi 500m
f5-dssm-db / -sentinel 1152 Mi each 600m each
f5-observer / -receiver 500 Mi each 512m / 1c
f5-observer-operator 256 Mi 250m
f5-spk-cwc 640 Mi 556m
f5-afm 512 Mi 500m
f5-ipam-ctlr / f5-rabbit 512 Mi each 100m / 300m
otel-collector / flo 256 Mi each 500m / 250m
Sum on the worker ~20 Gi ~12 cores

Each kind node container reports the docker daemon's full memory and CPU as its allocatable — kind does not partition. So the worker won't schedule the full stack until the daemon (or Docker Desktop VM) is sized above the request total, plus ~4 Gi headroom for the control-plane pods sharing the same VM and kernel overhead in both node containers.

What the cluster actually uses

Steady-state, after CNEInstance.Available=True, the cluster's real RSS is much smaller than the reservation:

Component Working set CPU
TMM pod (worker) ~1.2 GB ~100m
kube-apiserver ~900 MB ~150m
All other F5 pods (~20) ~1.0 GB ~470m
Calico + coredns + etcd + kube-* ~700 MB ~150m
Kernel / runtime per node ~500 MB × 2
Total cluster RSS ~4.5 GB pod + ~1 GB overhead ~900m steady, ~1.2c during TMM init

So the cluster lives inside ~6 GB of real memory once it's up — it just won't get there without first satisfying the K8s scheduler's ~20 Gi worker reservation.

Symptom when the floor is too low

kindbnkctl e2e reaches [5/5] deploy-cne and stalls. Six pods (f5-dssm-db-0, f5-dssm-sentinel-0, f5-spk-cwc-*, f5-observer-{0,receiver-0,operator-*}) sit Pending with FailedScheduling: Insufficient memory on the worker, and CNEInstance.Available never goes true. Quick check:

kubectl --kubeconfig <poc>/artifacts/kubeconfig describe node demo-worker \
  | grep -E "Allocatable:|Allocated resources:" -A6

If memory Requests is ≥99% of Allocatable, raise the docker daemon allocation and re-run from the failed phase (kindbnkctl deploy cne …) — it's idempotent.

Disk

1.4 GB (kindest/node image) + ~2.4 GB (F5 container images pulled to the worker) + ~0.5 GB (cert-manager, alpine/k8s tooling, manifests) + ~5 GB headroom for kind cluster state and logs.

kindbnkctl doctor reports the host's actual CPU count and fails when it falls below MinBaseline. Override the constants in internal/version/version.go if you've tuned chart values to reduce requests.

bnk-forge integration

If a local bnk-forge clone exists at ~/git/bnk-forge (or $KINDBNKCTL_BNK_FORGE_PATH) when kindbnkctl init runs, the new PoC's bnk_forge: block is pre-filled and enabled. On cluster up, kindbnkctl best-effort registers the kind cluster with bnk-forge — if the local bnk-forge stack isn't running, the auto-hook logs a clean skip and continues.

kindbnkctl never installs or starts bnk-forge for you. If it's configured but not running, bring it up manually (cd ~/git/bnk-forge && make deploy) then kindbnkctl bnk-forge launch to register after the fact.

Download

Prebuilt binaries for each tagged release are on the GitHub Releases page — three archives per release plus a checksums.txt:

Platform Archive
Linux (Intel/AMD) kindbnkctl_<version>_linux_amd64.tar.gz
Linux (ARM64) kindbnkctl_<version>_linux_arm64.tar.gz
macOS (Apple Silicon) kindbnkctl_<version>_darwin_arm64.tar.gz

One-liner install (Linux amd64; swap the suffix for your platform):

VERSION=$(curl -fsSL https://api.github.com/repos/mwiget/kindbnkctl/releases/latest | sed -n 's/.*"tag_name": *"\([^"]*\)".*/\1/p')
curl -fsSL "https://github.com/mwiget/kindbnkctl/releases/download/${VERSION}/kindbnkctl_${VERSION#v}_linux_amd64.tar.gz" \
  | tar -xz -C /tmp kindbnkctl
sudo install -m 0755 /tmp/kindbnkctl /usr/local/bin/kindbnkctl
kindbnkctl version

Releases follow v<bnk-version>-<n> — e.g. v2.3.0-1, v2.3.0-2. The 2.3.0 prefix tracks the pinned BNK release; the -n suffix increments per kindbnkctl-only iteration.

Or build from source — see Repo layout below.

Requirements

Tool Why
Docker or Podman kind runs Kubernetes nodes as containers; FLO + cert-gen also shell into an alpine/k8s:1.31.5 container at deploy time
kind cluster bring-up (default backend)
k3d (optional) alternative backend, selected via the k3dbnkctl symlink (see Cluster backend)
kubectl cluster reads/writes (apply, wait, label)
helm cert-manager + FLO install, release-manifest pull
git (optional) init git-inits the PoC repo (skippable with --no-git)

Verify after install:

kindbnkctl doctor

What customers supply themselves, dropped into keys/ of the PoC repo (delivered through F5's normal channels):

  • FAR tarball — image-pull credentials for repo.f5.com
  • JWT — TEEM activation token

Cluster backend (kind / k3d)

kind is the default backend. k3d (k3s-in-docker) is available as an option, selected by the binary's own name: symlink k3dbnkctl to the installed kindbnkctl and invoke the symlink to drive k3d instead.

ln -sf kindbnkctl ~/.local/bin/k3dbnkctl
k3dbnkctl cluster up --poc demo --yolo --confirm-cluster demo   # uses k3d
kindbnkctl cluster up --poc demo --yolo --confirm-cluster demo  # uses kind

Both backends build the same two-node, Calico-CNI, k8s-v1.30.8 shape and share the entire BNK deploy pipeline. Warm, k3d brings the cluster up ~18 % faster and idles ~200 MiB lighter (5 pods vs 12). Full measurements and the trade-offs are in docs/kind-vs-k3d.md. (Requires the k3d CLI on PATH; k3dbnkctl doctor checks for it.)

Quick start

# 1. Create a fresh PoC repo. Auto-detects ~/git/bnk-forge.
kindbnkctl init demo --customer "Acme"
cd demo

# 2. Drop the operator-supplied files into keys/.
cp /path/to/f5-far-auth-key.tgz keys/
cp /path/to/license.jwt          keys/.jwt

# 3. Confirm poc.yaml is clean.
kindbnkctl validate

# 4. Run the pipeline (~10–20 min with a warm docker cache).
kindbnkctl e2e --yolo --confirm-cluster demo

# 5. Tear down (symmetric):
kindbnkctl destroy --yolo --confirm-cluster demo

Per-phase invocation

If you'd rather drive the phases one at a time for diagnostics:

kindbnkctl cluster up      --yolo --confirm-cluster demo
kindbnkctl deploy prereqs  --yolo --confirm-deploy  demo
kindbnkctl deploy flo      --yolo --confirm-deploy  demo
kindbnkctl deploy cne      --yolo --confirm-deploy  demo

Every phase is idempotent and gated by --yolo plus a typo-guard.

Repo layout (the binary itself)

cmd/kindbnkctl/        main entrypoint
internal/cli/          cobra commands (init, validate, doctor, cluster,
                       deploy, destroy, e2e, bnk-forge, version)
internal/poc/          poc.yaml schema + I/O
internal/cluster/      kind + docker wrappers
internal/deploy/       cert-manager, FLO, License CR, CWC cert-gen
internal/bnkforge/     bnk-forge HTTP client (copy-fork of dpubnkctl)
internal/embedded/     go:embed AGENTS.md, CLAUDE.md, templates/
internal/version/      build-stamped + BNK 2.3.0 pins + min-spec floor

Repo layout (a PoC created by kindbnkctl init)

poc.yaml         declarative state — source of truth
AGENTS.md        operator + agent guide
CLAUDE.md        @AGENTS.md include
journal/         append-only markdown log
artifacts/       rendered kind.yaml, kubeconfig, helm values, CWC certs
keys/            gitignored — FAR tgz + JWT live here
.gitignore       excludes all secret material

Network topology

The shape after a full e2e plus bgp-peer-frr (everything the other scenarios build on). One docker bridge on the host (the kind cluster's own); two kind node containers; a Multus-managed Linux bridge inside the worker carries BGP traffic between TMM and the FRR helper pod. Scenario backends are plain Calico pods — the Gateway IPs they serve get plumbed via BGP, so the backends don't need to be on the NAD themselves.

+----------------------------------------------------------------------------+
| HOST  (Linux or macOS Docker Desktop)                                      |
|                                                                            |
|   docker bridge: kind  172.18.0.0/16                                       |
|       |                                                                    |
+-------|--------------------------------------------------------------------+
        |
+-------+--------------+   +-------------------------------------------------+
| smoke-control-plane  |   | smoke-worker  (kind node container)             |
| (kind node container)|   | label: app=f5-tmm                               |
| eth0 172.18.0.2      |   | eth0 172.18.0.3                                 |
|                      |   |                                                 |
| pods:                |   |  +-------------------------------------------+  |
|   Calico  Multus     |   |  | TMM pod        ns=default  app=f5-tmm     |  |
|   FLO     CWC        |   |  | 6 containers:                             |  |
|   cert-manager       |   |  |   f5-tmm                                  |  |
|   ...                |   |  |   f5-tmm-routing  (= ZeBOS)               |  |
+----------------------+   |  |   debug  blobd  toda-observer  ipsec      |  |
                           |  | Interfaces:                               |  |
                           |  |   net1   192.168.99.X/24  Multus NAD      |  |
                           |  |          (BGP source, no eth0 hook)       |  |
                           |  |   eth0   10.244.x.x/32   Calico (kube-API |  |
                           |  |          + ZeBOS bgpd kernel listener)    |  |
                           |  |   xeth0  no IP    Calico veth #2, TMM     |  |
                           |  |          userspace raw frames             |  |
                           |  |   tmm    169.254.0.253/24  virtio, pod    |  |
                           |  |          default route to TMM DP          |  |
                           |  |   tunl0  DOWN     Calico IPIP placeholder |  |
                           |  +-------------------------------------------+  |
                           |  +-------------------------------------------+  |
                           |  | FRR pod        ns=scn-bgp  app=scn-frr    |  |
                           |  | 1 container:   frr (zebra + bgpd)         |  |
                           |  |   net1   192.168.99.Y/24  Multus NAD      |  |
                           |  |          (BGP peer + curl source)         |  |
                           |  |   eth0   10.244.x.x/32   Calico           |  |
                           |  +-------------------------------------------+  |
                           |             ^                                   |
                           |             |  BGP TCP/179 + scenario curls     |
                           |             v  over br-bnk-bgp, L2              |
                           |  +========================================+     |
                           |  ||  br-bnk-bgp   Linux bridge in node    ||    |
                           |  ||  netns, created by the bridge-CNI     ||    |
                           |  ||  plugin via NAD name=bnk-bgp ;        ||    |
                           |  ||  host-local IPAM 192.168.99.20-250    ||    |
                           |  ||  on /24                               ||    |
                           |  +========================================+     |
                           |                                                 |
                           |  +-------------------------------------------+  |
                           |  | scenario backends  (plain Calico pods —   |  |
                           |  | no NAD attachment, no node pinning)       |  |
                           |  |   nginx        ns=scn-httproute-e2e       |  |
                           |  |   pp-backend   ns=scn-proxy               |  |
                           |  |   ext-backend  ns=scn-extres   (Pool      |  |
                           |  |     member references its Calico podIP)   |  |
                           |  +-------------------------------------------+  |
                           |                                                 |
                           |  DaemonSets in node netns:                      |
                           |    Calico-node     Multus thick                 |
                           |    f5-coremond (if how-to #4 ran)               |
                           +-------------------------------------------------+

BGP session:
  TMM/ZeBOS  AS 65000  =======  net1 <-> net1, L2 over br-bnk-bgp  =======>  FRR  AS 65001
                                                                             listen-range
                                                                             192.168.99.0/24
                                                                             peer-group
                                                                             from-tmm

  TMM ZeBOS advertises (redistribute kernel, at router-bgp scope —
  silently dropped if placed inside address-family ipv4):
    192.168.99.0/24      (net1 connected)
    203.0.113.100/32     Gateway scn-gateway        (http-routing-e2e)
    203.0.113.101/32     Gateway scn-extres-gw      (external-resource-pool)
    203.0.113.102/32     Gateway scn-proxy-gw       (proxy-protocol-l4)

  FRR installs each /32 as a kernel route:
    203.0.113.100/32 via 192.168.99.X dev net1 proto bgp
  so any client in the FRR pod can curl the Gateway addresses
  end-to-end via the NAD bridge, completely bypassing TMM's eth0
  TCP hook. This is what http-routing-e2e and external-resource-pool
  rely on for their data-plane assertions.

Key knob: CNEInstance.spec.advanced.tmm.env TMM_MAPRES_ADDL_VETHS_ON_DP=FALSE is set by bgp-peer-frr. With this TRUE (TMM's default for demoMode), mapres grabs net1 for the userspace data plane and flushes its kernel IP — ZeBOS then has nothing to source-bind to. Flipping it FALSE lets net1 stay a normal Linux interface with its NAD-assigned IP so the kernel TCP stack handles BGP traffic ordinarily.

Scenarios — testing F5 how-tos against the running cluster

After e2e brings the cluster up, drive named test scenarios against it. Each scenario maps to one F5 how-to article (or sub-article) and exercises a slice of BNK functionality end-to-end: render manifests into artifacts/scenarios/<name>/, apply them, assert reconciled state, write a JSON+md report under reports/<timestamp>/scenarios/.

kindbnkctl scenario list                            # all known scenarios + rating
kindbnkctl scenario run http-routing --poc ./demo   # apply + verify + report
kindbnkctl scenario run http-routing --dry-run      # render manifests only
kindbnkctl scenario clean http-routing              # delete what was applied

Rating is a stable hint about what's testable in the 2-node / demo-TMM shape:

Rating Meaning
green fully testable here
amber partially testable — control-plane verifies, data-plane plumbing missing
red requires real DPUs / BGP peers / etc.; listed for discoverability, never executed

Scoring of the F5 BNK how-tos index:

# How-to Rating Scenario Wall time
1 Restrict access to sensitive data 🟢 cwc-admin-access 9s
2 Components needing cluster-wide access 🟢 cluster-wide-watch 4s
3 Set up dynamic routing with BGP 🟢 bgp-peer-frr 3m19s
4 Set up core file collection 🟢 core-file-collection 3m01s
6 Configure Token Counting and Enforcement 🟢 ai-token-counting 25s
7 Semantic AI Model Caching (sub-article of AI Traffic Optimization) 🟢 ai-semantic-cache 22s
8 HTTP traffic steering with Gateway API HTTPRoute 🟢 http-routing-e2e 21s
9 Proxy Protocol iRule support for L4 routes 🟢 proxy-protocol-l4 24s
10 Load Balance Traffic to External Resources 🟢 external-resource-pool 14s

Plus four scenarios drawn from the BNK Use-Cases / CRD pages rather than the how-tos index:

Use-case Rating Scenario
Dynamic IP address allocation (FIC for Gateway API) 🟡 fic-dynamic-ip
TCP load balancer (L4Route protocol=TCP, weighted backends) 🟢 tcp-l4-loadbalance
UDP load balancer (L4Route protocol=UDP, socat echo) 🟢 udp-l4-loadbalance
gRPC routing (GRPCRoute, grpcbin backend, grpcurl client) 🟡 grpc-loadbalance

fic-dynamic-ip (🟡): manifest-side configuration applies cleanly (F5BnkGateway, Gateway w/ infrastructure.parametersRef, HTTPRoute) but Gateway never reaches Programmed=True. f5-cne-controller logs "No IPAM found for Gateway" — the F5BnkGateway pool isn't auto- converted into IPAM/IPAMRange CRs in this BNK 2.3.0 demo deployment. The scenario asserts the control-plane state and surfaces the AddressNotAssigned condition as informational.

grpc-loadbalance (🟡): GRPCRoute reconciles, Gateway reaches Programmed=True, BGP route propagates, grpcurl installs SHA- verified, and a direct grpcurl-to-backend Service call lists all gRPC services successfully. But cleartext gRPC traffic through the Gateway returns RST_STREAM(INTERNAL_ERROR) — TMM's standard HTTP/json/httprouter profile chain (visible in audit logs) breaks gRPC framing. Investigation confirmed TMM unconditionally applies profile-http + profile-json + profile-httprouter to all listener types (HTTP and HTTPS), corrupting HTTP/2 binary frames regardless of TLS termination. Setting appProtocol: kubernetes.io/h2c on the Service, switching to an HTTPS listener on port 443 with TLS, and adding profile-sbi (all verified via TMM audit logs) did not change the outcome. This is a BNK 2.3.0 FLO limitation. Fix needs either a "raw HTTP/2 passthrough" mode for GRPCRoute listeners, or a BNK profile override path not yet exposed through the Gateway API CRDs.

Wall times measured on a fresh e2e (cluster destroy + redeploy) running 2026-05-21 on a Linux laptop. The two TMM-restarting scenarios (bgp-peer-frr + core-file-collection) dominate at ~3 minutes each; the others are tens of seconds because they either don't touch TMM or piggyback on the bridge already up. kindbnkctl scenario run --all runs every green-rated scenario in topo-sorted dependency order, writing an aggregate reports/<stamp>/run.{json,md} summary alongside the per-scenario JSONs.

Cluster bring-up itself (kindbnkctl e2e) is 5m44s: validate 0s · cluster-up 48s · deploy-prereqs 20s · deploy-flo 24s · deploy-cne 4m12s (includes waiting on bnk-gatewayclass to reach Accepted=True — required to keep first-run scenario Gateways from being marked-for-deletion by the controller).

How-tos #5 (DOCA Offloads on DPU), #11 (Static Active-Standby Interface Bonding), and #12 (TMOS DNS Service Integration with CIS) are omitted from the table because they require resources kind can't provide: DPU silicon (#5), bondable physical NICs (#11), and a real upstream BIG-IP GTM box (#12). They remain valid BNK features outside the kindbnkctl shape.

Ratings are assigned only after a scenario is built and run. Implemented scenarios that pan out land as 🟢; ones that hit a real architectural barrier on kind+demoMode get 🟡 with the gap documented in the scenario's Description(). Empty cell = scenario not yet built.

bgp-peer-frr (green) deploys a real BGP session between an FRR pod and TMM's ZeBOS daemon, peered over a Multus NetworkAttachmentDefinition (bridge CNI) on a per-node Linux bridge. The NAD path bypasses TMM's eth0 TCP hook entirely — BGP rides net1 in both pods, exchanging prefixes via the bridge. Six assertions pass: Multus DaemonSet Ready, both pods have net1 in the 192.168.99.0/24 NAD range, ZeBOS sees the neighbor, BGP session Established, and FRR's BGP table has at least one prefix learned from TMM (via redistribute kernel).

http-routing-e2e (green) — depends on bgp-peer-frr for the NAD plumbing. Applies a GatewayClass + Gateway (static spec.addresses=203.0.113.100) + HTTPRoute + nginx backend. TMM's ZeBOS (via redistribute kernel) advertises 203.0.113.100/32 into BGP; FRR installs the kernel route via net1; the verify step execs 5 curls from inside the FRR pod, which already has the route. All 6 assertions pass including the 5×curl. Path: FRR socket → FRR kernel route → net1 → bnk-bgp bridge → TMM net1 → Gateway listener → nginx. TMM's eth0 TCP hook is completely bypassed.

Reproduce manually:

kubectl -n scn-bgp exec deploy/scn-frr -c frr -- \
  curl -sS -H 'Host: kindbnkctl.local' http://203.0.113.100/
# → kindbnkctl-scenario-httproute-e2e-OK

external-resource-pool (green) — demonstrates how-to #10 (load balance to non-Service backends) via the BNK Pool CR. HTTPRoute backendRefs points at a Pool {group:k8s.f5net.com, kind:Pool} instead of a Service; Pool.spec.members lists endpoints by IP+port. On kind, the "external" backend is an nginx pod attached to the bnk-bgp NAD (same bridge TMM uses), with its NAD IP auto-discovered and rendered into the Pool CR. Gateway address is 203.0.113.101 to avoid collision with http-routing-e2e.

cwc-admin-access (green) — implements how-to #1 (restrict access to sensitive data). Demonstrates BNK's dual-gate access control on the CWC admin API: mTLS at the TLS layer + bearer token at the HTTP layer. Both materials are produced by the deploy-flo phase already (cwc-license-client-certs Secret + cwc-auth-token Secret in f5-cne-core); the scenario just replicates them into its own namespace, spawns a curl probe pod, and runs three requests against https://f5-spk-cwc.f5-cne-core.svc:38081/status: authenticated (expect 200 + license JSON), no Authorization header (expect 401 "invalid token format"), bogus token (expect 401 "invalid token"). Independent of bgp-peer-frr — this is a pure runtime-access check.

proxy-protocol-l4 (green) — implements how-to #9 (PROXY-protocol iRule on an L4 route). The new BNK CRs reconcile (F5BigCneIrule Programmed, L4Route Accepted, BNKNetPolicy ResolvedRefs True), TMM proxies the TCP traffic, FRR learns the Gateway IP via BGP, and 5/5 curls from FRR through the Gateway return the marker body with the parsed proxy_addr set to FRR's NAD IP — proving the iRule's TCP::respond prepended the PROXY v1 line before nginx saw the request. Load-bearing knob: L4Route.spec.pvaAccelerationMode: disabled, which keeps the data path in TMM's TCL slow path. With the default full/assisted PVA mode, TMM hardware-offloads the connection after handshake and TCP::respond fires in the VM but can't reach the offloaded wire — symptoms are 200 OK from nginx turning into "broken header" errors and curl (52) Empty reply.

core-file-collection (green) — implements how-to #4 (set up core file collection). One-line CNEInstance.spec.coreCollection. enabled=true flip plus advanced.coremon.hostPath=true so the CoreMond DaemonSet survives kind's single-node-RWO storage class. FLO auto-creates a CoreMond CR + DaemonSet in f5-cne-core and adds kernel-cores / f5-core-store / tmm-core volumes to the TMM Deployment template. The scenario asserts the CR exists, the DaemonSet is Running, and the CNEInstance condition CoremondAvailable=True. The how-to's "kill -11 to force a crash" verification step is intentionally NOT automated — crashing TMM mid-scenario destabilises the cluster, and the follow-up "did a core file land in /var/crash" check needs a privileged node-level read we'd rather not bake in. Operators can run the kill manually after the scenario and inspect the kind worker container's filesystem to confirm capture.

Reference run report

A complete e2e --with-scenarios report from a clean cluster is checked in at examples/reports/run-demo-2026-06-03T06-47-53Z.md so a reader can see the full report shape (versions, host resources, cluster topology, F5 control-plane pods, every deploy phase, and every scenario row) without running anything locally.

Reproduce on your own host with:

kindbnkctl e2e \
  --poc <pocdir> \
  --yolo --confirm-cluster <pocname> \
  --with-scenarios \
  --no-resume

Output lands at <pocdir>/reports/<stamp>/run-<pocname>-<stamp>.md (plus the JSON twin, per-phase logs under logs/, and per-scenario JSONs under scenarios/). The checked-in report ran 16m42s end-to-end: ~6m deploy (validate → cluster-up → deploy-prereqs/flo/cne) plus ~11m running 12 green scenarios topo-sorted by dependency order (the one amber scenario — fic-dynamic-ip — is skipped by --all and must be run explicitly).

Testing

make test    # Go unit tests (poc, deploy, cluster, scenarios)
make smoke   # unit tests + Layer A CLI smoke (no cluster required, ~5s)

make smoke is the gate to run before pushing — it covers the non-cluster-dependent surface area in one shot.

Design references

  • dpubnkctl — the bare-metal + DPU sister tool. kindbnkctl is a copy-fork: internal/poc, internal/cluster, internal/cli are rewritten for the kind path; internal/bnkforge, internal/deploy are forked verbatim with minor adjustments (local kubectl/helm instead of containerized).
  • f5-bnk-udf (branch v2.2.0) — the inspiration for the BNK-on-host shape: advanced.demoMode.enabled: true + node label + nodeSelector, ZeBOS dynamic-routing ConfigMap pattern, multi-worker topology. Same CNEInstance recipe family; kindbnkctl adapts it to a two-node kind cluster with Multus NADs replacing the macvlan-on-bare-metal approach used in f5-bnk-udf.

About

Single-binary CLI that deploys F5 BIG-IP Next for Kubernetes (BNK) 2.3.0 on a 2-node kind cluster with TMM in demo mode.

Topics

Resources

License

Stars

Watchers

Forks

Packages

 
 
 

Contributors