How to deploy the EDOT Collector on Kubernetes

Deploying the Elastic Distribution of OpenTelemetry (EDOT) Collector on Kubernetes sends cluster metrics, node metrics, container logs, and application telemetry to Elastic Observability through the OpenTelemetry kube-stack Helm chart. It fits clusters where workloads already use OpenTelemetry or where the OpenTelemetry Operator will inject Elastic-supported instrumentation into selected namespaces.

The Elastic-supported Kubernetes path installs the OpenTelemetry Operator plus three Collector roles. A cluster Collector gathers cluster-level metrics and events, a daemon Collector runs on nodes for node metrics, logs, and application telemetry, and a gateway Collector exports the processed data to Elastic.

The chart expects an elastic-secret-otel secret with elastic_endpoint and elastic_api_key keys in the opentelemetry-operator-system namespace. Use the versioned values file and chart version shown by Elastic for the target deployment, and use cert-manager in production when the operator webhook certificate should renew automatically instead of relying on the chart's self-signed certificate.

Steps to deploy the EDOT Collector on Kubernetes:

  1. Confirm that kubectl points to the cluster that should receive the EDOT Collector.
    $ kubectl config current-context
    production-observability

    Installing into the wrong context creates collectors, webhooks, and cluster-wide permissions in the wrong cluster.

  2. Add the OpenTelemetry Helm chart repository.
    $ helm repo add open-telemetry https://open-telemetry.github.io/opentelemetry-helm-charts --force-update
    "open-telemetry" has been added to your repositories
  3. Create the operator namespace.
    $ kubectl create namespace opentelemetry-operator-system
    namespace/opentelemetry-operator-system created
  4. Set a restrictive file mode for the temporary credential file.
    $ umask 077
  5. Save the Elastic endpoint and API key in a temporary local env file.
    $ cat > elastic-otel.env <<'EOF'
    elastic_endpoint=https://elastic.example.com:443
    elastic_api_key=REDACTED_API_KEY
    EOF

    Keep the real API key out of saved transcripts, tickets, screenshots, and shared shell history.

  6. Create the secret required by the Elastic EDOT values file.
    $ kubectl create secret generic elastic-secret-otel \
      --namespace opentelemetry-operator-system \
      --from-env-file=elastic-otel.env
    secret/elastic-secret-otel created

    The rendered EDOT gateway Collector reads ELASTIC_API_KEY from elastic_api_key and ELASTIC_ENDPOINT from elastic_endpoint in this secret.

  7. Remove the temporary credential file after Kubernetes stores the secret.
    $ rm elastic-otel.env
  8. Install the OpenTelemetry kube-stack chart with the Elastic EDOT values file.
    $ helm upgrade --install opentelemetry-kube-stack open-telemetry/opentelemetry-kube-stack \
      --namespace opentelemetry-operator-system \
      --values https://raw.githubusercontent.com/elastic/elastic-agent/refs/tags/v9.4.2/deploy/helm/edot-collector/kube-stack/values.yaml \
      --version 0.12.4
    Release "opentelemetry-kube-stack" does not exist. Installing it now.
    NAME: opentelemetry-kube-stack
    NAMESPACE: opentelemetry-operator-system
    STATUS: deployed
    REVISION: 1

    Replace the values URL and chart version when Elastic's Add Data screen or compatibility notes show a different pair for the target Stack version.

  9. Check the Helm release state.
    $ helm status opentelemetry-kube-stack --namespace opentelemetry-operator-system
    NAME: opentelemetry-kube-stack
    NAMESPACE: opentelemetry-operator-system
    STATUS: deployed
    REVISION: 1
    ##### snipped #####
  10. Verify that the operator and Collector pods are running.
    $ kubectl get pods --namespace opentelemetry-operator-system
    NAME                                                              READY   STATUS    RESTARTS   AGE
    opentelemetry-kube-stack-opentelemetry-operator-6f6dbb9b7c-nx7dk   2/2     Running   0          4m
    opentelemetry-kube-stack-cluster-stats-collector-74dddc8f6-s5msx   1/1     Running   0          3m
    opentelemetry-kube-stack-daemon-collector-8jfq2                    1/1     Running   0          3m
    opentelemetry-kube-stack-daemon-collector-zlq6p                    1/1     Running   0          3m
    opentelemetry-kube-stack-gateway-collector-7db8dd6df5-5szbn         1/1     Running   0          3m

    The daemon Collector has one pod per scheduled node, so the exact count should match the node placement in the cluster.

  11. Check the gateway Collector startup log.
    $ kubectl logs deployment/opentelemetry-kube-stack-gateway-collector \
      --namespace opentelemetry-operator-system
    2026-06-18T10:16:31.014Z	info	service@v0.138.0/service.go:199	Starting otelcol
    2026-06-18T10:16:31.275Z	info	otlpreceiver@v0.138.0/otlp.go:116	Starting GRPC server	{"endpoint": "0.0.0.0:4317"}
    2026-06-18T10:16:31.276Z	info	otlpreceiver@v0.138.0/otlp.go:173	Starting HTTP server	{"endpoint": "0.0.0.0:4318"}
    2026-06-18T10:16:31.318Z	info	service@v0.138.0/service.go:225	Everything is ready. Begin running and processing data.

    Authentication or endpoint errors usually appear in the gateway Collector because that role exports data to Elastic.

  12. Annotate an application namespace when EDOT auto-instrumentation is needed for workload traces.
    $ kubectl annotate namespace apps instrumentation.opentelemetry.io/inject-nodejs="opentelemetry-operator-system/elastic-instrumentation" --overwrite
    namespace/apps annotated

    Use nodejs, java, python, dotnet, or go as supported by the workload, then restart the application pods so the instrumentation is injected.

  13. Confirm Kubernetes telemetry in Elastic Observability. Open Kibana, go to Dashboards, and search for [OTEL][Metrics Kubernetes] Cluster Overview.

    The dashboard should show the cluster, nodes, namespaces, pods, and recent metrics from the deployed Collectors.