Kubernetes Workload Observation
CollectorCtrl can show the OpenTelemetry Collectors you already run in Kubernetes next to your host collectors. You keep your Helm charts, GitOps controllers and deployment pipelines. A small in-cluster observer reports what is running; CollectorCtrl displays it.
Kubernetes support is an observation pilot. It shows workload identity, observed configuration and pod instances. It does not collect collector metrics, push configuration, restart pods or upgrade workloads. Live validation on GKE, AKS, EKS and OpenShift is still in progress, so treat these platforms as validation targets rather than certified support.
How it works
- You install the observer (Helm chart from CollectorCtrl-K8s-Operator) once per cluster.
- For each collector workload you want to see, you create one
CollectorMonitorresource. - The observer reads the workload, its pods and its mounted ConfigMap through the Kubernetes API and sends a snapshot to CollectorCtrl over a trusted
wss://OpAMP connection. - The observer only ever writes
CollectorMonitorstatus. It never changes your workloads, ConfigMaps or application pods.
What you see in CollectorCtrl
The Fleet Inventory has three views: All, Host collectors and Kubernetes workloads. The Kubernetes view adds cluster and namespace filters. Opening a workload shows:
| Tab | What it contains |
|---|---|
| Configuration | ConfigMap name and key, resource version, configuration hash and observation time. Configuration YAML appears only if reportConfig: true is set on the monitor. |
| Instances | Desired and ready instances, image, restarts and waiting/termination reasons per pod. Terminating pods are marked; completed pods are hidden by default. Kubernetes nodes are shown as pod placement, not as managed hosts. |
| Source & ownership | Cluster, namespace, workload kind and name, collector container and any available ownership information. |
A snapshot that is old, or from an observer that has disconnected, is shown as historical. The freshness budget is at least two minutes, or twice the reporting interval plus thirty seconds. Kubernetes readiness is not treated as proof that the configuration is loaded at runtime or that telemetry reaches its destination.
What CollectorCtrl will not do to observed workloads
Your deployment system remains in charge. Observed Kubernetes workloads are:
- Excluded from host configuration policies, canary rollouts, Supervisor upgrades, runtime templates and Telemetry Governor taps.
- Protected from host-only actions. Restart, remote commands, package deployment and instrumentation are rejected for them, whether requested from the UI, the REST API, the MCP server or Copilot. Mixed bulk operations list unsupported targets instead of reporting success.
- Not edited from CollectorCtrl. Git pull request workflows and emergency direct writes for workloads are not available in this release.
Install the observer
1. Prepare the CollectorCtrl server
Run a CollectorCtrl server build that matches the observer build (v0.6.0-beta or later). The OpAMP endpoint (port 4320) must be reachable from the cluster over wss:// with a certificate the observer trusts. Certificate verification cannot be turned off.
2. Create an enrollment token
In CollectorCtrl, go to Settings → API Tokens → Agent Enrollment and create a cce_… token. Each new workload/container identity uses one enrollment, so allow enough uses for the workloads you plan to monitor.
3. Store the token in a Secret
Create a Secret in the observer's namespace with the key enrollment-token, using your normal secret-management workflow.
4. Install the Helm chart
Install the chart from the operator repository, pointing it at your server and Secret (see the command below).
5. Create a CollectorMonitor per workload
Apply one CollectorMonitor for each collector workload you want to see, then open Fleet → Kubernetes workloads.
kubectl create namespace collectorctrl-system
kubectl create secret generic collectorctrl-auth \
--namespace collectorctrl-system \
--from-literal=enrollment-token=cce_YOUR_TOKEN
helm upgrade --install collectorctrl-observer ./helm-charts/collectorctrl-operator \
--namespace collectorctrl-system \
--set opamp.server=wss://collectorctrl.example.internal:4320/v1/opamp \
--set opamp.enrollmentSecret=collectorctrl-auth
The chart pulls the published observer image, ghcr.io/collectorctrl/collectorctrl-k8s-operator/operator:latest, by default. Override image.repository and image.tag to use your own registry or a pinned build.
After enrollment, the observer saves per-workload credentials on a retained PersistentVolumeClaim and reuses them on reconnect and restart. The chart needs a provisionable storage class, or set credentialStorage.existingClaim. Keep this claim across upgrades and reinstalls. Run exactly one observer replica (the chart uses the Recreate strategy), because multiple credential writers are not supported.
Common chart settings
| Value | Purpose |
|---|---|
opamp.server | The trusted wss:// OpAMP endpoint. Monitors must use exactly this endpoint. |
opamp.enrollmentSecret | Secret holding enrollment-token. |
opampCAConfigMap | ConfigMap with ca.crt when your server uses a private certificate authority. |
credentialStorage.existingClaim / storageClassName / size | Where per-workload credentials are kept. |
rbac.clusterScoped | true (default) observes across namespaces; false restricts the observer to its own namespace. |
clusterID | Stable, unique cluster ID. Discovered from the kube-system namespace UID by default; required when rbac.clusterScoped=false. |
rbac.authSecretNames | Names of per-monitor Secrets the observer may read (empty by default). |
OpenShift: add -f helm-charts/collectorctrl-operator/values-openshift.yaml before your own values. This lets the cluster's SCC assign the UID and fsGroup. Do not grant anyuid or privileged to work around an install error.
Monitor an existing collector
apiVersion: collectorctrl.io/v1alpha1
kind: CollectorMonitor
metadata:
name: existing-gateway
namespace: observability
labels:
k8s.cluster.name: production-eu
spec:
workloadSelector:
kind: Deployment # Deployment, DaemonSet or StatefulSet
name: otel-gateway
matchLabels: {}
collectorContainer: otel-collector # required for multi-container pods
opampServer: wss://collectorctrl.example.internal:4320/v1/opamp
reportConfig: false # opt in to upload the config YAML
healthCheck:
interval: 30s
- One monitor selects exactly one workload. An ambiguous selector reports an error rather than picking one.
- If the container mounts several ConfigMaps or YAML keys, set
configMapSelector.nameandconfigMapSelector.key. - Don't create two monitors for the same collector container; they would share one identity.
- Check discovery and connection errors with
kubectl describe collectormonitor existing-gateway -n observability.
With reportConfig: true, the observed configuration YAML is uploaded to CollectorCtrl. Dedicated redaction is not yet available. Leave it off for configurations that contain inline credentials, and prefer environment or Secret references.
Upgrading an existing observer
If you installed an earlier observer build:
- Create an Agent Enrollment token and reference it through
opamp.enrollmentSecret. - Make sure persistent credential storage is available, and reuse it across upgrades.
- Run one replica.
- Set
opamp.serverto the trustedwss://endpoint and use the same endpoint in every monitor. AddopampCAConfigMapfor a private CA. - Installations that used a shared secret should first run with
opamp.authMode=legacyandopamp.existingSecret(keysecret-key) so credentials are issued and saved, then switch to enrollment and turn off server legacy mode.
Upgrade the server and the observer together.
Current limits
- Discovery covers Deployments, DaemonSets and StatefulSets with a selected collector container and mounted or projected ConfigMaps. Injected sidecars without a template ConfigMap mount, native OpenTelemetry Operator resources, Secret-backed configuration and OpenShift DeploymentConfig are not covered yet.
- Command-line config merges, environment expansion and remote config providers are not reconstructed.
- Cluster- or namespace-specific team permissions are not implemented yet; existing permissions and environment rules still apply.
- Old workload records need manual pruning. Deleting and recreating a workload creates a new fleet identity.
- Observed workloads count toward the existing agent capacity allowance.
Coming next
Platform validation across Kubernetes distributions, verified Git ownership and source bindings, then validated pull-request proposals for raw ConfigMaps, the official Helm chart and OpenTelemetryCollector resources.
CollectorCtrl