Installing the OpenTelemetry Operator on Kubernetes adds a controller, admission webhooks, and custom resources for managing Collectors and workload instrumentation from the Kubernetes API. It fits platform teams that want telemetry components reconciled like other cluster resources instead of maintaining hand-written Collector deployments.
The upstream static manifest installs the Operator into the opentelemetry-operator-system namespace and uses cert-manager to issue the webhook certificate. The kubectl apply path is the direct upstream install method for a cluster that already has a working kubectl context and permission to create CRDs, RBAC, namespaces, and admission webhooks.
The installation is ready when the Operator deployment is available, the opentelemetry.io API resources are listed, and a small OpenTelemetryCollector resource reconciles into a running Collector pod and service. Run the smoke-test Collector with the debug exporter only long enough to confirm reconciliation because it prints telemetry fields to logs.
$ kubectl config current-context production-platform
The Operator manifest creates cluster-scoped CRDs, webhooks, and RBAC. Use a non-production cluster first when testing the install path.
$ kubectl apply -f https://github.com/cert-manager/cert-manager/releases/download/v1.20.2/cert-manager.yaml namespace/cert-manager created customresourcedefinition.apiextensions.k8s.io/challenges.acme.cert-manager.io created customresourcedefinition.apiextensions.k8s.io/orders.acme.cert-manager.io created customresourcedefinition.apiextensions.k8s.io/certificaterequests.cert-manager.io created customresourcedefinition.apiextensions.k8s.io/certificates.cert-manager.io created ##### snipped ##### deployment.apps/cert-manager-cainjector created deployment.apps/cert-manager created deployment.apps/cert-manager-webhook created mutatingwebhookconfiguration.admissionregistration.k8s.io/cert-manager-webhook created validatingwebhookconfiguration.admissionregistration.k8s.io/cert-manager-webhook created
cert-manager provides the certificate used by the Operator admission webhook. Use the version from the current cert-manager installation documentation when a newer release is required by the cluster policy.
$ kubectl wait --for=condition=Available --timeout=180s deployment --all -n cert-manager deployment.apps/cert-manager condition met deployment.apps/cert-manager-cainjector condition met deployment.apps/cert-manager-webhook condition met
$ kubectl apply -f https://github.com/open-telemetry/opentelemetry-operator/releases/latest/download/opentelemetry-operator.yaml namespace/opentelemetry-operator-system created customresourcedefinition.apiextensions.k8s.io/instrumentations.opentelemetry.io created customresourcedefinition.apiextensions.k8s.io/opampbridges.opentelemetry.io created customresourcedefinition.apiextensions.k8s.io/opentelemetrycollectors.opentelemetry.io created customresourcedefinition.apiextensions.k8s.io/targetallocators.opentelemetry.io created ##### snipped ##### deployment.apps/opentelemetry-operator-controller-manager created certificate.cert-manager.io/opentelemetry-operator-serving-cert created issuer.cert-manager.io/opentelemetry-operator-selfsigned-issuer created mutatingwebhookconfiguration.admissionregistration.k8s.io/opentelemetry-operator-mutating-webhook-configuration created validatingwebhookconfiguration.admissionregistration.k8s.io/opentelemetry-operator-validating-webhook-configuration created
$ kubectl wait --for=condition=Available --timeout=180s deployment/opentelemetry-operator-controller-manager -n opentelemetry-operator-system deployment.apps/opentelemetry-operator-controller-manager condition met
$ kubectl get pods -n opentelemetry-operator-system NAME READY STATUS RESTARTS AGE opentelemetry-operator-controller-manager-845b44c6c7-9sc4t 1/1 Running 0 100s
$ kubectl api-resources --api-group opentelemetry.io NAME SHORTNAMES APIVERSION NAMESPACED KIND instrumentations otelinst,otelinsts opentelemetry.io/v1alpha1 true Instrumentation opampbridges opentelemetry.io/v1alpha1 true OpAMPBridge opentelemetrycollectors otelcol,otelcols opentelemetry.io/v1beta1 true OpenTelemetryCollector targetallocators opentelemetry.io/v1alpha1 true TargetAllocator
$ kubectl create namespace observability namespace/observability created
$ kubectl apply -n observability -f - <<'EOF'
apiVersion: opentelemetry.io/v1beta1
kind: OpenTelemetryCollector
metadata:
name: smoke
spec:
config:
receivers:
otlp:
protocols:
grpc:
endpoint: 0.0.0.0:4317
http:
endpoint: 0.0.0.0:4318
processors:
memory_limiter:
check_interval: 1s
limit_percentage: 75
spike_limit_percentage: 15
exporters:
debug:
verbosity: basic
service:
pipelines:
traces:
receivers: [otlp]
processors: [memory_limiter]
exporters: [debug]
EOF
opentelemetrycollector.opentelemetry.io/smoke created
The OpenTelemetryCollector custom resource stores Collector YAML under spec.config. Generate a production Collector config separately and replace debug with the backend exporter used by the environment.
Related: How to configure an OTLP receiver in the OpenTelemetry Collector
Tool: OpenTelemetry Collector Config Generator
$ kubectl rollout status deployment/smoke-collector -n observability --timeout=240s Waiting for deployment "smoke-collector" rollout to finish: 0 of 1 updated replicas are available... deployment "smoke-collector" successfully rolled out
$ kubectl get opentelemetrycollector smoke -n observability NAME MODE VERSION READY AGE IMAGE MANAGEMENT smoke deployment 0.153.0 1/1 76s ghcr.io/open-telemetry/opentelemetry-collector-releases/opentelemetry-collector:0.153.0 managed
The exact Collector version follows the installed Operator release unless spec.image overrides it.
$ kubectl get pods,svc -l app.kubernetes.io/instance=observability.smoke -n observability NAME READY STATUS RESTARTS AGE pod/smoke-collector-78b9df6c86-k95lm 1/1 Running 0 76s NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE service/smoke-collector ClusterIP 10.43.57.27 <none> 4317/TCP,4318/TCP 76s service/smoke-collector-headless ClusterIP None <none> 4317/TCP,4318/TCP 76s service/smoke-collector-monitoring ClusterIP 10.43.2.154 <none> 8888/TCP 76s
$ kubectl delete opentelemetrycollector smoke -n observability opentelemetrycollector.opentelemetry.io "smoke" deleted
Deleting the smoke-test custom resource removes the Operator-managed Collector objects. Do not delete production OpenTelemetryCollector resources unless their telemetry path has already been replaced.