Operator diagnostics capture is available from Operator version 0.16.0 onwards.
How it works
The Operator’s diagnostics capture gathers information about your Ditto Server deployment and Kubernetes environment to aid troubleshooting your deployment, giving you a single artifact to share when you contact Ditto support, speeding up issue resolution. The Ditto Operator is built for restricted environments. Collection happens entirely through the Kubernetes API and pod HTTP endpoints. It never needspods/exec and makes no outbound network calls
beyond the cluster’s API server, making it safe to run in air-gapped and
compliance-sensitive clusters.
Resources are discovered by enumerating everything in the namespaces you name. You specify the target namespaces, so you
remain in control of what gets collected.
Each run collects:
- Kubernetes events
- Container logs
- Scraped HTTP endpoints (the built-in
/metricsand/debug) - Ditto CR definitions
- Core Kubernetes objects
- Strimzi/Kafka resources
- A handful of cluster-scoped resources such as
Node,StorageClass, andPersistentVolume
Sensitive data is redacted by default.This includes:
- Kubernetes Secrets
ConfigMapkeys, labels and annotations whose keys appear sensitive, such as those containingtoken,password,secret,key,cred, etc.- Tokens spotted in event messages such as JWTs, long base64 blobs, and
AuthorizationorCookieheaders
Running diagnostics capture
You capture diagnostics by creating aBigPeerManagerTask: the Operator runs the collection
in-cluster (with the permissions it needs) and writes the archive to storage you control.
Creating a BigPeerManagerTask
ABigPeerManagerTask describes a maintenance task that the Operator runs for you. Today,
diagnostics is the only supported task. The fields under spec.task.diagnostics configure what
each run collects (namespaces, system, logMaxLines, maxArchives, and so on), and output
configures where the archive is written. The task runs the Operator’s own image and version by
default; pin them with spec.version and spec.image only if you need a specific build.
You can trigger a task in two ways:
- On demand: create the task suspended, then run it once whenever you need a bundle. Best for capturing state during active troubleshooting.
- On a recurring schedule: give the task a cron schedule and the Operator runs it automatically. Best for capturing state continuously, so a bundle already exists when an incident happens.
The Operator provisions the identity each task’s underlying
CronJob runs as. There’s a dedicated
ServiceAccount and a ClusterRoleBinding to the cluster-wide read ClusterRole
(ditto-bpmt-diagnostics), which the Ditto Operator Helm chart installs. A standard Operator Helm
install therefore already has everything the task needs.Run once on demand
To collect a single bundle without waiting for a schedule, create the task withsuspend: true
so it never fires on its own (a schedule is still required, but is ignored while suspended), and
write to a PersistentVolumeClaim the Operator provisions and owns so the bundle persists once
the run completes. namespaces is omitted, so only the task’s own namespace is collected (it is
always included):
StorageClass. Retrieve it as described in
Retrieving the archive.
Run on a recurring schedule
To collect a bundle continuously rather than on demand, dropsuspend and set schedule to
the cron expression you want. The Operator then runs the capture automatically on that cadence,
with no manual Job trigger needed:
maxArchives (default 10) and you can
fetch any that remain (see Retrieving the archive).
Collecting additional namespaces
To collect more than the task’s own namespace, list the extra ones undernamespaces.
Set system: true to also include kube-system:
Choosing where the archive goes
Theoutput.file.storage field selects the volume that backs the archive directory. There are
three options, from least to most durable.
An ephemeral emptyDir, discarded when the pod completes (mainly useful for testing the scheduling and execution of the task):
PersistentVolumeClaim the Operator creates, owns, and reuses across runs (and deletes when
the task is deleted):
PersistentVolumeClaim that you manage yourself:
provisioned and pvc, the bundles outlive individual runs, so you can fetch them later
(see Retrieving the archive).
Retrieving the archive
Withprovisioned or pvc storage, the bundles persist on the pvc after each run. Because the
pvc lives inside the cluster, you retrieve a bundle by mounting it into a short-lived pod and
copying the file out with kubectl cp. Run these commands in the same namespace as the task.
1
Find the backing PVC
For a
provisioned task, the Operator records the pvc it created under the task’s status.
Read its name into a variable (for a pvc task, use your own claim name instead):2
Start a temporary pod that mounts the claim
Create a small pod that mounts the
pvc at the task’s output.file.path
(/var/lib/diagnostics in these examples) and idles so you can copy from it:3
Copy the bundle to your machine
The most recent run is always available as
latest_diagnostics.tar.xz. Copy it out:4
Unpack the archive
Extract the bundle to inspect or share its contents:
5
Clean up the temporary pod
Delete the pod once you have the bundle. The claim and its archives are left untouched:
What’s in the archive
The archive is organised by scope, then namespace and resource, so you can browse it withtar tf before unpacking:
metadata.yaml at the root records how the bundle was produced (the Operator version,
the flags used, and the namespaces collected), along with a per-resource count of what was
gathered. It’s the first thing to open.
A run never aborts on a single failure. If a collector or an endpoint scrape fails, for
example because of missing RBAC, the run records each failure under collector_errors in
metadata.yaml and still writes whatever it managed to collect, so even a partial bundle is
useful.
Advanced configuration
Scraping HTTP endpoints inline
By default the task scrapes the built-in/metrics and /debug endpoints on every pod
labelled ditto.live/big-peer. You can add your own mappings under endpoints, each pairing a
pod label selector with one or more target endpoints. The Operator renders the list into a
controller-owned ConfigMap and mounts it into the pod:
port is either a number (9404) or the name of a container port (http).
Scraping HTTP endpoints via a ConfigMap
If you’d rather manage the scraping configuration yourself, put it in aConfigMap as a
diagnostics.yaml document and point the task at it with configMap. This is mutually
exclusive with the inline endpoints field:
configMap.key field is optional; when omitted, the controller reads the
diagnostics.yaml key (shown above).
Other task settings
The examples above cover the common fields.BigPeerManagerTask also exposes the standard
Kubernetes CronJob controls: suspend to pause a schedule without deleting the task,
concurrencyPolicy, successfulJobsHistoryLimit/failedJobsHistoryLimit, and a template
for customising the generated CronJob, pod, and container (image pull secrets, tolerations,
and so on).
For the complete, version-accurate field reference, inspect the CRD on your own cluster: