How to install the OpenTelemetry Operator on Kubernetes

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.

Steps to install the OpenTelemetry Operator on Kubernetes:

  1. Confirm the active kubectl context points to the target cluster.
    $ 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.

  2. Install cert-manager from the official static manifest.
    $ 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.

  3. Wait for cert-manager deployments.
    $ 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
  4. Install the OpenTelemetry Operator manifest.
    $ 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
  5. Wait for the Operator deployment.
    $ kubectl wait --for=condition=Available --timeout=180s deployment/opentelemetry-operator-controller-manager -n opentelemetry-operator-system
    deployment.apps/opentelemetry-operator-controller-manager condition met
  6. Check the Operator pod.
    $ kubectl get pods -n opentelemetry-operator-system
    NAME                                                         READY   STATUS    RESTARTS   AGE
    opentelemetry-operator-controller-manager-845b44c6c7-9sc4t   1/1     Running   0          100s
  7. Confirm the opentelemetry.io API resources are registered.
    $ 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
  8. Create a namespace for a reconciliation smoke test.
    $ kubectl create namespace observability
    namespace/observability created
  9. Create a minimal Operator-managed Collector.
    $ 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

  10. Wait for the Operator-managed Collector deployment.
    $ 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
  11. Check the Collector custom resource status.
    $ 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.

  12. Check the Collector pod and services.
    $ 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
  13. Remove the smoke-test Collector when the install proof is complete.
    $ 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.