Deploying Scout¶
Two Deployment Modes
Same-cluster mode (default): Scout and the Bindy operator run in the same cluster. No extra configuration needed.
Multi-cluster mode: Scout runs on workload clusters and writes to a dedicated Queen Bee cluster cluster running Bindy. Use bindy bootstrap mc to generate credentials, then set BINDY_SCOUT_REMOTE_SECRET. See Multi-Cluster Setup below.
Bindy Scout is an optional companion controller that watches Ingress resources and LoadBalancer Services across your cluster and automatically creates ARecord CRs on behalf of application teams — without requiring them to have write access to the bindy namespace.
See the Bindy Scout guide for the full conceptual overview, including the scout bee backstory, how record naming works, and the multi-cluster roadmap.
Prerequisites¶
- The main Bindy operator must already be running (Deploying Operator)
- CRDs must be installed (Scout uses the
ARecordCRD) - A
DNSZonemust exist for the zone Scout will write records into
Install¶
The recommended way to install Scout is with the bindy CLI. This applies all resources via server-side apply and is safe to re-run:
This creates:
- A
Namespace(bindy-systemby default) - All 12
CustomResourceDefinitionobjects (same set as the operator — safe if already installed) - A
ServiceAccount(bindy-scout) inbindy-system - A
ClusterRole/ClusterRoleBindingfor cluster-wide Ingress watch, LoadBalancer Service watch, DNSZone read, and Secret read - A
Role/RoleBindingforARecordwrite access inbindy-system - A
Deploymentrunning thebindy scoutcontroller
Air-gapped / private registry
This producesharbor.corp.internal/bindy-mirror/bindy:<version> instead of ghcr.io/firestoned/bindy:<version>. See the CLI reference for the full air-gapped workflow.
Preview before applying
Prints every resource as YAML without connecting to the cluster.Configure¶
Scout requires one mandatory setting: the logical cluster name that is stamped on every ARecord it creates. Set it via environment variable or CLI flag.
CLI takes precedence
When both --cluster-name and BINDY_SCOUT_CLUSTER_NAME are set, the CLI flag wins.
Full configuration reference¶
| Variable | CLI flag | Default | Description |
|---|---|---|---|
BINDY_SCOUT_CLUSTER_NAME |
--cluster-name |
— | Required. Logical cluster name stamped on all created ARecord labels. |
BINDY_SCOUT_NAMESPACE |
--namespace |
bindy-system |
Namespace where ARecord CRs are created. |
POD_NAMESPACE |
— | default |
Scout's own namespace. Always excluded from Ingress watching. Inject via downward API. |
BINDY_SCOUT_EXCLUDE_NAMESPACES |
— | — | Comma-separated list of additional namespaces to skip. |
BINDY_SCOUT_DEFAULT_ZONE |
--default-zone |
— | Default DNS zone when no bindy.firestoned.io/zone annotation is present. With DEFAULT_IPS, Ingresses and Services only need scout-enabled: "true". |
BINDY_SCOUT_DEFAULT_IPS |
--default-ips |
— | Comma-separated default IP(s) used when no per-resource annotation or LB status IP is available. For shared-ingress topologies (e.g. Traefik). |
BINDY_SCOUT_REMOTE_SECRET |
— | — | (Multi-cluster) Name of a Secret in the local cluster containing a kubeconfig key for the Queen Bee cluster. When set, Scout writes ARecord CRs and validates zones on the remote Bindy cluster. See Multi-Cluster Setup below. |
BINDY_SCOUT_REMOTE_SECRET_NAMESPACE |
— | Scout's own namespace | (Multi-cluster) Namespace of the BINDY_SCOUT_REMOTE_SECRET. Defaults to Scout's own namespace. |
RUST_LOG |
— | info |
Log level: trace, debug, info, warn, error. |
RUST_LOG_FORMAT |
— | text |
Log format: text or json. |
Multi-Cluster Setup¶
In multi-cluster deployments, Scout runs on workload clusters and writes ARecord CRs to the dedicated Queen Bee cluster (where the Bindy operator lives). Use bindy bootstrap mc to generate the credentials.
1. Generate credentials on the Queen Bee cluster¶
# Run this against the Queen Bee cluster (with Queen Bee cluster KUBECONFIG active)
bindy bootstrap mc \
--service-account bindy-scout-remote \
--namespace bindy-system \
| kubectl --context=<child-cluster> apply -f -
This single pipeline:
1. Creates a ServiceAccount + Role + RoleBinding on the Queen Bee cluster (minimal: ARecord CRUD + DNSZone read)
2. Generates a kubeconfig for that service account
3. Outputs a bindy.firestoned.io/remote-kubeconfig Secret and applies it to the child cluster
One SA per child cluster
Use a unique --service-account per child cluster for independent credential revocation:
2. Enable remote mode on the Scout Deployment¶
Add BINDY_SCOUT_REMOTE_SECRET to the Scout Deployment on the child cluster:
Scout will load the kubeconfig from that Secret and write all ARecord CRs to the Queen Bee cluster instead of the local cluster.
See the Scout guide — Multi-Cluster Mode for the full architecture diagram, per-cluster SA strategy, and RBAC details.
Verify¶
Check that the Scout pod is running:
Expected output:
Check Scout logs:
You should see Scout announce which namespaces it is watching and confirm it is ready.
Test¶
Annotate an Ingress in any non-excluded namespace:
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: my-app
namespace: my-app-ns
annotations:
bindy.firestoned.io/scout-enabled: "true"
bindy.firestoned.io/zone: "example.com"
spec:
rules:
- host: my-app.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: my-app
port:
number: 80
Annotate a LoadBalancer Service in any non-excluded namespace:
Annotate an HTTPRoute attached to a Gateway:
IP required
HTTPRoute has no LoadBalancer status. Supply an IP via bindy.firestoned.io/ip or set BINDY_SCOUT_DEFAULT_IPS.
apiVersion: gateway.networking.k8s.io/v1
kind: HTTPRoute
metadata:
name: my-app
namespace: my-app-ns
annotations:
bindy.firestoned.io/scout-enabled: "true"
bindy.firestoned.io/zone: "example.com"
bindy.firestoned.io/ip: "203.0.113.10"
spec:
parentRefs:
- name: my-gateway
namespace: gateway-ns
hostnames:
- my-app.example.com
rules:
- matches:
- path:
type: PathPrefix
value: /
backendRefs:
- name: my-app
port: 80
Annotate a TLSRoute for TCP/TLS workloads:
IP required
TLSRoute has no LoadBalancer status. Supply an IP via bindy.firestoned.io/ip or set BINDY_SCOUT_DEFAULT_IPS.
apiVersion: gateway.networking.k8s.io/v1
kind: TLSRoute
metadata:
name: my-grpc-api
namespace: my-app-ns
annotations:
bindy.firestoned.io/scout-enabled: "true"
bindy.firestoned.io/zone: "example.com"
bindy.firestoned.io/ip: "203.0.113.11"
spec:
parentRefs:
- name: my-gateway
namespace: gateway-ns
hostnames:
- my-grpc-api.example.com
rules:
- backendRefs:
- name: my-grpc-api
port: 9090
Within seconds, Scout creates an ARecord in bindy-system:
# All Scout-managed records
kubectl get arecords -n bindy-system -l bindy.firestoned.io/managed-by=scout
# Records from a specific source resource (works for any kind: Ingress, Service, HTTPRoute, TLSRoute)
kubectl get arecords -n bindy-system -l bindy.firestoned.io/source-name=<resource-name>
Next Steps¶
- Bindy Scout Guide — full conceptual guide, annotations reference, record naming, and RBAC details
- Environment Variables — complete Scout environment variable reference